---
-Language: Cpp
-BasedOnStyle: WebKit
+Language: Cpp
+BasedOnStyle: WebKit
AccessModifierOffset: -2
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
-IndentWidth: 2
+IndentWidth: 2
ObjCBlockIndentWidth: 2
AlignAfterOpenBracket: Align
-SortIncludes: false
+SortIncludes: false
SpaceBeforeCpp11BracedList: false
Cpp11BracedListStyle: true
---
-Checks: 'clang-diagnostic-*,clang-analyzer-*,bugprone-*,concurrency-*,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-performance-avoid-endl'
+FormatStyle: none
+HeaderFileExtensions:
+ - h
+ - hh
+ - hpp
+ImplementationFileExtensions:
+ - c
+ - cc
+ - cpp
WarningsAsErrors: ''
HeaderFilterRegex: ''
-AnalyzeTemporaryDtors: false
-FormatStyle: none
-User: fred
+Checks: |
+ 'clang-diagnostic-*,clang-analyzer-*,bugprone-*,concurrency-*,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-performance-avoid-endl'
+# yamllint disable rule:line-length
CheckOptions:
- - key: bugprone-string-constructor.LargeLengthThreshold
- value: '8388608'
- - key: modernize-replace-auto-ptr.IncludeStyle
- value: llvm
- - key: bugprone-reserved-identifier.Invert
- value: 'false'
- - key: bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
- value: 'true'
- - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
- value: 'false'
- - key: bugprone-exception-escape.FunctionsThatShouldNotThrow
- value: ''
- - key: cert-dcl16-c.NewSuffixes
- value: 'L;LL;LU;LLU'
- - key: bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
- value: 'true'
- - key: modernize-loop-convert.MaxCopySize
- value: '16'
- - key: bugprone-narrowing-conversions.PedanticMode
- value: 'false'
- - key: bugprone-unused-return-value.CheckedFunctions
- value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
- - key: bugprone-signed-char-misuse.CharTypdefsToIgnore
- value: ''
- - key: bugprone-argument-comment.CommentStringLiterals
- value: '0'
- - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
- value: 'true'
- - key: bugprone-easily-swappable-parameters.MinimumLength
- value: '2'
- - key: bugprone-sizeof-expression.WarnOnSizeOfConstant
- value: 'true'
- - key: bugprone-argument-comment.CommentBoolLiterals
- value: '0'
- - key: bugprone-argument-comment.CommentUserDefinedLiterals
- value: '0'
- - key: cert-str34-c.DiagnoseSignedUnsignedCharComparisons
- value: 'false'
- - key: bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
- value: 'false'
- - key: concurrency-mt-unsafe.FunctionSet
- value: any
- - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
- value: 'false'
- - key: google-readability-braces-around-statements.ShortStatementLines
- value: '1'
- - key: bugprone-reserved-identifier.AllowedIdentifiers
- value: ''
- - key: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
- value: 'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;FowardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
- - key: bugprone-easily-swappable-parameters.QualifiersMix
- value: 'false'
- - key: bugprone-signal-handler.AsyncSafeFunctionSet
- value: POSIX
- - key: bugprone-easily-swappable-parameters.ModelImplicitConversions
- value: 'true'
- - key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
- value: 'true'
- - key: bugprone-argument-comment.CommentNullPtrs
- value: '0'
- - key: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
- value: 'true'
- - key: bugprone-argument-comment.StrictMode
- value: '0'
- - key: bugprone-misplaced-widening-cast.CheckImplicitCasts
- value: 'false'
- - key: bugprone-suspicious-missing-comma.RatioThreshold
- value: '0.200000'
- - key: modernize-loop-convert.MinConfidence
- value: reasonable
- - key: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
- value: '1'
- - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
- value: 'true'
- - key: google-readability-namespace-comments.ShortNamespaceLines
- value: '10'
- - key: google-readability-namespace-comments.SpacesBeforeComments
- value: '2'
- - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
- value: 'true'
- - key: bugprone-argument-comment.IgnoreSingleArgument
- value: '0'
- - key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
- value: ''
- - key: bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
- value: 'true'
- - key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
- value: 'false'
- - key: bugprone-assert-side-effect.CheckFunctionCalls
- value: 'false'
- - key: bugprone-easily-swappable-parameters.IgnoredParameterNames
- value: '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
- - key: bugprone-narrowing-conversions.IgnoreConversionFromTypes
- value: ''
- - key: bugprone-string-constructor.StringNames
- value: '::std::basic_string;::std::basic_string_view'
- - key: bugprone-assert-side-effect.AssertMacros
- value: assert,NSAssert,NSCAssert
- - key: bugprone-exception-escape.IgnoredExceptions
- value: ''
- - key: bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
- value: 'true'
- - key: llvm-qualified-auto.AddConstToQualified
- value: 'false'
- - key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
- value: 'true'
- - key: modernize-loop-convert.NamingStyle
- value: CamelCase
- - key: bugprone-suspicious-include.ImplementationFileExtensions
- value: 'c;cc;cpp;cxx'
- - key: bugprone-suspicious-missing-comma.SizeThreshold
- value: '5'
- - key: bugprone-suspicious-include.HeaderFileExtensions
- value: ';h;hh;hpp;hxx'
- - key: google-readability-function-size.StatementThreshold
- value: '800'
- - key: llvm-else-after-return.WarnOnConditionVariables
- value: 'false'
- - key: bugprone-argument-comment.CommentCharacterLiterals
- value: '0'
- - key: bugprone-argument-comment.CommentIntegerLiterals
- value: '0'
- - key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
- value: 'true'
- - key: modernize-pass-by-value.IncludeStyle
- value: llvm
- - key: bugprone-reserved-identifier.AggressiveDependentMemberLookup
- value: 'false'
- - key: bugprone-sizeof-expression.WarnOnSizeOfThis
- value: 'true'
- - key: bugprone-string-constructor.WarnOnLargeLength
- value: 'true'
- - key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
- value: '16'
- - key: bugprone-argument-comment.CommentFloatLiterals
- value: '0'
- - key: modernize-use-nullptr.NullMacros
- value: 'NULL'
- - key: bugprone-dangling-handle.HandleClasses
- value: 'std::basic_string_view;std::experimental::basic_string_view'
- - key: bugprone-dynamic-static-initializers.HeaderFileExtensions
- value: ';h;hh;hpp;hxx'
- - key: bugprone-suspicious-enum-usage.StrictMode
- value: 'false'
- - key: bugprone-implicit-widening-of-multiplication-result.IncludeStyle
- value: llvm
- - key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
- value: '5'
- - key: bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
- value: 'true'
- - key: llvm-else-after-return.WarnOnUnfixable
- value: 'false'
- - key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
- value: 'true'
+ - key: bugprone-string-constructor.LargeLengthThreshold
+ value: '8388608'
+ - key: modernize-replace-auto-ptr.IncludeStyle
+ value: llvm
+ - key: bugprone-reserved-identifier.Invert
+ value: 'false'
+ - key: bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
+ value: 'true'
+ - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
+ value: 'false'
+ - key: bugprone-exception-escape.FunctionsThatShouldNotThrow
+ value: ''
+ - key: cert-dcl16-c.NewSuffixes
+ value: 'L;LL;LU;LLU'
+ - key: bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
+ value: 'true'
+ - key: modernize-loop-convert.MaxCopySize
+ value: '16'
+ - key: bugprone-narrowing-conversions.PedanticMode
+ value: 'false'
+ - key: bugprone-unused-return-value.CheckedFunctions
+ value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
+ - key: bugprone-signed-char-misuse.CharTypdefsToIgnore
+ value: ''
+ - key: bugprone-argument-comment.CommentStringLiterals
+ value: '0'
+ - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
+ value: 'true'
+ - key: bugprone-easily-swappable-parameters.MinimumLength
+ value: '2'
+ - key: bugprone-sizeof-expression.WarnOnSizeOfConstant
+ value: 'true'
+ - key: bugprone-argument-comment.CommentBoolLiterals
+ value: '0'
+ - key: bugprone-argument-comment.CommentUserDefinedLiterals
+ value: '0'
+ - key: cert-str34-c.DiagnoseSignedUnsignedCharComparisons
+ value: 'false'
+ - key: bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
+ value: 'false'
+ - key: concurrency-mt-unsafe.FunctionSet
+ value: any
+ - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
+ value: 'false'
+ - key: google-readability-braces-around-statements.ShortStatementLines
+ value: '1'
+ - key: bugprone-reserved-identifier.AllowedIdentifiers
+ value: ''
+ - key: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
+ value: 'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;FowardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
+ - key: bugprone-easily-swappable-parameters.QualifiersMix
+ value: 'false'
+ - key: bugprone-signal-handler.AsyncSafeFunctionSet
+ value: POSIX
+ - key: bugprone-easily-swappable-parameters.ModelImplicitConversions
+ value: 'true'
+ - key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
+ value: 'true'
+ - key: bugprone-argument-comment.CommentNullPtrs
+ value: '0'
+ - key: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
+ value: 'true'
+ - key: bugprone-argument-comment.StrictMode
+ value: '0'
+ - key: bugprone-misplaced-widening-cast.CheckImplicitCasts
+ value: 'false'
+ - key: bugprone-suspicious-missing-comma.RatioThreshold
+ value: '0.200000'
+ - key: modernize-loop-convert.MinConfidence
+ value: reasonable
+ - key: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
+ value: '1'
+ - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
+ value: 'true'
+ - key: google-readability-namespace-comments.ShortNamespaceLines
+ value: '10'
+ - key: google-readability-namespace-comments.SpacesBeforeComments
+ value: '2'
+ - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
+ value: 'true'
+ - key: bugprone-argument-comment.IgnoreSingleArgument
+ value: '0'
+ - key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
+ value: ''
+ - key: bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
+ value: 'true'
+ - key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
+ value: 'false'
+ - key: bugprone-assert-side-effect.CheckFunctionCalls
+ value: 'false'
+ - key: bugprone-easily-swappable-parameters.IgnoredParameterNames
+ value: '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
+ - key: bugprone-narrowing-conversions.IgnoreConversionFromTypes
+ value: ''
+ - key: bugprone-string-constructor.StringNames
+ value: '::std::basic_string;::std::basic_string_view'
+ - key: bugprone-assert-side-effect.AssertMacros
+ value: assert,NSAssert,NSCAssert
+ - key: bugprone-exception-escape.IgnoredExceptions
+ value: ''
+ - key: bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
+ value: 'true'
+ - key: llvm-qualified-auto.AddConstToQualified
+ value: 'false'
+ - key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
+ value: 'true'
+ - key: modernize-loop-convert.NamingStyle
+ value: CamelCase
+ - key: bugprone-suspicious-include.ImplementationFileExtensions
+ value: 'c;cc;cpp;cxx'
+ - key: bugprone-suspicious-missing-comma.SizeThreshold
+ value: '5'
+ - key: bugprone-suspicious-include.HeaderFileExtensions
+ value: ';h;hh;hpp;hxx'
+ - key: google-readability-function-size.StatementThreshold
+ value: '800'
+ - key: llvm-else-after-return.WarnOnConditionVariables
+ value: 'false'
+ - key: bugprone-argument-comment.CommentCharacterLiterals
+ value: '0'
+ - key: bugprone-argument-comment.CommentIntegerLiterals
+ value: '0'
+ - key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
+ value: 'true'
+ - key: modernize-pass-by-value.IncludeStyle
+ value: llvm
+ - key: bugprone-reserved-identifier.AggressiveDependentMemberLookup
+ value: 'false'
+ - key: bugprone-sizeof-expression.WarnOnSizeOfThis
+ value: 'true'
+ - key: bugprone-string-constructor.WarnOnLargeLength
+ value: 'true'
+ - key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
+ value: '16'
+ - key: bugprone-argument-comment.CommentFloatLiterals
+ value: '0'
+ - key: modernize-use-nullptr.NullMacros
+ value: 'NULL'
+ - key: bugprone-dangling-handle.HandleClasses
+ value: 'std::basic_string_view;std::experimental::basic_string_view'
+ - key: bugprone-dynamic-static-initializers.HeaderFileExtensions
+ value: ';h;hh;hpp;hxx'
+ - key: bugprone-suspicious-enum-usage.StrictMode
+ value: 'false'
+ - key: bugprone-implicit-widening-of-multiplication-result.IncludeStyle
+ value: llvm
+ - key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
+ value: '5'
+ - key: bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
+ value: 'true'
+ - key: llvm-else-after-return.WarnOnUnfixable
+ value: 'false'
+ - key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
+ value: 'true'
+# yamllint enable
...
---
-Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,bugprone-*,concurrency-*,modernize-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-avoid-do-while,-cppcoreguidelines-avoid-const-or-ref-data-members,-performance-avoid-endl'
+FormatStyle: none
+HeaderFileExtensions:
+ - h
+ - hh
+ - hpp
+ImplementationFileExtensions:
+ - c
+ - cc
+ - cpp
WarningsAsErrors: ''
HeaderFilterRegex: ''
-AnalyzeTemporaryDtors: false
-FormatStyle: none
-User: fred
+Checks: |
+ 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,bugprone-*,concurrency-*,modernize-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-avoid-do-while,-cppcoreguidelines-avoid-const-or-ref-data-members,-performance-avoid-endl'
+# yamllint disable rule:line-length
CheckOptions:
- - key: readability-suspicious-call-argument.PrefixSimilarAbove
- value: '30'
- - key: cppcoreguidelines-no-malloc.Reallocations
- value: '::realloc'
- - key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
- value: '::free;::realloc;::freopen;::fclose'
- - key: bugprone-reserved-identifier.Invert
- value: 'false'
- - key: bugprone-narrowing-conversions.PedanticMode
- value: 'false'
- - key: bugprone-unused-return-value.CheckedFunctions
- value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
- - key: modernize-use-auto.MinTypeNameLength
- value: '5'
- - key: cppcoreguidelines-macro-usage.CheckCapsOnly
- value: 'false'
- - key: readability-inconsistent-declaration-parameter-name.Strict
- value: 'false'
- - key: readability-suspicious-call-argument.DiceDissimilarBelow
- value: '60'
- - key: readability-suspicious-call-argument.Equality
- value: 'true'
- - key: bugprone-easily-swappable-parameters.QualifiersMix
- value: 'false'
- - key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
- value: 'true'
- - key: bugprone-argument-comment.CommentNullPtrs
- value: '0'
- - key: cppcoreguidelines-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
- value: 'true'
- - key: cppcoreguidelines-init-variables.IncludeStyle
- value: llvm
- - key: modernize-use-nodiscard.ReplacementString
- value: '[[nodiscard]]'
- - key: modernize-loop-convert.MakeReverseRangeHeader
- value: ''
- - key: readability-suspicious-call-argument.SuffixSimilarAbove
- value: '30'
- - key: cppcoreguidelines-narrowing-conversions.WarnOnIntegerNarrowingConversion
- value: 'true'
- - key: bugprone-easily-swappable-parameters.IgnoredParameterNames
- value: '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
- - key: modernize-loop-convert.UseCxx20ReverseRanges
- value: 'true'
- - key: cppcoreguidelines-prefer-member-initializer.UseAssignment
- value: 'false'
- - key: performance-type-promotion-in-math-fn.IncludeStyle
- value: llvm
- - key: readability-function-cognitive-complexity.DescribeBasicIncrements
- value: 'true'
- - key: bugprone-suspicious-include.ImplementationFileExtensions
- value: 'c;cc;cpp;cxx'
- - key: modernize-loop-convert.MakeReverseRangeFunction
- value: ''
- - key: readability-inconsistent-declaration-parameter-name.IgnoreMacros
- value: 'true'
- - key: bugprone-suspicious-missing-comma.SizeThreshold
- value: '5'
- - key: readability-identifier-naming.IgnoreFailedSplit
- value: 'false'
- - key: readability-qualified-auto.AddConstToQualified
- value: 'true'
- - key: bugprone-sizeof-expression.WarnOnSizeOfThis
- value: 'true'
- - key: bugprone-string-constructor.WarnOnLargeLength
- value: 'true'
- - key: cppcoreguidelines-explicit-virtual-functions.OverrideSpelling
- value: override
- - key: readability-uppercase-literal-suffix.IgnoreMacros
- value: 'true'
- - key: modernize-make-shared.IgnoreMacros
- value: 'true'
- - key: bugprone-dynamic-static-initializers.HeaderFileExtensions
- value: ';h;hh;hpp;hxx'
- - key: bugprone-suspicious-enum-usage.StrictMode
- value: 'false'
- - key: performance-unnecessary-copy-initialization.AllowedTypes
- value: ''
- - key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
- value: '5'
- - key: modernize-use-transparent-functors.SafeMode
- value: 'false'
- - key: readability-suspicious-call-argument.Levenshtein
- value: 'true'
- - key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
- value: 'true'
- - key: bugprone-string-constructor.LargeLengthThreshold
- value: '8388608'
- - key: readability-simplify-boolean-expr.ChainedConditionalAssignment
- value: 'false'
- - key: cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
- value: 'false'
- - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
- value: 'false'
- - key: bugprone-exception-escape.FunctionsThatShouldNotThrow
- value: ''
- - key: performance-inefficient-vector-operation.EnableProto
- value: 'false'
- - key: modernize-make-shared.MakeSmartPtrFunction
- value: 'std::make_shared'
- - key: modernize-loop-convert.MaxCopySize
- value: '16'
- - key: readability-suspicious-call-argument.PrefixDissimilarBelow
- value: '25'
- - key: readability-function-size.LineThreshold
- value: '4294967295'
- - key: bugprone-easily-swappable-parameters.MinimumLength
- value: '4'
- - key: portability-simd-intrinsics.Suggest
- value: 'false'
- - key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
- value: ''
- - key: modernize-use-override.IgnoreDestructors
- value: 'false'
- - key: modernize-make-shared.MakeSmartPtrFunctionHeader
- value: '<memory>'
- - key: bugprone-sizeof-expression.WarnOnSizeOfConstant
- value: 'true'
- - key: readability-redundant-string-init.StringNames
- value: '::std::basic_string_view;::std::basic_string'
- - key: modernize-make-unique.IgnoreDefaultInitialization
- value: 'true'
- - key: modernize-use-emplace.ContainersWithPushBack
- value: '::std::vector;::std::list;::std::deque'
- - key: readability-magic-numbers.IgnoreBitFieldsWidths
- value: 'true'
- - key: modernize-make-unique.IncludeStyle
- value: llvm
- - key: modernize-use-override.OverrideSpelling
- value: override
- - key: readability-suspicious-call-argument.LevenshteinDissimilarBelow
- value: '50'
- - key: bugprone-argument-comment.CommentStringLiterals
- value: '0'
- - key: concurrency-mt-unsafe.FunctionSet
- value: any
- - key: google-readability-braces-around-statements.ShortStatementLines
- value: '1'
- - key: bugprone-reserved-identifier.AllowedIdentifiers
- value: ''
- - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
- value: 'false'
- - key: readability-else-after-return.WarnOnUnfixable
- value: 'true'
- - key: cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues
- value: '1.0;100.0;'
- - key: modernize-use-emplace.IgnoreImplicitConstructors
- value: 'false'
- - key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros
- value: 'true'
- - key: readability-suspicious-call-argument.Substring
- value: 'true'
- - key: modernize-use-equals-delete.IgnoreMacros
- value: 'true'
- - key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
- value: llvm
- - key: readability-magic-numbers.IgnoreAllFloatingPointValues
- value: 'false'
- - key: readability-suspicious-call-argument.Abbreviations
- value: 'arr=array;cnt=count;idx=index;src=source;stmt=statement;cpy=copy;dest=destination;dist=distancedst=distance;ptr=pointer;wdth=width;str=string;ln=line;srv=server;attr=attribute;ref=reference;buf=buffer;col=column;nr=number;vec=vector;len=length;elem=element;val=value;i=index;var=variable;hght=height;cl=client;num=number;pos=position;lst=list;addr=address'
- - key: bugprone-misplaced-widening-cast.CheckImplicitCasts
- value: 'false'
- - key: readability-uppercase-literal-suffix.NewSuffixes
- value: ''
- - key: modernize-loop-convert.MinConfidence
- value: reasonable
- - key: performance-unnecessary-value-param.AllowedTypes
- value: ''
- - key: readability-uniqueptr-delete-release.PreferResetCall
- value: 'false'
- - key: cppcoreguidelines-avoid-magic-numbers.IgnorePowersOf2IntegerValues
- value: 'false'
- - key: google-readability-namespace-comments.SpacesBeforeComments
- value: '2'
- - key: cppcoreguidelines-avoid-magic-numbers.IgnoreBitFieldsWidths
- value: 'true'
- - key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues
- value: '1;2;3;4;'
- - key: cppcoreguidelines-no-malloc.Allocations
- value: '::malloc;::calloc'
- - key: bugprone-narrowing-conversions.IgnoreConversionFromTypes
- value: ''
- - key: readability-function-size.BranchThreshold
- value: '4294967295'
- - key: bugprone-suspicious-missing-comma.RatioThreshold
- value: '0.200000'
- - key: readability-implicit-bool-conversion.AllowIntegerConditions
- value: 'false'
- - key: readability-function-size.StatementThreshold
- value: '800'
- - key: readability-identifier-naming.IgnoreMainLikeFunctions
- value: 'false'
- - key: cppcoreguidelines-init-variables.MathHeader
- value: '<math.h>'
- - key: google-readability-function-size.StatementThreshold
- value: '800'
- - key: bugprone-reserved-identifier.AggressiveDependentMemberLookup
- value: 'false'
- - key: readability-suspicious-call-argument.DiceSimilarAbove
- value: '70'
- - key: modernize-use-equals-default.IgnoreMacros
- value: 'true'
- - key: readability-suspicious-call-argument.Abbreviation
- value: 'true'
- - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
- value: 'false'
- - key: modernize-use-emplace.SmartPointers
- value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
- - key: cppcoreguidelines-no-malloc.Deallocations
- value: '::free'
- - key: bugprone-dangling-handle.HandleClasses
- value: 'std::basic_string_view;std::experimental::basic_string_view'
- - key: readability-magic-numbers.IgnorePowersOf2IntegerValues
- value: 'false'
- - key: readability-suspicious-call-argument.JaroWinklerSimilarAbove
- value: '85'
- - key: readability-simplify-subscript-expr.Types
- value: '::std::basic_string;::std::basic_string_view;::std::vector;::std::array'
- - key: performance-unnecessary-copy-initialization.ExcludedContainerTypes
- value: ''
- - key: modernize-replace-auto-ptr.IncludeStyle
- value: llvm
- - key: performance-move-const-arg.CheckTriviallyCopyableMove
- value: 'true'
- - key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold
- value: '3'
- - key: readability-function-size.VariableThreshold
- value: '4294967295'
- - key: cert-dcl16-c.NewSuffixes
- value: 'L;LL;LU;LLU'
- - key: bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
- value: 'true'
- - key: readability-identifier-naming.GetConfigPerFile
- value: 'true'
- - key: modernize-use-default-member-init.UseAssignment
- value: 'false'
- - key: readability-function-size.NestingThreshold
- value: '4294967295'
- - key: modernize-use-override.AllowOverrideAndFinal
- value: 'false'
- - key: cppcoreguidelines-narrowing-conversions.IgnoreConversionFromTypes
- value: ''
- - key: readability-function-size.ParameterThreshold
- value: '4294967295'
- - key: modernize-pass-by-value.ValuesOnly
- value: 'false'
- - key: readability-function-cognitive-complexity.IgnoreMacros
- value: 'true'
- - key: modernize-loop-convert.IncludeStyle
- value: llvm
- - key: cert-str34-c.DiagnoseSignedUnsignedCharComparisons
- value: 'false'
- - key: bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
- value: 'false'
- - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
- value: 'false'
- - key: cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal
- value: 'false'
- - key: readability-redundant-smartptr-get.IgnoreMacros
- value: 'true'
- - key: readability-identifier-naming.AggressiveDependentMemberLookup
- value: 'false'
- - key: modernize-use-emplace.TupleTypes
- value: '::std::pair;::std::tuple'
- - key: modernize-use-emplace.TupleMakeFunctions
- value: '::std::make_pair;::std::make_tuple'
- - key: cppcoreguidelines-owning-memory.LegacyResourceProducers
- value: '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile'
- - key: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
- value: 'true'
- - key: bugprone-argument-comment.StrictMode
- value: '0'
- - key: modernize-replace-random-shuffle.IncludeStyle
- value: llvm
- - key: modernize-use-bool-literals.IgnoreMacros
- value: 'true'
- - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
- value: 'true'
- - key: google-readability-namespace-comments.ShortNamespaceLines
- value: '10'
- - key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
- value: ''
- - key: modernize-avoid-bind.PermissiveParameterList
- value: 'false'
- - key: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
- value: '1'
- - key: readability-suspicious-call-argument.Suffix
- value: 'true'
- - key: readability-suspicious-call-argument.JaroWinklerDissimilarBelow
- value: '75'
- - key: modernize-use-noexcept.ReplacementString
- value: ''
- - key: modernize-use-override.FinalSpelling
- value: final
- - key: modernize-use-using.IgnoreMacros
- value: 'true'
- - key: cppcoreguidelines-explicit-virtual-functions.FinalSpelling
- value: final
- - key: readability-suspicious-call-argument.MinimumIdentifierNameLength
- value: '3'
- - key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
- value: 'true'
- - key: modernize-loop-convert.NamingStyle
- value: CamelCase
- - key: cppcoreguidelines-pro-type-member-init.UseAssignment
- value: 'false'
- - key: bugprone-suspicious-include.HeaderFileExtensions
- value: ';h;hh;hpp;hxx'
- - key: performance-no-automatic-move.AllowedTypes
- value: ''
- - key: readability-suspicious-call-argument.SubstringDissimilarBelow
- value: '40'
- - key: bugprone-argument-comment.CommentIntegerLiterals
- value: '0'
- - key: performance-for-range-copy.WarnOnAllAutoCopies
- value: 'false'
- - key: modernize-pass-by-value.IncludeStyle
- value: llvm
- - key: bugprone-argument-comment.CommentFloatLiterals
- value: '0'
- - key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
- value: '16'
- - key: readability-simplify-boolean-expr.ChainedConditionalReturn
- value: 'false'
- - key: readability-else-after-return.WarnOnConditionVariables
- value: 'true'
- - key: modernize-use-nullptr.NullMacros
- value: 'NULL'
- - key: readability-suspicious-call-argument.SuffixDissimilarBelow
- value: '25'
- - key: bugprone-argument-comment.CommentCharacterLiterals
- value: '0'
- - key: cppcoreguidelines-macro-usage.AllowedRegexp
- value: '^DEBUG_*'
- - key: readability-suspicious-call-argument.LevenshteinSimilarAbove
- value: '66'
- - key: cppcoreguidelines-narrowing-conversions.PedanticMode
- value: 'false'
- - key: modernize-make-shared.IgnoreDefaultInitialization
- value: 'true'
- - key: readability-suspicious-call-argument.JaroWinkler
- value: 'true'
- - key: bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
- value: 'true'
- - key: modernize-make-shared.IncludeStyle
- value: llvm
- - key: readability-suspicious-call-argument.Prefix
- value: 'true'
- - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
- value: 'false'
- - key: bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
- value: 'true'
- - key: bugprone-signed-char-misuse.CharTypdefsToIgnore
- value: ''
- - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
- value: 'true'
- - key: modernize-make-unique.IgnoreMacros
- value: 'true'
- - key: performance-for-range-copy.AllowedTypes
- value: ''
- - key: bugprone-argument-comment.CommentBoolLiterals
- value: '0'
- - key: readability-braces-around-statements.ShortStatementLines
- value: '0'
- - key: bugprone-argument-comment.CommentUserDefinedLiterals
- value: '0'
- - key: readability-magic-numbers.IgnoredFloatingPointValues
- value: '1.0;100.0;'
- - key: readability-implicit-bool-conversion.AllowPointerConditions
- value: 'false'
- - key: performance-inefficient-string-concatenation.StrictMode
- value: 'false'
- - key: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
- value: 'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;FowardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
- - key: modernize-make-unique.MakeSmartPtrFunction
- value: 'std::make_unique'
- - key: readability-redundant-declaration.IgnoreMacros
- value: 'true'
- - key: portability-restrict-system-includes.Includes
- value: '*'
- - key: modernize-make-unique.MakeSmartPtrFunctionHeader
- value: '<memory>'
- - key: bugprone-signal-handler.AsyncSafeFunctionSet
- value: POSIX
- - key: bugprone-easily-swappable-parameters.ModelImplicitConversions
- value: 'true'
- - key: readability-suspicious-call-argument.SubstringSimilarAbove
- value: '50'
- - key: cppcoreguidelines-narrowing-conversions.WarnWithinTemplateInstantiation
- value: 'false'
- - key: cppcoreguidelines-narrowing-conversions.WarnOnEquivalentBitWidth
- value: 'true'
- - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnorePublicMemberVariables
- value: 'false'
- - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted
- value: 'false'
- - key: modernize-use-noexcept.UseNoexceptFalse
- value: 'true'
- - key: readability-function-cognitive-complexity.Threshold
- value: '75'
- - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
- value: 'true'
- - key: bugprone-argument-comment.IgnoreSingleArgument
- value: '0'
- - key: bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
- value: 'true'
- - key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
- value: 'false'
- - key: performance-faster-string-find.StringLikeClasses
- value: '::std::basic_string;::std::basic_string_view'
- - key: bugprone-assert-side-effect.CheckFunctionCalls
- value: 'false'
- - key: bugprone-string-constructor.StringNames
- value: '::std::basic_string;::std::basic_string_view'
- - key: bugprone-assert-side-effect.AssertMacros
- value: assert,NSAssert,NSCAssert
- - key: bugprone-exception-escape.IgnoredExceptions
- value: ''
- - key: bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
- value: 'true'
- - key: modernize-use-default-member-init.IgnoreMacros
- value: 'true'
- - key: llvm-qualified-auto.AddConstToQualified
- value: 'false'
- - key: llvm-else-after-return.WarnOnConditionVariables
- value: 'false'
- - key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
- value: 'true'
- - key: modernize-raw-string-literal.DelimiterStem
- value: lit
- - key: readability-suspicious-call-argument.Dice
- value: 'true'
- - key: modernize-raw-string-literal.ReplaceShorterLiterals
- value: 'false'
- - key: readability-magic-numbers.IgnoredIntegerValues
- value: '1;2;3;4;'
- - key: performance-inefficient-vector-operation.VectorLikeClasses
- value: '::std::vector'
- - key: modernize-use-auto.RemoveStars
- value: 'false'
- - key: bugprone-implicit-widening-of-multiplication-result.IncludeStyle
- value: llvm
- - key: portability-simd-intrinsics.Std
- value: ''
- - key: performance-unnecessary-value-param.IncludeStyle
- value: llvm
- - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors
- value: 'false'
- - key: modernize-replace-disallow-copy-and-assign-macro.MacroName
- value: DISALLOW_COPY_AND_ASSIGN
- - key: llvm-else-after-return.WarnOnUnfixable
- value: 'false'
+ - key: readability-suspicious-call-argument.PrefixSimilarAbove
+ value: '30'
+ - key: cppcoreguidelines-no-malloc.Reallocations
+ value: '::realloc'
+ - key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
+ value: '::free;::realloc;::freopen;::fclose'
+ - key: bugprone-reserved-identifier.Invert
+ value: 'false'
+ - key: bugprone-narrowing-conversions.PedanticMode
+ value: 'false'
+ - key: bugprone-unused-return-value.CheckedFunctions
+ value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
+ - key: modernize-use-auto.MinTypeNameLength
+ value: '5'
+ - key: cppcoreguidelines-macro-usage.CheckCapsOnly
+ value: 'false'
+ - key: readability-inconsistent-declaration-parameter-name.Strict
+ value: 'false'
+ - key: readability-suspicious-call-argument.DiceDissimilarBelow
+ value: '60'
+ - key: readability-suspicious-call-argument.Equality
+ value: 'true'
+ - key: bugprone-easily-swappable-parameters.QualifiersMix
+ value: 'false'
+ - key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
+ value: 'true'
+ - key: bugprone-argument-comment.CommentNullPtrs
+ value: '0'
+ - key: cppcoreguidelines-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
+ value: 'true'
+ - key: cppcoreguidelines-init-variables.IncludeStyle
+ value: llvm
+ - key: modernize-use-nodiscard.ReplacementString
+ value: '[[nodiscard]]'
+ - key: modernize-loop-convert.MakeReverseRangeHeader
+ value: ''
+ - key: readability-suspicious-call-argument.SuffixSimilarAbove
+ value: '30'
+ - key: cppcoreguidelines-narrowing-conversions.WarnOnIntegerNarrowingConversion
+ value: 'true'
+ - key: bugprone-easily-swappable-parameters.IgnoredParameterNames
+ value: '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
+ - key: modernize-loop-convert.UseCxx20ReverseRanges
+ value: 'true'
+ - key: cppcoreguidelines-prefer-member-initializer.UseAssignment
+ value: 'false'
+ - key: performance-type-promotion-in-math-fn.IncludeStyle
+ value: llvm
+ - key: readability-function-cognitive-complexity.DescribeBasicIncrements
+ value: 'true'
+ - key: bugprone-suspicious-include.ImplementationFileExtensions
+ value: 'c;cc;cpp;cxx'
+ - key: modernize-loop-convert.MakeReverseRangeFunction
+ value: ''
+ - key: readability-inconsistent-declaration-parameter-name.IgnoreMacros
+ value: 'true'
+ - key: bugprone-suspicious-missing-comma.SizeThreshold
+ value: '5'
+ - key: readability-identifier-naming.IgnoreFailedSplit
+ value: 'false'
+ - key: readability-qualified-auto.AddConstToQualified
+ value: 'true'
+ - key: bugprone-sizeof-expression.WarnOnSizeOfThis
+ value: 'true'
+ - key: bugprone-string-constructor.WarnOnLargeLength
+ value: 'true'
+ - key: cppcoreguidelines-explicit-virtual-functions.OverrideSpelling
+ value: override
+ - key: readability-uppercase-literal-suffix.IgnoreMacros
+ value: 'true'
+ - key: modernize-make-shared.IgnoreMacros
+ value: 'true'
+ - key: bugprone-dynamic-static-initializers.HeaderFileExtensions
+ value: ';h;hh;hpp;hxx'
+ - key: bugprone-suspicious-enum-usage.StrictMode
+ value: 'false'
+ - key: performance-unnecessary-copy-initialization.AllowedTypes
+ value: ''
+ - key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
+ value: '5'
+ - key: modernize-use-transparent-functors.SafeMode
+ value: 'false'
+ - key: readability-suspicious-call-argument.Levenshtein
+ value: 'true'
+ - key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
+ value: 'true'
+ - key: bugprone-string-constructor.LargeLengthThreshold
+ value: '8388608'
+ - key: readability-simplify-boolean-expr.ChainedConditionalAssignment
+ value: 'false'
+ - key: cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
+ value: 'false'
+ - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
+ value: 'false'
+ - key: bugprone-exception-escape.FunctionsThatShouldNotThrow
+ value: ''
+ - key: performance-inefficient-vector-operation.EnableProto
+ value: 'false'
+ - key: modernize-make-shared.MakeSmartPtrFunction
+ value: 'std::make_shared'
+ - key: modernize-loop-convert.MaxCopySize
+ value: '16'
+ - key: readability-suspicious-call-argument.PrefixDissimilarBelow
+ value: '25'
+ - key: readability-function-size.LineThreshold
+ value: '4294967295'
+ - key: bugprone-easily-swappable-parameters.MinimumLength
+ value: '4'
+ - key: portability-simd-intrinsics.Suggest
+ value: 'false'
+ - key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
+ value: ''
+ - key: modernize-use-override.IgnoreDestructors
+ value: 'false'
+ - key: modernize-make-shared.MakeSmartPtrFunctionHeader
+ value: '<memory>'
+ - key: bugprone-sizeof-expression.WarnOnSizeOfConstant
+ value: 'true'
+ - key: readability-redundant-string-init.StringNames
+ value: '::std::basic_string_view;::std::basic_string'
+ - key: modernize-make-unique.IgnoreDefaultInitialization
+ value: 'true'
+ - key: modernize-use-emplace.ContainersWithPushBack
+ value: '::std::vector;::std::list;::std::deque'
+ - key: readability-magic-numbers.IgnoreBitFieldsWidths
+ value: 'true'
+ - key: modernize-make-unique.IncludeStyle
+ value: llvm
+ - key: modernize-use-override.OverrideSpelling
+ value: override
+ - key: readability-suspicious-call-argument.LevenshteinDissimilarBelow
+ value: '50'
+ - key: bugprone-argument-comment.CommentStringLiterals
+ value: '0'
+ - key: concurrency-mt-unsafe.FunctionSet
+ value: any
+ - key: google-readability-braces-around-statements.ShortStatementLines
+ value: '1'
+ - key: bugprone-reserved-identifier.AllowedIdentifiers
+ value: ''
+ - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
+ value: 'false'
+ - key: readability-else-after-return.WarnOnUnfixable
+ value: 'true'
+ - key: cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues
+ value: '1.0;100.0;'
+ - key: modernize-use-emplace.IgnoreImplicitConstructors
+ value: 'false'
+ - key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros
+ value: 'true'
+ - key: readability-suspicious-call-argument.Substring
+ value: 'true'
+ - key: modernize-use-equals-delete.IgnoreMacros
+ value: 'true'
+ - key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
+ value: llvm
+ - key: readability-magic-numbers.IgnoreAllFloatingPointValues
+ value: 'false'
+ - key: readability-suspicious-call-argument.Abbreviations
+ value: 'arr=array;cnt=count;idx=index;src=source;stmt=statement;cpy=copy;dest=destination;dist=distancedst=distance;ptr=pointer;wdth=width;str=string;ln=line;srv=server;attr=attribute;ref=reference;buf=buffer;col=column;nr=number;vec=vector;len=length;elem=element;val=value;i=index;var=variable;hght=height;cl=client;num=number;pos=position;lst=list;addr=address'
+ - key: bugprone-misplaced-widening-cast.CheckImplicitCasts
+ value: 'false'
+ - key: readability-uppercase-literal-suffix.NewSuffixes
+ value: ''
+ - key: modernize-loop-convert.MinConfidence
+ value: reasonable
+ - key: performance-unnecessary-value-param.AllowedTypes
+ value: ''
+ - key: readability-uniqueptr-delete-release.PreferResetCall
+ value: 'false'
+ - key: cppcoreguidelines-avoid-magic-numbers.IgnorePowersOf2IntegerValues
+ value: 'false'
+ - key: google-readability-namespace-comments.SpacesBeforeComments
+ value: '2'
+ - key: cppcoreguidelines-avoid-magic-numbers.IgnoreBitFieldsWidths
+ value: 'true'
+ - key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues
+ value: '1;2;3;4;'
+ - key: cppcoreguidelines-no-malloc.Allocations
+ value: '::malloc;::calloc'
+ - key: bugprone-narrowing-conversions.IgnoreConversionFromTypes
+ value: ''
+ - key: readability-function-size.BranchThreshold
+ value: '4294967295'
+ - key: bugprone-suspicious-missing-comma.RatioThreshold
+ value: '0.200000'
+ - key: readability-implicit-bool-conversion.AllowIntegerConditions
+ value: 'false'
+ - key: readability-function-size.StatementThreshold
+ value: '800'
+ - key: readability-identifier-naming.IgnoreMainLikeFunctions
+ value: 'false'
+ - key: cppcoreguidelines-init-variables.MathHeader
+ value: '<math.h>'
+ - key: google-readability-function-size.StatementThreshold
+ value: '800'
+ - key: bugprone-reserved-identifier.AggressiveDependentMemberLookup
+ value: 'false'
+ - key: readability-suspicious-call-argument.DiceSimilarAbove
+ value: '70'
+ - key: modernize-use-equals-default.IgnoreMacros
+ value: 'true'
+ - key: readability-suspicious-call-argument.Abbreviation
+ value: 'true'
+ - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+ value: 'false'
+ - key: modernize-use-emplace.SmartPointers
+ value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
+ - key: cppcoreguidelines-no-malloc.Deallocations
+ value: '::free'
+ - key: bugprone-dangling-handle.HandleClasses
+ value: 'std::basic_string_view;std::experimental::basic_string_view'
+ - key: readability-magic-numbers.IgnorePowersOf2IntegerValues
+ value: 'false'
+ - key: readability-suspicious-call-argument.JaroWinklerSimilarAbove
+ value: '85'
+ - key: readability-simplify-subscript-expr.Types
+ value: '::std::basic_string;::std::basic_string_view;::std::vector;::std::array'
+ - key: performance-unnecessary-copy-initialization.ExcludedContainerTypes
+ value: ''
+ - key: modernize-replace-auto-ptr.IncludeStyle
+ value: llvm
+ - key: performance-move-const-arg.CheckTriviallyCopyableMove
+ value: 'true'
+ - key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold
+ value: '3'
+ - key: readability-function-size.VariableThreshold
+ value: '4294967295'
+ - key: cert-dcl16-c.NewSuffixes
+ value: 'L;LL;LU;LLU'
+ - key: bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
+ value: 'true'
+ - key: readability-identifier-naming.GetConfigPerFile
+ value: 'true'
+ - key: modernize-use-default-member-init.UseAssignment
+ value: 'false'
+ - key: readability-function-size.NestingThreshold
+ value: '4294967295'
+ - key: modernize-use-override.AllowOverrideAndFinal
+ value: 'false'
+ - key: cppcoreguidelines-narrowing-conversions.IgnoreConversionFromTypes
+ value: ''
+ - key: readability-function-size.ParameterThreshold
+ value: '4294967295'
+ - key: modernize-pass-by-value.ValuesOnly
+ value: 'false'
+ - key: readability-function-cognitive-complexity.IgnoreMacros
+ value: 'true'
+ - key: modernize-loop-convert.IncludeStyle
+ value: llvm
+ - key: cert-str34-c.DiagnoseSignedUnsignedCharComparisons
+ value: 'false'
+ - key: bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
+ value: 'false'
+ - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
+ value: 'false'
+ - key: cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal
+ value: 'false'
+ - key: readability-redundant-smartptr-get.IgnoreMacros
+ value: 'true'
+ - key: readability-identifier-naming.AggressiveDependentMemberLookup
+ value: 'false'
+ - key: modernize-use-emplace.TupleTypes
+ value: '::std::pair;::std::tuple'
+ - key: modernize-use-emplace.TupleMakeFunctions
+ value: '::std::make_pair;::std::make_tuple'
+ - key: cppcoreguidelines-owning-memory.LegacyResourceProducers
+ value: '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile'
+ - key: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
+ value: 'true'
+ - key: bugprone-argument-comment.StrictMode
+ value: '0'
+ - key: modernize-replace-random-shuffle.IncludeStyle
+ value: llvm
+ - key: modernize-use-bool-literals.IgnoreMacros
+ value: 'true'
+ - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
+ value: 'true'
+ - key: google-readability-namespace-comments.ShortNamespaceLines
+ value: '10'
+ - key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
+ value: ''
+ - key: modernize-avoid-bind.PermissiveParameterList
+ value: 'false'
+ - key: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
+ value: '1'
+ - key: readability-suspicious-call-argument.Suffix
+ value: 'true'
+ - key: readability-suspicious-call-argument.JaroWinklerDissimilarBelow
+ value: '75'
+ - key: modernize-use-noexcept.ReplacementString
+ value: ''
+ - key: modernize-use-override.FinalSpelling
+ value: final
+ - key: modernize-use-using.IgnoreMacros
+ value: 'true'
+ - key: cppcoreguidelines-explicit-virtual-functions.FinalSpelling
+ value: final
+ - key: readability-suspicious-call-argument.MinimumIdentifierNameLength
+ value: '3'
+ - key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
+ value: 'true'
+ - key: modernize-loop-convert.NamingStyle
+ value: CamelCase
+ - key: cppcoreguidelines-pro-type-member-init.UseAssignment
+ value: 'false'
+ - key: bugprone-suspicious-include.HeaderFileExtensions
+ value: ';h;hh;hpp;hxx'
+ - key: performance-no-automatic-move.AllowedTypes
+ value: ''
+ - key: readability-suspicious-call-argument.SubstringDissimilarBelow
+ value: '40'
+ - key: bugprone-argument-comment.CommentIntegerLiterals
+ value: '0'
+ - key: performance-for-range-copy.WarnOnAllAutoCopies
+ value: 'false'
+ - key: modernize-pass-by-value.IncludeStyle
+ value: llvm
+ - key: bugprone-argument-comment.CommentFloatLiterals
+ value: '0'
+ - key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
+ value: '16'
+ - key: readability-simplify-boolean-expr.ChainedConditionalReturn
+ value: 'false'
+ - key: readability-else-after-return.WarnOnConditionVariables
+ value: 'true'
+ - key: modernize-use-nullptr.NullMacros
+ value: 'NULL'
+ - key: readability-suspicious-call-argument.SuffixDissimilarBelow
+ value: '25'
+ - key: bugprone-argument-comment.CommentCharacterLiterals
+ value: '0'
+ - key: cppcoreguidelines-macro-usage.AllowedRegexp
+ value: '^DEBUG_*'
+ - key: readability-suspicious-call-argument.LevenshteinSimilarAbove
+ value: '66'
+ - key: cppcoreguidelines-narrowing-conversions.PedanticMode
+ value: 'false'
+ - key: modernize-make-shared.IgnoreDefaultInitialization
+ value: 'true'
+ - key: readability-suspicious-call-argument.JaroWinkler
+ value: 'true'
+ - key: bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
+ value: 'true'
+ - key: modernize-make-shared.IncludeStyle
+ value: llvm
+ - key: readability-suspicious-call-argument.Prefix
+ value: 'true'
+ - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
+ value: 'false'
+ - key: bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
+ value: 'true'
+ - key: bugprone-signed-char-misuse.CharTypdefsToIgnore
+ value: ''
+ - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
+ value: 'true'
+ - key: modernize-make-unique.IgnoreMacros
+ value: 'true'
+ - key: performance-for-range-copy.AllowedTypes
+ value: ''
+ - key: bugprone-argument-comment.CommentBoolLiterals
+ value: '0'
+ - key: readability-braces-around-statements.ShortStatementLines
+ value: '0'
+ - key: bugprone-argument-comment.CommentUserDefinedLiterals
+ value: '0'
+ - key: readability-magic-numbers.IgnoredFloatingPointValues
+ value: '1.0;100.0;'
+ - key: readability-implicit-bool-conversion.AllowPointerConditions
+ value: 'false'
+ - key: performance-inefficient-string-concatenation.StrictMode
+ value: 'false'
+ - key: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
+ value: 'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;FowardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
+ - key: modernize-make-unique.MakeSmartPtrFunction
+ value: 'std::make_unique'
+ - key: readability-redundant-declaration.IgnoreMacros
+ value: 'true'
+ - key: portability-restrict-system-includes.Includes
+ value: '*'
+ - key: modernize-make-unique.MakeSmartPtrFunctionHeader
+ value: '<memory>'
+ - key: bugprone-signal-handler.AsyncSafeFunctionSet
+ value: POSIX
+ - key: bugprone-easily-swappable-parameters.ModelImplicitConversions
+ value: 'true'
+ - key: readability-suspicious-call-argument.SubstringSimilarAbove
+ value: '50'
+ - key: cppcoreguidelines-narrowing-conversions.WarnWithinTemplateInstantiation
+ value: 'false'
+ - key: cppcoreguidelines-narrowing-conversions.WarnOnEquivalentBitWidth
+ value: 'true'
+ - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnorePublicMemberVariables
+ value: 'false'
+ - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted
+ value: 'false'
+ - key: modernize-use-noexcept.UseNoexceptFalse
+ value: 'true'
+ - key: readability-function-cognitive-complexity.Threshold
+ value: '75'
+ - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
+ value: 'true'
+ - key: bugprone-argument-comment.IgnoreSingleArgument
+ value: '0'
+ - key: bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
+ value: 'true'
+ - key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
+ value: 'false'
+ - key: performance-faster-string-find.StringLikeClasses
+ value: '::std::basic_string;::std::basic_string_view'
+ - key: bugprone-assert-side-effect.CheckFunctionCalls
+ value: 'false'
+ - key: bugprone-string-constructor.StringNames
+ value: '::std::basic_string;::std::basic_string_view'
+ - key: bugprone-assert-side-effect.AssertMacros
+ value: assert,NSAssert,NSCAssert
+ - key: bugprone-exception-escape.IgnoredExceptions
+ value: ''
+ - key: bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
+ value: 'true'
+ - key: modernize-use-default-member-init.IgnoreMacros
+ value: 'true'
+ - key: llvm-qualified-auto.AddConstToQualified
+ value: 'false'
+ - key: llvm-else-after-return.WarnOnConditionVariables
+ value: 'false'
+ - key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
+ value: 'true'
+ - key: modernize-raw-string-literal.DelimiterStem
+ value: lit
+ - key: readability-suspicious-call-argument.Dice
+ value: 'true'
+ - key: modernize-raw-string-literal.ReplaceShorterLiterals
+ value: 'false'
+ - key: readability-magic-numbers.IgnoredIntegerValues
+ value: '1;2;3;4;'
+ - key: performance-inefficient-vector-operation.VectorLikeClasses
+ value: '::std::vector'
+ - key: modernize-use-auto.RemoveStars
+ value: 'false'
+ - key: bugprone-implicit-widening-of-multiplication-result.IncludeStyle
+ value: llvm
+ - key: portability-simd-intrinsics.Std
+ value: ''
+ - key: performance-unnecessary-value-param.IncludeStyle
+ value: llvm
+ - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors
+ value: 'false'
+ - key: modernize-replace-disallow-copy-and-assign-macro.MacroName
+ value: DISALLOW_COPY_AND_ASSIGN
+ - key: llvm-else-after-return.WarnOnUnfixable
+ value: 'false'
+# yamllint enable
...
<!-- Hi! Thanks for filing an issue. It will be read with care by human beings. Can we ask you to please fill out this template and not simply demand new features or send in complaints? Thanks! -->
<!-- Also please search the existing issues (both open and closed) to see if your report might be duplicate -->
-- [ ] This is not a support question, I have read [about opensource](https://www.powerdns.com/opensource.html) and will send support questions to the IRC channel, [Github Discussions](https://github.com/PowerDNS/pdns/discussions/) or the mailing list.
+- [ ] This is not a support question, I have read [about opensource](https://www.powerdns.com/opensource.html) and will send support questions to the IRC channel, [GitHub Discussions](https://github.com/PowerDNS/pdns/discussions/) or the mailing list.
- [ ] I have read and understood the ['out in the open' support policy](https://blog.powerdns.com/2016/01/18/open-source-support-out-in-the-open/)
<!-- Tell us what is issue is about -->
Alenichev
alexa
algoroll
+alloca
allocs
Altpeter
Anderton
Cairney
calculatesoaserial
calidns
+capf
Cauquil
ccache
ccc
+ccls
ccounts
cdb
CDBKV
Christof
chrooted
chrooting
+clangd
clientanswers
Cloos
closesocket
comboaddress
commandline
committransaction
+compiledb
conaxis
configfile
+configmap
configname
configsetting
confs
cornercases
corpit
costypetrisor
+coverallsapp
coverity
cppcheck
createslavedomain
cvs
cvstrac
CXXFLAGS
+cxxsettings
+cxxsupport
daemonizing
daemontools
Daganoto
Davids
Dayneko
dbfile
+dblacka
dblfilename
dblookup
dbpf
Deduktiva
dedup
defcontent
+defmacro
defpol
defttl
Dehaine
Dimitrios
Directi
Disqus
+distclean
djbdns
dlerror
dlg
Donatas
dontcare
doq
+dotout
downsides
downstreams
dport
Dufberg
dumpluaraw
dumresp
+dwarfstd
dynblock
dynblocklist
dynblocksref
ECCN
ech
econds
-ECSDA
ecswho
editline
edns
ednssubnet
EDNSTo
edu
+eglot
ejones
Ekkelenkamp
+eldoc
elgoog
+elisp
+elpa
+emacs
endbr
Enden
enp
+Ensar
ent
envoutput
epel
firewalls
fixednow
Florus
+flycheck
+flyspell
footerbgcolor
footertextcolor
forfun
fullycapable
Furnell
Fusl
+fuzzers
fwzones
FYhvws
FZq
gatech
Gavarret
Gbps
+gcna
+gcovr
gdpr
Geijn
genindex
gettsigkey
Geuze
GFm
+ggdb
Ghz
Gibheer
Gieben
Harker
Hausberger
headbgcolor
+headerline
headerlink
headfont
headlinkcolor
ifurlextup
ifurlup
ihsinme
+imenu
Imhard
incbin
includeboilerplate
Jermar
Jeroen
jessie
+joaotavora
jonathaneen
Jong
Jorn
KEYBITS
keyblock
keydir
+keyids
+keymap
keyname
keypair
keypairgen
keyroller
keysearch
keysize
+keystyle
keytab
keytype
keywordmatches
KTNAME
Kuehrer
kvs
+KVTo
kxdpgun
Ladot
Lafon
latlon
latlonloc
latomic
-lauch
Laurient
Laursen
+lcov
LCUP
LDA
ldapbackend
letsencrypt
letterpaper
libatomic
+libclang
libcrypto
libcryptopp
libdecaf
libresolv
libressl
librt
+libsettings
libsodium
libsofthsm
+libstdc
libsystemd
libtdsodbc
libxdp
lowerroman
Lrhazi
lsock
+lsp
lto
luaaction
luabackend
mbytes
Meerwald
Mekking
+melpa
memlock
Memusage
menuselection
mnordhoff
MOADNS
Modderman
+modeline
modifyingpolicydecisions
modindex
monshouwer
netinet
netmaskgroup
netmasks
+netms
netsnmp
NETWORKMASK
Neue
Neuf
+newcomment
newcontent
nftables
nic
NODCACHEDIRUDR
noedns
noerrors
+NOLINTNEXTLINE
NOLOCK
nometasync
Nominet
NUMA
numreceived
nvd
+nwk
nxd
NXDATA
nxdomain
packetcache
packethandler
papersize
-paramater
PARAMKEYWORDS
PATC
patchlevels
PCache
pcap
PCAPFILE
+pch
pdns
pdnsbackend
pdnscontrol
+pdnskeyroller
pdnsldap
pdnslog
pdnsodbx
Pfetzing
pgmysql
pgmysqlbackend
+PGO
pgp
pgpsql
phishing
pickwrandom
piddir
pidfile
+PIDs
pilindex
Pinski
pipebackend
pipermail
+pkghashes
Plusnet
plzz
pmtmr
Predota
preoutquery
Preproc
+prepublishkeyroll
prequery
prerpz
presignedness
princ
prioritization
privs
+profdata
+profraw
+progn
protobuf
protozero
providername
querytime
qytpe
ragel
+raii
Rak
randombackend
randombit
recursord
recursordist
Recursordoc
+Recursorsettings
Recuweb
recvbuf
recverr
respout
respsizes
resynchronise
-retransfering
reuseds
reuseport
RFCs
rightsidebar
Rijsdijk
ringbuffer
+rizsotto
rkey
rmem
rname
rocommunity
Roel
+rolltype
Rosmalen
roundrobin
rping
selectmplexer
senderrors
Sendetzky
-sensistive
+serde
Sergey
serverpools
serverselection
setkey
setnotified
SETPIPE
+setq
settting
setvariable
Shabanov
softhsm
Soldaat
somedomain
+somestruct
Sonix
Soref
Soroceanu
SPHINXPROJ
sphinxsidebar
sphinxsidebarwrapper
+Spinlocks
splitsetup
Spruyt
SQLs
stutiredboy
subkey
submitters
+subnamespace
subnetmask
+substructs
suffixmatchtree
Sukhbir
supermaster
taskqueue
tbhandler
tcely
-TCounters
+tcounters
tcpconnecttimeouts
tcpdump
TCPKEEPALIVE
tcplatency
tcpmaxconcurrentconnections
tcpnewconnections
+tcpout
tcpreusedconnections
tcptoomanyconcurrentconnections
tds
tlsa
tmpfs
tobool
+TOCTOU
toctree
todos
toint
Tolstov
Toosarani
Toshifumi
+totms
Travaille
+treemacs
tribool
trustanchor
trustanchorfile
uninitialised
Uninstaller
unistd
-unitialized
unixodbc
unixtime
-unparseable
+unparsable
UNPRIV
unpublishdomainkey
unreachables
viewcode
visitedlinkcolor
vixie
+vla
Voegeli
Volker
voxel
wpad
wproduction
wrandom
+wrapv
wuh
Wzs
Xander
Xek
Xeon
XForwarded
-XFR
Xiang
xorbooter
xpf
xsk
xskmap
XXXXXX
+XXXXXXX
yahttp
yamlconversion
yamlsettings
+yasnippet
Yehuda
yeswehack
Yiu
/docs/
^docs/
+\.md$
pdns/recursordist/settings/table.py
# hit-count: 9 file-count: 7
# Compiler flags
(?:^|[\t ,"'`=(])-[DWL](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
-(?:^|[\t ,"'`=(])-f(?!ield|ile|ilter|orce|unction)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
+(?:^|[\t ,"'`=(])-f(?!ield|ile|ilter|orce|ormat|unction)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
(?:^|[\t ,"'`=(])-l(?!imited)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# hit-count: 9 file-count: 2
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b
+
+# scrypt / argon
+\$(?:scrypt|argon\d+[di]*)\$\S+
jobs:
call-build-and-test-all-master-debian-11:
- name: Call build-and-test-all master using debian 11 as docker runner image
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@master
with:
runner-docker-image-name: base-pdns-ci-image/debian-11-pdns-base
call-build-and-test-all-auth-49:
- name: Call build-and-test-all rel/auth-4.9.x
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/auth-4.9.x
with:
branch-name: rel/auth-4.9.x
call-build-and-test-all-auth-48:
- name: Call build-and-test-all rel/auth-4.8.x
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/auth-4.8.x
with:
branch-name: rel/auth-4.8.x
call-build-and-test-all-auth-47:
- name: Call build-and-test-all rel/auth-4.7.x
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/auth-4.7.x
with:
branch-name: rel/auth-4.7.x
- call-build-and-test-all-auth-46:
- name: Call build-and-test-all rel/auth-4.6.x
+ call-build-and-test-all-rec-51:
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
- uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/auth-4.6.x
+ uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/rec-5.1.x
with:
- branch-name: rel/auth-4.6.x
+ branch-name: rel/rec-5.1.x
call-build-and-test-all-rec-50:
- name: Call build-and-test-all rel/rec-5.0.x
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/rec-5.0.x
with:
branch-name: rel/rec-5.0.x
call-build-and-test-all-rec-49:
- name: Call build-and-test-all rel/rec-4.9.x
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/rec-4.9.x
with:
branch-name: rel/rec-4.9.x
- call-build-and-test-all-rec-48:
- name: Call build-and-test-all rel/rec-4.8.x
- if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
- uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/rec-4.8.x
- with:
- branch-name: rel/rec-4.8.x
-
call-build-and-test-all-dnsdist-19:
- name: Call build-and-test-all rel/dnsdist-1.9.x
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/dnsdist-1.9.x
with:
branch-name: rel/dnsdist-1.9.x
call-build-and-test-all-dnsdist-18:
- name: Call build-and-test-all rel/dnsdist-1.8.x
if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/dnsdist-1.8.x
with:
branch-name: rel/dnsdist-1.8.x
-
- call-build-and-test-all-dnsdist-17:
- name: Call build-and-test-all rel/dnsdist-1.7.x
- if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
- uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/dnsdist-1.7.x
- with:
- branch-name: rel/dnsdist-1.7.x
echo "tag=${{ env.DEFAULT_IMAGE_TAG }}" >> "$GITHUB_OUTPUT"
build-auth:
- name: build auth
+ name: build auth (${{ matrix.builder }})
if: ${{ !github.event.schedule || vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
runs-on: ubuntu-22.04
needs: get-runner-container-image
container:
- image: "${{ needs.get-runner-container-image.outputs.id }}:${{ needs.get-runner-container-image.outputs.tag }}"
+ image: "${{ matrix.container_image }}"
env:
FUZZING_TARGETS: yes
UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1:suppressions=${{ env.REPO_HOME }}/build-scripts/UBSan.supp"
options: --sysctl net.ipv6.conf.all.disable_ipv6=0
strategy:
matrix:
- include:
- - builder: autotools
- sanitizers: asan+ubsan
- - builder: meson
- sanitizers: address,undefined
- build_option: '--meson'
+ container_image: ["${{ needs.get-runner-container-image.outputs.id }}:${{ needs.get-runner-container-image.outputs.tag }}"]
+ builder: [autotools, meson]
+ exclude:
+ - container_image: "ghcr.io/powerdns/base-pdns-ci-image/debian-11-pdns-base:${{ needs.get-runner-container-image.outputs.tag }}"
+ builder: meson
fail-fast: false
defaults:
run:
key: auth-ccache-${{ matrix.builder }}-${{ steps.get-stamp.outputs.stamp }}
restore-keys: auth-ccache-${{ matrix.builder }}
- name: set sanitizers
- run: echo "SANITIZERS=${{ matrix.sanitizers }}" >> "$GITHUB_ENV"
+ run: echo "SANITIZERS=${{ matrix.builder == 'meson' && 'address,undefined' || 'asan+ubsan' }}" >> "$GITHUB_ENV"
working-directory: .
- run: inv install-auth-build-deps
working-directory: .
- - run: inv ci-autoconf ${{ matrix.build_option }}
+ - run: inv ci-autoconf ${{ matrix.builder == 'meson' && '--meson' || '' }}
working-directory: .
- - run: inv ci-auth-configure ${{ matrix.build_option }} -b pdns-${{ env.BUILDER_VERSION }}
+ - run: inv ci-auth-configure ${{ matrix.builder == 'meson' && '--meson' || '' }} -b pdns-${{ env.BUILDER_VERSION }}
working-directory: .
- - run: inv ci-auth-build ${{ matrix.build_option }} # This runs under pdns-$BUILDER_VERSION/pdns/ for make bear
+ - run: inv ci-auth-build ${{ matrix.builder == 'meson' && '--meson' || '' }} # This runs under pdns-$BUILDER_VERSION/pdns/ for make bear
- run: inv ci-auth-install-remotebackend-test-deps
- - run: inv ci-auth-run-unit-tests ${{ matrix.build_option }}
+ - if: ${{ matrix.builder == 'meson' }}
+ run: inv install-auth-test-deps-only -b geoip
+ - run: inv ci-auth-run-unit-tests ${{ matrix.builder == 'meson' && '--meson' || '' }}
+ env:
+ PDNS_BUILD_PATH: ../pdns-${{ env.BUILDER_VERSION }}
- run: inv generate-coverage-info ./testrunner $GITHUB_WORKSPACE
if: ${{ env.COVERAGE == 'yes' && matrix.builder != 'meson' }}
working-directory: ./pdns-${{ env.BUILDER_VERSION }}/pdns
if: ${{ env.COVERAGE == 'yes' && matrix.builder != 'meson' }}
uses: coverallsapp/github-action@v2
with:
- flag-name: auth-unit-${{ matrix.sanitizers }}
+ flag-name: auth-unit-${{ env.SANITIZERS }}
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
- - run: inv ci-auth-install ${{ matrix.build_option }}
+ fail-on-error: false
+ - run: inv ci-auth-install ${{ matrix.builder == 'meson' && '--meson' || '' }}
- run: ccache -s
- if: ${{ matrix.builder != 'meson' }}
run: echo "normalized-branch-name=${{ inputs.branch-name || github.ref_name }}" | tr "/" "-" >> "$GITHUB_ENV"
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
- run: inv ci-make-install
- run: ccache -s
- run: echo "normalized-branch-name=${{ inputs.branch-name || github.ref_name }}" | tr "/" "-" >> "$GITHUB_ENV"
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
- run: inv ci-make-install
- run: ccache -s
- run: echo "normalized-branch-name=${{ inputs.branch-name || github.ref_name }}" | tr "/" "-" >> "$GITHUB_ENV"
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
test-auth-backend:
needs:
env: {}
ports: []
- backend: godbc_mssql
- image: mcr.microsoft.com/mssql/server:2017-GA-ubuntu
+ image: mcr.microsoft.com/mssql/server:2022-CU12-ubuntu-22.04
env:
ACCEPT_EULA: Y
SA_PASSWORD: 'SAsa12%%-not-a-secret-password'
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
test-ixfrdist:
needs:
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
test-recursor-api:
needs:
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
test-recursor-regression:
needs:
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
test-recursor-bulk:
name: 'test rec *mini* bulk'
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
test-dnsdist-regression:
needs:
path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
parallel: true
allow-empty: true
+ fail-on-error: false
swagger-syntax-check:
if: ${{ !github.event.schedule || vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
uses: coverallsapp/github-action@v2
with:
parallel-finished: true
+ fail-on-error: false
- name: Install jq and jc
run: "sudo apt-get update && sudo apt-get install jq jc"
- name: Fail job if any of the previous jobs failed
tags: ${{ inputs.image-tags }}
- name: Build and load powerdns product images
id: build-image
- uses: docker/build-push-action@v5
+ uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile-${{ inputs.product }}
--- /dev/null
+---
+name: 'daily: build packages for master '
+
+on:
+ schedule:
+ - cron: '0 5 * * *'
+
+permissions:
+ actions: read
+ id-token: write
+ contents: write
+
+jobs:
+ call-build-packages-auth:
+ uses: PowerDNS/pdns/.github/workflows/build-packages.yml@master
+ with:
+ is_release: 'NO'
+ product: 'authoritative'
+ ref: master
+ secrets:
+ DOWNLOADS_AUTOBUILT_SECRET: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
+ DOWNLOADS_AUTOBUILT_RSYNCTARGET: ${{ secrets.DOWNLOADS_AUTOBUILT_RSYNCTARGET }}
+ DOWNLOADS_AUTOBUILT_HOSTKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_HOSTKEY }}
+
+ call-build-packages-dnsdist:
+ uses: PowerDNS/pdns/.github/workflows/build-packages.yml@master
+ with:
+ is_release: 'NO'
+ product: 'dnsdist'
+ ref: master
+ secrets:
+ DOWNLOADS_AUTOBUILT_SECRET: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
+ DOWNLOADS_AUTOBUILT_RSYNCTARGET: ${{ secrets.DOWNLOADS_AUTOBUILT_RSYNCTARGET }}
+ DOWNLOADS_AUTOBUILT_HOSTKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_HOSTKEY }}
+
+ call-build-packages-rec:
+ uses: PowerDNS/pdns/.github/workflows/build-packages.yml@master
+ with:
+ is_release: 'NO'
+ product: 'recursor'
+ ref: master
+ secrets:
+ DOWNLOADS_AUTOBUILT_SECRET: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
+ DOWNLOADS_AUTOBUILT_RSYNCTARGET: ${{ secrets.DOWNLOADS_AUTOBUILT_RSYNCTARGET }}
+ DOWNLOADS_AUTOBUILT_HOSTKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_HOSTKEY }}
jobs:
prepare:
name: generate OS list
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
outputs:
oslist: ${{ steps.get-oslist.outputs.oslist }}
steps:
run: echo "oslist=$(jo -a ${{ inputs.os }})" >> "$GITHUB_OUTPUT"
build:
needs: prepare
- name: build ${{ inputs.product }} (${{ inputs.ref }}) for ${{ matrix.os }}
- # on a ubuntu-20.04 VM
- runs-on: ubuntu-20.04
+ name: ${{ inputs.product }} (${{ inputs.ref }}) on ${{ matrix.runner-os }} for ${{ matrix.os }}
+ runs-on: ${{ matrix.runner-os }}
strategy:
matrix:
os: ${{fromJson(needs.prepare.outputs.oslist)}}
+ runner-os:
+ - ubuntu-22.04
+ - ubicloud-standard-2-arm
+ exclude:
+ - os: el-7
+ runner-os: ubicloud-standard-2-arm
fail-fast: false
outputs:
+ product-name: ${{ steps.normalize-name.outputs.normalized-package-name }}
version: ${{ steps.getversion.outputs.version }}
- pkghashes-el-7: ${{ steps.pkghashes.outputs.pkghashes-el-7 }}
- pkghashes-el-8: ${{ steps.pkghashes.outputs.pkghashes-el-8 }}
- pkghashes-el-9: ${{ steps.pkghashes.outputs.pkghashes-el-9 }}
- pkghashes-debian-buster: ${{ steps.pkghashes.outputs.pkghashes-debian-buster }}
- pkghashes-debian-bullseye: ${{ steps.pkghashes.outputs.pkghashes-debian-bullseye }}
- pkghashes-debian-bookworm: ${{ steps.pkghashes.outputs.pkghashes-debian-bookworm }}
- pkghashes-ubuntu-focal: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-focal }}
- pkghashes-ubuntu-jammy: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-jammy }}
- pkghashes-ubuntu-noble: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-noble }}
+ pkghashes-el-7-x86_64: ${{ steps.pkghashes.outputs.pkghashes-el-7-x86_64 }}
+ pkghashes-el-8-x86_64: ${{ steps.pkghashes.outputs.pkghashes-el-8-x86_64 }}
+ pkghashes-el-8-aarch64: ${{ steps.pkghashes.outputs.pkghashes-el-8-aarch64 }}
+ pkghashes-el-9-x86_64: ${{ steps.pkghashes.outputs.pkghashes-el-9-x86_64 }}
+ pkghashes-el-9-aarch64: ${{ steps.pkghashes.outputs.pkghashes-el-9-aarch64 }}
+ pkghashes-debian-buster-x86_64: ${{ steps.pkghashes.outputs.pkghashes-debian-buster-x86_64 }}
+ pkghashes-debian-buster-aarch64: ${{ steps.pkghashes.outputs.pkghashes-debian-buster-aarch64 }}
+ pkghashes-debian-bullseye-x86_64: ${{ steps.pkghashes.outputs.pkghashes-debian-bullseye-x86_64 }}
+ pkghashes-debian-bullseye-aarch64: ${{ steps.pkghashes.outputs.pkghashes-debian-bullseye-aarch64 }}
+ pkghashes-debian-bookworm-x86_64: ${{ steps.pkghashes.outputs.pkghashes-debian-bookworm-x86_64 }}
+ pkghashes-debian-bookworm-aarch64: ${{ steps.pkghashes.outputs.pkghashes-debian-bookworm-aarch64 }}
+ pkghashes-ubuntu-focal-x86_64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-focal-x86_64 }}
+ pkghashes-ubuntu-focal-aarch64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-focal-aarch64 }}
+ pkghashes-ubuntu-jammy-x86_64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-jammy-x86_64 }}
+ pkghashes-ubuntu-jammy-aarch64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-jammy-aarch64 }}
+ pkghashes-ubuntu-noble-x86_64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-noble-x86_64 }}
+ pkghashes-ubuntu-noble-aarch64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-noble-aarch64 }}
srchashes: ${{ steps.srchashes.outputs.srchashes }}
steps:
- uses: actions/checkout@v4
run: |
echo "version=$(readlink builder/tmp/latest)" >> $GITHUB_OUTPUT
id: getversion
- - name: Upload packages as GH artifacts
- uses: actions/upload-artifact@v4
- with:
- name: ${{ inputs.product }}-${{ matrix.os }}-${{ steps.getversion.outputs.version }}
- path: built_pkgs/
- retention-days: 7
+ - name: Get target architecture
+ run: |
+ echo "target-arch=$(uname -m)" >> $GITHUB_OUTPUT
+ id: getarch
- name: Normalize package name
id: normalize-name
run: |
else
echo "normalized-package-name=${{ inputs.product }}" >> $GITHUB_OUTPUT
fi
-
+ - name: Include architecture in the packages compressed file name
+ run: for f in $(ls ./built_pkgs/*/*/*-${{ matrix.os }}.tar.bz2 | sed 's/\.tar.bz2$//'); do mv $f.tar.bz2 $f-${{ steps.getarch.outputs.target-arch }}.tar.bz2; done
+ - name: Upload packages as GH artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ inputs.product }}-${{ matrix.os }}-${{ steps.getversion.outputs.version }}-${{ steps.getarch.outputs.target-arch }}
+ path: built_pkgs/
+ retention-days: 7
- name: Extract packages from the tarball
# so we get provenance for individual packages (and the JSON package manifests from the builder)
id: extract
run: |
mkdir -m 700 -p ./packages/
- tar xvf ./built_pkgs/*/*/${{ steps.normalize-name.outputs.normalized-package-name }}-${{ steps.getversion.outputs.version }}-${{ matrix.os }}.tar.bz2 -C ./packages/ --transform='s/.*\///'
+ tar xvf ./built_pkgs/*/*/${{ steps.normalize-name.outputs.normalized-package-name }}-${{ steps.getversion.outputs.version }}-${{ matrix.os }}-${{ steps.getarch.outputs.target-arch }}.tar.bz2 -C ./packages/ --transform='s/.*\///'
- name: Generate package hashes for provenance
shell: bash
id: pkghashes
run: |
- echo "pkghashes-${{ matrix.os }}=$(sha256sum ./packages/*.rpm ./packages/*.deb ./packages/*.json | base64 -w0)" >> $GITHUB_OUTPUT
+ echo "pkghashes-${{ matrix.os }}-${{ steps.getarch.outputs.target-arch }}=$(sha256sum ./packages/*.rpm ./packages/*.deb ./packages/*.json | base64 -w0)" >> $GITHUB_OUTPUT
- name: Generate source hash for provenance
shell: bash
id: srchashes
run: |
- echo "srchashes=$(sha256sum ./built_pkgs/*/*/${{ steps.normalize-name.outputs.normalized-package-name }}-${{ steps.getversion.outputs.version }}.tar.bz2 ./packages/*.json | base64 -w0)" >> $GITHUB_OUTPUT
+ echo "srchashes=$(sha256sum ./built_pkgs/*/*/${{ steps.normalize-name.outputs.normalized-package-name }}-${{ steps.getversion.outputs.version }}.tar.bz2 | base64 -w0)" >> $GITHUB_OUTPUT
- name: Upload packages to downloads.powerdns.com
env:
SSHKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
check-hashes:
needs: build
name: Check if hashes were created for all requested targets
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
steps:
- name: Get list of outputs from build jobs
- run: echo '${{ toJSON(needs.build.outputs) }}' | jq 'keys[]' | grep -v version | tee /tmp/build-outputs.txt
+ run: echo '${{ toJSON(needs.build.outputs) }}' | jq 'keys[]' | grep -vE 'version|product-name' | tee /tmp/build-outputs.txt
- name: Get list of OS inputs
- run: for i in ${{ inputs.os }}; do echo "\"pkghashes-$i\""; done | sort | tee /tmp/os-inputs.txt; echo "\"srchashes\"" | tee -a /tmp/os-inputs.txt
+ run: |
+ for os in ${{ inputs.os }}; do
+ for architecture in x86_64 aarch64; do
+ [[ "$os" != "el-7" || "$architecture" != "aarch64" ]] && echo "\"pkghashes-$os-$architecture\"" | tee -a /tmp/os-inputs.txt
+ done
+ done
+ sort -o /tmp/os-inputs.txt /tmp/os-inputs.txt
+ echo "\"srchashes\"" | tee -a /tmp/os-inputs.txt
- name: Fail if there is a hash missing
run: if ! diff -q /tmp/build-outputs.txt /tmp/os-inputs.txt; then exit 1; fi
strategy:
matrix:
os: ${{fromJson(needs.prepare.outputs.oslist)}}
+ architecture: ['x86_64', 'aarch64']
+ exclude:
+ - os: el-7
+ architecture: aarch64
permissions:
actions: read # To read the workflow path.
id-token: write # To sign the provenance.
contents: write # To be able to upload assets as release artifacts
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
with:
- base64-subjects: "${{ needs.build.outputs[format('pkghashes-{0}', matrix.os)] }}"
+ base64-subjects: "${{ needs.build.outputs[format('pkghashes-{0}-{1}', matrix.os, matrix.architecture)] }}"
upload-assets: false
- provenance-name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-${{ matrix.os}}.intoto.jsonl"
+ provenance-name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-${{ matrix.os }}-${{ matrix.architecture }}.intoto.jsonl"
+ private-repository: true
provenance-src:
needs: build
base64-subjects: "${{ needs.build.outputs.srchashes }}"
upload-assets: false
provenance-name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-src.intoto.jsonl"
+ private-repository: true
upload-provenance:
needs: [prepare, build, provenance-src, provenance-pkgs]
name: Upload the provenance artifacts to downloads.powerdns.com
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
strategy:
matrix:
os: ${{fromJson(needs.prepare.outputs.oslist)}}
+ architecture: ['x86_64', 'aarch64']
+ exclude:
+ - os: el-7
+ architecture: aarch64
steps:
- name: Download source tarball provenance for ${{ inputs.product }} (${{ inputs.ref }})
id: download-src-provenance
id: download-provenance
uses: actions/download-artifact@v4 # be careful, this needs to match what https://github.com/slsa-framework/slsa-github-generator is using
with:
- name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-${{ matrix.os}}.intoto.jsonl"
+ name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-${{ matrix.os }}-${{ matrix.architecture }}.intoto.jsonl"
- name: Upload provenance artifacts to downloads.powerdns.com
id: upload-provenance
env:
SSHKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
RSYNCTARGET: ${{ secrets.DOWNLOADS_AUTOBUILT_RSYNCTARGET }}
HOSTKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_HOSTKEY }}
- PRODUCT: ${{ inputs.product }}
+ PRODUCT: ${{ needs.build.outputs.product-name }}
VERSION: ${{ needs.build.outputs.version }}
if:
"${{ env.SSHKEY != '' }}"
echo "$SSHKEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
echo "$HOSTKEY" > ~/.ssh/known_hosts
- rsync -4rlptD ${{steps.download-src-provenance.outputs.download-path}}/*.jsonl ${{steps.download-provenance.outputs.download-path}}/*.jsonl "${RSYNCTARGET}/${PRODUCT}/${VERSION}/"
+ mkdir -m 755 -p "slsa/${PRODUCT}/${VERSION}/"
+ mv ${{steps.download-provenance.outputs.download-path}}/*.jsonl "slsa/${PRODUCT}/${VERSION}"
+ rsync -4rlptD slsa/* "$RSYNCTARGET"
jobs:
call-builder-auth-49:
- name: Call builder rel/auth-4.9.x
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/auth-4.9.x
with:
branch-name: rel/auth-4.9.x
call-builder-auth-48:
- name: Call builder rel/auth-4.8.x
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/auth-4.8.x
with:
branch-name: rel/auth-4.8.x
call-builder-auth-47:
- name: Call builder rel/auth-4.7.x
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/auth-4.7.x
with:
branch-name: rel/auth-4.7.x
- call-builder-auth-46:
- name: Call builder rel/auth-4.6.x
+ call-builder-rec-51:
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
- uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/auth-4.6.x
+ uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/rec-5.1.x
with:
- branch-name: rel/auth-4.6.x
+ branch-name: rel/rec-5.1.x
call-builder-rec-50:
- name: Call builder rel/rec-5.0.x
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/rec-5.0.x
with:
branch-name: rel/rec-5.0.x
call-builder-rec-49:
- name: Call builder rel/rec-4.9.x
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/rec-4.9.x
with:
branch-name: rel/rec-4.9.x
- call-builder-rec-48:
- name: Call builder rel/rec-4.8.x
- if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
- uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/rec-4.8.x
- with:
- branch-name: rel/rec-4.8.x
-
call-builder-dnsdist-19:
- name: Call builder rel/dnsdist-1.9.x
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/dnsdist-1.9.x
with:
branch-name: rel/dnsdist-1.9.x
call-builder-dnsdist-18:
- name: Call builder rel/dnsdist-1.8.x
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/dnsdist-1.8.x
with:
branch-name: rel/dnsdist-1.8.x
-
- call-builder-dnsdist-17:
- name: Call builder rel/dnsdist-1.7.x
- if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
- uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/dnsdist-1.7.x
- with:
- branch-name: rel/dnsdist-1.7.x
build:
name: build.sh
if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
- # on a ubuntu-20.04 VM
- runs-on: ubuntu-20.04
+ runs-on: ${{ matrix.runner-os }}
strategy:
matrix:
product: ['authoritative', 'recursor', 'dnsdist']
os:
- - centos-7
+ - el-7
- el-8
- - centos-8-stream
- centos-9-stream
- ubuntu-lunar
- ubuntu-mantic
- debian-bookworm
- debian-trixie
- amazon-2023
+ runner-os:
+ - ubuntu-22.04
+ - ubicloud-standard-2-arm
+ exclude:
+ - os: el-7
+ runner-os: ubicloud-standard-2-arm
fail-fast: false
steps:
- uses: actions/checkout@v4
run: |
echo "version=$(readlink builder/tmp/latest)" >> $GITHUB_OUTPUT
id: getversion
+ - name: Get target architecture
+ run: |
+ echo "target-arch=$(uname -m)" >> $GITHUB_OUTPUT
+ id: getarch
- name: Upload packages
uses: actions/upload-artifact@v4
with:
- name: ${{ matrix.product }}-${{ matrix.os }}-${{ steps.getversion.outputs.version }}
+ name: ${{ matrix.product }}-${{ matrix.os }}-${{ steps.getversion.outputs.version }}-${{ steps.getarch.outputs.target-arch }}
path: built_pkgs/
retention-days: 7
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
if: matrix.product == 'auth'
- name: Run clang-tidy for auth
if: matrix.product == 'auth'
- run: git diff --no-prefix -U0 HEAD^..HEAD | python3 .github/scripts/git-filter.py --product auth | python3 .github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-auth.yml
+ run: git diff --no-prefix -U0 HEAD^..HEAD | /usr/bin/python3 .github/scripts/git-filter.py --product auth | /usr/bin/python3 .github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-auth.yml
- name: Print clang-tidy fixes YAML for auth
if: matrix.product == 'auth'
shell: bash
run: |
if [ -f clang-tidy-auth.yml ]; then
set +e
- python3 .github/scripts/clang-tidy.py --fixes-file clang-tidy-auth.yml
+ /usr/bin/python3 .github/scripts/clang-tidy.py --fixes-file clang-tidy-auth.yml
echo "failed=$?" >> $GITHUB_OUTPUT
fi
- name: Run clang-tidy for dnsdist
if: matrix.product == 'dnsdist'
working-directory: ./pdns/dnsdistdist/
- run: git diff --no-prefix -U0 HEAD^..HEAD | python3 ../../.github/scripts/git-filter.py --product dnsdist | python3 ../../.github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-dnsdist.yml
+ run: git diff --no-prefix -U0 HEAD^..HEAD | /usr/bin/python3 ../../.github/scripts/git-filter.py --product dnsdist | /usr/bin/python3 ../../.github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-dnsdist.yml
- name: Print clang-tidy fixes YAML for dnsdist
if: matrix.product == 'dnsdist'
working-directory: ./pdns/dnsdistdist/
run: |
if [ -f clang-tidy-dnsdist.yml ]; then
set +e
- python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-dnsdist.yml
+ /usr/bin/python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-dnsdist.yml
echo "failed=$?" >> $GITHUB_OUTPUT
fi
- name: Run clang-tidy for rec
if: matrix.product == 'rec'
working-directory: ./pdns/recursordist/
- run: git diff --no-prefix -U0 HEAD^..HEAD | python3 ../../.github/scripts/git-filter.py --product rec | python3 ../../.github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-rec.yml
+ run: git diff --no-prefix -U0 HEAD^..HEAD | /usr/bin/python3 ../../.github/scripts/git-filter.py --product rec | /usr/bin/python3 ../../.github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-rec.yml
- name: Print clang-tidy fixes YAML for rec
if: matrix.product == 'rec'
working-directory: ./pdns/recursordist/
run: |
if [ -f clang-tidy-rec.yml ]; then
set +e
- python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-rec.yml
+ /usr/bin/python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-rec.yml
echo "failed=$?" >> $GITHUB_OUTPUT
fi
--- /dev/null
+---
+name: Trigger specific coverity scan
+
+on:
+ workflow_dispatch:
+ inputs:
+ product:
+ description: Product to build
+ type: choice
+ options:
+ - authoritative
+ - recursor
+ - dnsdist
+
+permissions: # least privileges, see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+ contents: read
+
+jobs:
+ coverity-auth:
+ name: coverity scan of the auth
+ if: ${{ github.event.inputs.product == 'authoritative' }}
+ uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+ with:
+ product: ${{ github.event.inputs.product }}
+ secrets:
+ COVERITY_TOKEN: ${{ secrets.coverity_auth_token }}
+ COVERITY_EMAIL: ${{ secrets.coverity_email }}
+
+ coverity-dnsdist:
+ name: coverity scan of dnsdist
+ if: ${{ github.event.inputs.product == 'dnsdist' }}
+ uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+ with:
+ product: ${{ github.event.inputs.product }}
+ secrets:
+ COVERITY_TOKEN: ${{ secrets.coverity_dnsdist_token }}
+ COVERITY_EMAIL: ${{ secrets.coverity_email }}
+
+ coverity-rec:
+ name: coverity scan of the rec
+ if: ${{ github.event.inputs.product == 'recursor' }}
+ uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+ with:
+ product: ${{ github.event.inputs.product }}
+ secrets:
+ COVERITY_TOKEN: ${{ secrets.coverity_rec_token }}
+ COVERITY_EMAIL: ${{ secrets.coverity_email }}
--- /dev/null
+---
+name: Coverity scan
+
+on:
+ workflow_call:
+ inputs:
+ product:
+ required: true
+ description: Product to build
+ type: string
+ secrets:
+ COVERITY_TOKEN:
+ required: true
+ COVERITY_EMAIL:
+ required: true
+
+permissions: # least privileges, see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+ contents: read
+
+env:
+ CLANG_VERSION: '12'
+
+jobs:
+ coverity-auth:
+ name: coverity scan of the auth
+ if: ${{ inputs.product == 'authoritative' }}
+ runs-on: ubuntu-22.04
+ env:
+ COVERITY_TOKEN: ${{ secrets.COVERITY_TOKEN }}
+ FUZZING_TARGETS: no
+ SANITIZERS:
+ UNIT_TESTS: no
+ steps:
+ - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 5
+ submodules: recursive
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
+ - run: inv install-clang
+ - run: inv install-auth-build-deps
+ - run: inv install-coverity-tools PowerDNS
+ - run: inv coverity-clang-configure
+ - run: inv ci-autoconf
+ - run: inv ci-auth-configure
+ - run: inv coverity-make
+ - run: inv coverity-tarball auth.tar.bz2
+ - run: inv coverity-upload ${{ secrets.COVERITY_EMAIL }} PowerDNS auth.tar.bz2
+
+ coverity-dnsdist:
+ name: coverity scan of dnsdist
+ if: ${{ inputs.product == 'dnsdist' }}
+ runs-on: ubuntu-22.04
+ env:
+ COVERITY_TOKEN: ${{ secrets.COVERITY_TOKEN }}
+ SANITIZERS:
+ UNIT_TESTS: no
+ REPO_HOME: ${{ github.workspace }}
+ steps:
+ - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 5
+ submodules: recursive
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
+ - run: inv install-clang
+ - run: inv install-dnsdist-build-deps --skipXDP
+ - run: inv install-coverity-tools dnsdist
+ - run: inv coverity-clang-configure
+ - run: inv ci-autoconf
+ working-directory: ./pdns/dnsdistdist/
+ - run: inv ci-install-rust ${{ env.REPO_HOME }}
+ working-directory: ./pdns/dnsdistdist/
+ - run: inv ci-build-and-install-quiche ${{ env.REPO_HOME }}
+ working-directory: ./pdns/dnsdistdist/
+ - run: inv ci-dnsdist-configure full
+ working-directory: ./pdns/dnsdistdist/
+ - run: inv coverity-make
+ working-directory: ./pdns/dnsdistdist/
+ - run: inv coverity-tarball dnsdist.tar.bz2
+ working-directory: ./pdns/dnsdistdist/
+ - run: inv coverity-upload ${{ secrets.COVERITY_EMAIL }} dnsdist dnsdist.tar.bz2
+ working-directory: ./pdns/dnsdistdist/
+
+ coverity-rec:
+ name: coverity scan of the rec
+ if: ${{ inputs.product == 'recursor' }}
+ runs-on: ubuntu-22.04
+ env:
+ COVERITY_TOKEN: ${{ secrets.COVERITY_TOKEN }}
+ SANITIZERS:
+ UNIT_TESTS: no
+ steps:
+ - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 5
+ submodules: recursive
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
+ - run: inv install-clang
+ - run: inv install-rec-build-deps
+ - run: inv install-coverity-tools 'PowerDNS+Recursor'
+ - run: inv coverity-clang-configure
+ - run: inv ci-autoconf
+ working-directory: ./pdns/recursordist/
+ - run: inv ci-rec-configure full
+ working-directory: ./pdns/recursordist/
+ - run: inv coverity-make
+ working-directory: ./pdns/recursordist/
+ - run: inv coverity-tarball recursor.tar.bz2
+ working-directory: ./pdns/recursordist/
+ - run: inv coverity-upload ${{ secrets.COVERITY_EMAIL }} 'PowerDNS+Recursor' recursor.tar.bz2
+ working-directory: ./pdns/recursordist/
steps:
- uses: PowerDNS/pdns/set-ubuntu-mirror@meta
- uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
# Configure pip index-url set to proxpi
- run: pip config set global.index-url http://${{ env.SERVICE_IP_ADDR }}:5000/index/
- run: pip config set global.trusted-host ${{ env.SERVICE_IP_ADDR }}
coverity-auth:
name: coverity scan of the auth
if: ${{ vars.SCHEDULED_MISC_DAILIES }}
- runs-on: ubuntu-22.04
- env:
+ uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+ with:
+ product: 'authoritative'
+ secrets:
COVERITY_TOKEN: ${{ secrets.coverity_auth_token }}
- FUZZING_TARGETS: no
- SANITIZERS:
- UNIT_TESTS: no
- steps:
- - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
- - uses: actions/checkout@v4
- with:
- fetch-depth: 5
- submodules: recursive
- - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
- - run: inv install-clang
- - run: inv install-auth-build-deps
- - run: inv install-coverity-tools PowerDNS
- - run: inv coverity-clang-configure
- - run: inv ci-autoconf
- - run: inv ci-auth-configure
- - run: inv coverity-make
- - run: inv coverity-tarball auth.tar.bz2
- - run: inv coverity-upload ${{ secrets.coverity_email }} PowerDNS auth.tar.bz2
+ COVERITY_EMAIL: ${{ secrets.coverity_email }}
coverity-dnsdist:
name: coverity scan of dnsdist
if: ${{ vars.SCHEDULED_MISC_DAILIES }}
- runs-on: ubuntu-22.04
- env:
+ uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+ with:
+ product: 'dnsdist'
+ secrets:
COVERITY_TOKEN: ${{ secrets.coverity_dnsdist_token }}
- SANITIZERS:
- UNIT_TESTS: no
- REPO_HOME: ${{ github.workspace }}
- steps:
- - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
- - uses: actions/checkout@v4
- with:
- fetch-depth: 5
- submodules: recursive
- - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
- - run: inv install-clang
- - run: inv install-dnsdist-build-deps --skipXDP
- - run: inv install-coverity-tools dnsdist
- - run: inv coverity-clang-configure
- - run: inv ci-autoconf
- working-directory: ./pdns/dnsdistdist/
- - run: inv ci-build-and-install-quiche ${{ env.REPO_HOME }}
- working-directory: ./pdns/dnsdistdist/
- - run: inv ci-dnsdist-configure full
- working-directory: ./pdns/dnsdistdist/
- - run: inv coverity-make
- working-directory: ./pdns/dnsdistdist/
- - run: inv coverity-tarball dnsdist.tar.bz2
- working-directory: ./pdns/dnsdistdist/
- - run: inv coverity-upload ${{ secrets.coverity_email }} dnsdist dnsdist.tar.bz2
- working-directory: ./pdns/dnsdistdist/
+ COVERITY_EMAIL: ${{ secrets.coverity_email }}
coverity-rec:
name: coverity scan of the rec
if: ${{ vars.SCHEDULED_MISC_DAILIES }}
- runs-on: ubuntu-22.04
- env:
+ uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+ with:
+ product: 'recursor'
+ secrets:
COVERITY_TOKEN: ${{ secrets.coverity_rec_token }}
- SANITIZERS:
- UNIT_TESTS: no
- steps:
- - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
- - uses: actions/checkout@v4
- with:
- fetch-depth: 5
- submodules: recursive
- - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
- - run: inv install-clang
- - run: inv install-rec-build-deps
- - run: inv install-coverity-tools 'PowerDNS+Recursor'
- - run: inv coverity-clang-configure
- - run: inv ci-autoconf
- working-directory: ./pdns/recursordist/
- - run: inv ci-rec-configure full
- working-directory: ./pdns/recursordist/
- - run: inv coverity-make
- working-directory: ./pdns/recursordist/
- - run: inv coverity-tarball recursor.tar.bz2
- working-directory: ./pdns/recursordist/
- - run: inv coverity-upload ${{ secrets.coverity_email }} 'PowerDNS+Recursor' recursor.tar.bz2
- working-directory: ./pdns/recursordist/
+ COVERITY_EMAIL: ${{ secrets.coverity_email }}
compile_commands.*
.cache
/.clang-tidy
+.ccls-cache
.gdb_history
.venv
./ext/lmdb-safe/lmdb-safe.cc
./ext/lmdb-safe/lmdb-safe.hh
-./ext/lmdb-safe/lmdb-typed.cc
./ext/lmdb-safe/lmdb-typed.hh
./ext/probds/murmur3.cc
./pdns/anadns.hh
./pdns/auth-carbon.cc
./pdns/auth-packetcache.cc
./pdns/auth-packetcache.hh
+./pdns/auth-primarycommunicator.cc
./pdns/auth-querycache.cc
./pdns/auth-querycache.hh
./pdns/axfr-retriever.cc
./pdns/base64.cc
./pdns/base64.hh
./pdns/bindparserclasses.hh
-./pdns/bpf-filter.cc
-./pdns/bpf-filter.hh
./pdns/calidns.cc
./pdns/capabilities.cc
./pdns/cdb.cc
./pdns/comfun.cc
./pdns/comment.hh
./pdns/dbdnsseckeeper.cc
-./pdns/delaypipe.cc
-./pdns/delaypipe.hh
./pdns/distributor.hh
./pdns/dns.cc
./pdns/dns.hh
./pdns/dnswasher.cc
./pdns/dnswriter.cc
./pdns/dnswriter.hh
-./pdns/doh.hh
./pdns/dumresp.cc
./pdns/dynhandler.cc
./pdns/dynhandler.hh
./pdns/ednsoptions.cc
./pdns/ednsoptions.hh
./pdns/ednspadding.cc
-./pdns/fstrm_logger.cc
-./pdns/fstrm_logger.hh
./pdns/gettime.cc
./pdns/gettime.hh
./pdns/histog.hh
./pdns/kvresp.cc
./pdns/libssl.cc
./pdns/libssl.hh
-./pdns/lock.hh
./pdns/lua-auth4.cc
./pdns/lua-auth4.hh
./pdns/lua-base4.cc
./pdns/lua-record.cc
./pdns/malloctrace.cc
./pdns/malloctrace.hh
-./pdns/auth-primarycommunicator.cc
./pdns/minicurl.cc
./pdns/minicurl.hh
./pdns/misc.cc
./pdns/pdnsutil.cc
./pdns/pkcs11signers.cc
./pdns/pkcs11signers.hh
-./pdns/protozero.cc
-./pdns/protozero.hh
./pdns/proxy-protocol.cc
./pdns/proxy-protocol.hh
./pdns/qtype.cc
./pdns/secpoll.cc
./pdns/secpoll.hh
./pdns/serialtweaker.cc
-./pdns/sholder.hh
./pdns/signingpipe.cc
./pdns/signingpipe.hh
./pdns/sillyrecords.cc
./pdns/snmp-agent.cc
./pdns/snmp-agent.hh
./pdns/speedtest.cc
-./pdns/sstuff.hh
./pdns/standalone_fuzz_target_runner.cc
./pdns/stat_t.hh
./pdns/statbag.cc
./pdns/test-packetcache_hh.cc
./pdns/test-proxy_protocol_cc.cc
./pdns/test-rcpgenerator_cc.cc
-./pdns/test-sholder_hh.cc
./pdns/test-statbag_cc.cc
./pdns/test-svc_records_cc.cc
./pdns/test-trusted-notification-proxy_cc.cc
./pdns/uuid-utils.cc
./pdns/validate.cc
./pdns/validate.hh
-./pdns/version.cc
-./pdns/version.hh
./pdns/webserver.cc
./pdns/webserver.hh
-./pdns/xpf.cc
-./pdns/xpf.hh
./pdns/zone2json.cc
./pdns/zone2ldap.cc
./pdns/zone2sql.cc
cp builder-support/dockerfiles/Dockerfile.target.debian-buster builder-support/dockerfiles/Dockerfile.target.debian-bookworm
```
-In the new `builder-support/dockerfiles/Dockerfile.target.debian-bookworm` file, replace every occurence of `debian-buster` by `debian-bookworm`, and of `debian:buster` by `debian:bookworm`
-
-Create symbolic links for the amd64 and arm64 versions:
-```
-ln -s builder-support/dockerfiles/Dockerfile.target.debian-bookworm builder-support/dockerfiles/Dockerfile.target.debian-bookworm-amd64
-ln -s builder-support/dockerfiles/Dockerfile.target.debian-bookworm builder-support/dockerfiles/Dockerfile.target.debian-bookworm-arm64
-```
+In the new `builder-support/dockerfiles/Dockerfile.target.debian-bookworm` file, replace every occurrence of `debian-buster` by `debian-bookworm`, and of `debian:buster` by `debian:bookworm`
Then add the new target to the list of OSes in the `.github/workflows/builder-dispatch.yml` workflow file:
```
* Every invocation of a program updates the `.gcda` files corresponding to the code that has been executed. It will append to existing `.gcda` files, but only process can update a given file so parallel execution will result in corrupted data.
* Writing to each `.gcda` might take a while for large programs, and has been known to slow down execution quite a lot.
* Accurate reporting of lines and branches may be problematic when optimizations are enabled, so it is advised to disable optimizations to get useful analysis.
-* Note that the `.gcda` files produced by `clang++` are not fully compatible with the `g++` ones, and with the existing tools, but [`llvm-cov gcov`](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) can produce `.gcov` files that should be compatible. A symptom of this incompatiblity looks like this:
+* Note that the `.gcda` files produced by `clang++` are not fully compatible with the `g++` ones, and with the existing tools, but [`llvm-cov gcov`](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) can produce `.gcov` files that should be compatible. A symptom of this incompatibility looks like this:
```
Processing pdns/ednssubnet.gcda
## Filing an Issue or Bug
**Note:** if you're planning to file a security bug, look at our
-[Security Policy](https://doc.powerdns.com/md/security/) first.
+[Security Policy](https://github.com/PowerDNS/pdns/security/policy) first.
When filing an issue or bug report, make the title of the issue a very short
summary (e.g. "Recursor crash when some-setting is set to 'crash'"). In the
And must:
* Be filed against the master branch before any release branch
-* Pass all tests in our CI (currently Github Actions and CircleCI)
+* Pass all tests in our CI (currently GitHub Actions and CircleCI)
Information on the tests can be found in the repository at
[/regression-tests/README.md](https://github.com/PowerDNS/pdns/blob/master/regression-tests/README.md)
1. Fix the warnings in a separate commit.
2. If fixing the warning would be too much trouble at this point in time, disabling the specific warning using the `// NOLINTNEXTLINE` or `// NOLINT` directives can be acceptable given the following is adhered to:
-Any added `// NOLINTNEXTLINE` or `// NOLINT` directive or others need to have a Github issue title, issue number and link next to them in the description along with the name or Github nickname of the person that wrote it. The Github issue must have an assignee and an accurate description of what needs to be done. As an example:
+Any added `// NOLINTNEXTLINE` or `// NOLINT` directive or others need to have a GitHub issue title, issue number and link next to them in the description along with the name or GitHub nickname of the person that wrote it. The GitHub issue must have an assignee and an accurate description of what needs to be done. As an example:
`// NOLINTNEXTLINE(<warning-name>) <issue-number> <issue-link> <person-name>: <issue-title> + a short comment if needed.`
# USAGE
-# docker build --build-arg MAKEFLAGS=-j8 -t recursor -f docker/Dockerfile-recursor .
+# docker build --build-arg MAKEFLAGS=-j8 -t recursor -f Dockerfile-recursor .
# docker run -p 1053:53 -p 1053:53/udp -ti --rm recursor
# dig a www.example.com @0 -p 1053
-PowerDNS and dnsdist Security Policy
+PowerDNS and DNSdist Security Policy
====================================
If you have a security problem to report, please email us at both peter.van.dijk@powerdns.com and remi.gacogne@powerdns.com.
Please do not mail security issues to public lists, nor file a ticket, unless we do not get back to you in a timely manner.
We fully credit reporters of security issues, and respond quickly, but please allow us a reasonable timeframe to coordinate a response.
-We remind PowerDNS and dnsdist users that under the terms of the GNU General Public License, PowerDNS and dnsdist come with ABSOLUTELY NO WARRANTY.
+We remind PowerDNS and DNSdist users that under the terms of the GNU General Public License, PowerDNS and DNSdist come with ABSOLUTELY NO WARRANTY.
This license is included in this documentation.
Yes We Hack
-----------
Security issues can also be reported on [our YesWeHack page](https://yeswehack.com/programs/powerdns) and might fetch a bounty.
-Do note that only the PowerDNS software (PowerDNS Authoritative Server, the PowerDNS Recursor and dnsdist) is in scope for the YesWeHack program, not our websites or other infrastructure.
+Do note that only the PowerDNS software (PowerDNS Authoritative Server, the PowerDNS Recursor and DNSdist) is in scope for the YesWeHack program, not our websites or other infrastructure.
Disclosure Policy
-----------------
This tool is mainly used internally to test releases but might be useful
for others.
+## Known Issues
+
+- `--test-aarch64` really only makes sense if the test script is running on
+ another platform (and so far we've assumed `x86_64` to be the default)
+
## Dependencies
- Python 3
# - `source venv/bin/activate`
# - `pip install --upgrade pip`
# - `pip install -r requirements.txt`
-# - `./generate-repo-files.py auth-41`
+# - `./generate-repo-files.py --test rec-51`
# Modules
# Globals
-g_version = '1.0.3'
+g_version = '1.0.4'
g_verbose = False
'test PowerDNS repositories.')
parser.add_argument('release', metavar='RELEASE',
choices=[# Authoritative Server
- 'auth-44', 'auth-45', 'auth-46', 'auth-47',
- 'auth-48', 'auth-master',
+ 'auth-47', 'auth-48', 'auth-49',
+ 'auth-master',
# Recursor
- 'rec-46', 'rec-47', 'rec-48', 'rec-49',
+ 'rec-48', 'rec-49', 'rec-50', 'rec-51',
'rec-master',
# DNSDist
- 'dnsdist-15', 'dnsdist-16', 'dnsdist-17',
- 'dnsdist-18', 'dnsdist-master'
- ],
+ 'dnsdist-17', 'dnsdist-18', 'dnsdist-19',
+ 'dnsdist-master'],
help='the release to generate Docker files for: ' +
'%(choices)s')
parser.add_argument('--run-output', action='store_true',
help='always show output from running a container')
parser.add_argument('--test', action='store_true',
help='test the release')
+ parser.add_argument('--test-aarch64', action='store_true',
+ help='test the release for ARM64')
parser.add_argument('--verbose', action='store_true',
help='verbose output')
parser.add_argument('--version', action='store_true',
os_image = os
if release.startswith('auth-'):
- if os in ('centos', 'el'):
+ if os in ('el'):
pkg = 'pdns'
else:
pkg = 'pdns-server'
def write_list_file (os, os_version, release):
tpl = g_env.get_template('pdns-list.jinja2')
- if os in ['debian', 'ubuntu']:
- arch = ' [arch=amd64] '
- else:
- arch = ' '
-
f = open('pdns.list.{}.{}-{}'.format(release, os, os_version), 'w')
f.write(tpl.render({ "os": os,
"os_version": os_version,
- "release": release,
- "arch": arch }))
+ "release": release }))
f.close()
if g_verbose:
print("Writing release files...")
- if release in ['auth-44', 'auth-45', 'auth-46', 'auth-47', 'auth-48',
- 'auth-master',
- 'rec-46', 'rec-47', 'rec-48', 'rec-49',
- 'rec-master',
- 'dnsdist-15', 'dnsdist-16', 'dnsdist-17', 'dnsdist-18',
- 'dnsdist-master']:
+ if release in ['auth-47', 'auth-48', 'auth-49', 'auth-master',
+ 'rec-48', 'rec-49', 'rec-50', 'rec-51', 'rec-master',
+ 'dnsdist-17', 'dnsdist-18', 'dnsdist-19', 'dnsdist-master']:
write_pkg_pin_file(release)
- write_dockerfile('centos', '7', release)
+ write_dockerfile('el', '7', release)
write_dockerfile('el', '8', release)
+ write_dockerfile('el', '9', release)
write_dockerfile('debian', 'buster', release)
write_list_file('debian', 'buster', release)
- write_dockerfile('ubuntu', 'focal', release)
- write_list_file('ubuntu', 'focal', release)
-
- if release in ['dnsdist-15']:
- write_dockerfile('raspbian', 'buster', release)
- write_list_file('raspbian', 'buster', release)
-
- if release in ['auth-46', 'auth-47', 'auth-48', 'auth-master',
- 'rec-46', 'rec-47', 'rec-48', 'rec-49', 'rec-master',
- 'dnsdist-16', 'dnsdist-17', 'dnsdist-18', 'dnsdist-master']:
write_dockerfile('debian', 'bullseye', release)
write_list_file('debian', 'bullseye', release)
-
- if release in ['auth-46', 'auth-47', 'auth-master',
- 'rec-46', 'rec-47', 'rec-48', 'rec-49', 'rec-master',
- 'dnsdist-15', 'dnsdist-16', 'dnsdist-17', 'dnsdist-master']:
- write_dockerfile('ubuntu', 'bionic', release)
- write_list_file('ubuntu', 'bionic', release)
-
- if release in ['auth-46', 'auth-47', 'auth-48', 'auth-master',
- 'rec-46', 'rec-47', 'rec-48', 'rec-49', 'rec-master',
- 'dnsdist-17', 'dnsdist-18', 'dnsdist-master']:
+ write_dockerfile('ubuntu', 'focal', release)
+ write_list_file('ubuntu', 'focal', release)
write_dockerfile('ubuntu', 'jammy', release)
write_list_file('ubuntu', 'jammy', release)
- if release in ['auth-47', 'auth-48', 'auth-master',
- 'rec-47', 'rec-48', 'rec-49', 'rec-master',
- 'dnsdist-17', 'dnsdist-18', 'dnsdist-master']:
- write_dockerfile('el', '9', release)
-
- if release in ['auth-48', 'auth-master']:
+ if release in ['auth-48', 'auth-49', 'auth-master',
+ 'rec-48', 'rec-49', 'rec-50', 'rec-51', 'rec-master',
+ 'dnsdist-19', 'dnsdist-master']:
write_dockerfile('debian', 'bookworm', release)
write_list_file('debian', 'bookworm', release)
+ if release in ['auth-49', 'auth-master',
+ 'rec-50', 'rec-51', 'rec-master',
+ 'dnsdist-19', 'dnsdist-master']:
+ write_dockerfile('ubuntu', 'noble', release)
+ write_list_file('ubuntu', 'noble', release)
+
# Test Release Functions
-def build (dockerfile):
+def build (dockerfile, arch='x86_64'):
# Maybe create `determine_tag` function.
if len(str(dockerfile)) <= len(g_dockerfile):
print('Unable to determine tag for {}'.format(dockerfile))
print('Building Docker image using {}...'.format(dockerfile))
if g_verbose:
print(' - tag = {}'.format(tag))
- cp = subprocess.run(['docker', 'build', '--no-cache', '--pull', '--file',
- dockerfile, '--tag', tag, '.'],
- capture_output=not(g_verbose))
+ if arch == 'x86_64':
+ cp = subprocess.run(['docker', 'build', '--no-cache', '--pull',
+ '--file', dockerfile, '--tag', tag, '.'],
+ capture_output=not(g_verbose))
+ # not very subtle
+ elif arch == 'aarch64':
+ cp = subprocess.run(['docker', 'build', '--platform', 'linux/arm64/v8',
+ '--no-cache', '--pull', '--file', dockerfile,
+ '--tag', tag, '.'],
+ capture_output=not(g_verbose))
# FIXME write failed output to log
if cp.returncode != 0:
print('Error building {}: {}'.format(tag, repr(cp.returncode)))
return ( tag, cp.returncode )
-def run (tag):
+def run (tag, arch='x86_64'):
if g_run_output:
capture_run_output = False
else:
capture_run_output = not(g_verbose)
print('Running Docker container tagged {}...'.format(tag))
- cp = subprocess.run(['docker', 'run', tag],
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
- version = re.search('(PowerDNS Authoritative Server|PowerDNS Recursor|' +
- 'dnsdist) (\d+\.\d+\.\d+(-\w+)?)',
+ if arch == 'x86_64':
+ cp = subprocess.run(['docker', 'run', tag],
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ # not very subtle
+ elif arch == 'aarch64':
+ cp = subprocess.run(['docker', 'run', '--platform', 'linux/arm64/v8',
+ tag],
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ version = re.search(r'(PowerDNS Authoritative Server|PowerDNS Recursor|' +
+ r'dnsdist) (\d+\.\d+\.\d+(-\w+)?)',
cp.stdout.decode())
if g_verbose:
print(cp.stdout.decode())
return files
-def test_release (release):
+def test_release (release, arch='x86_64'):
# sorted because we want determinism
dockerfiles = sorted(collect_dockerfiles(release))
failed_builds = []
failed_runs = []
returned_versions = []
- print('=== testing {} ==='.format(release))
+ print('=== testing {} ({}) ==='.format(release, arch))
for df in dockerfiles:
+ if arch == 'aarch64' and str(df).endswith('el-7'):
+ continue
+ if arch == 'aarch64' and not release in ['rec-49', 'rec-50', 'rec-51', 'rec-master',
+ 'dnsdist-19', 'dnsdist-master']:
+ continue
if g_verbose:
print('--- {} ---'.format(df))
- (tag, returncode) = build(df)
+ (tag, returncode) = build(df, arch)
if returncode != 0:
print('Skipping running {} due to build error: {}'
.format(df, returncode))
print('Skipping running {} due to undetermined tag.'.format(df))
failed_builds.append((str(df), returncode))
else:
- (returncode, return_version) = run(tag)
+ (returncode, return_version) = run(tag, arch)
# for some reason 99 is returned on `cmd --version` :shrug:
# (not sure if this is true since using `stdout=PIPE...`)
if returncode != 0 and returncode != 99:
if args.test:
test_release(args.release)
+
+if args.test_aarch64:
+ test_release(args.release, 'aarch64')
+++ /dev/null
-FROM {{ os_image }}:{{ os_version }}
-
-RUN yum install -y epel-release bind-utils
-
-{% if os_version == '7' %}
-RUN yum install -y yum-plugin-priorities
-{% endif %}
-
-{% if release == 'dnsdist-15' and os_version == '8' %}
-RUN dnf install -y 'dnf-command(config-manager)'
-RUN dnf config-manager --set-enabled powertools
-{% endif %}
-
-RUN curl -o /etc/yum.repos.d/powerdns-{{ release }}.repo https://repo.powerdns.com/repo-files/{{ os }}-{{ release }}.repo
-RUN yum install --assumeyes {%- if os_version == '8' %} --nobest{% endif %} {{ pkg }}
-
-{% if release.startswith('rec-') %}
-RUN mkdir /var/run/pdns-recursor
-{% endif %}
-
-CMD {{ cmd }} --version
-
FROM {{ os_image }}:{{ os_version }}
-{% if os_version == '8' or os_version == '9' %}
-RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ os_version }}.noarch.rpm bind-utils
-{% endif %}
-
-{% if os_version == '7' %}
-RUN yum install -y yum-plugin-priorities
-{% endif %}
+RUN yum install -y oracle-epel-release-el{{ os_version }} bind-utils
{% if release == 'dnsdist-15' and os_version == '8' %}
RUN dnf install -y 'dnf-command(config-manager)'
-deb {{- arch -}} http://repo.powerdns.com/{{ os }} {{ os_version }}-{{ release }} main
-
+deb http://repo.powerdns.com/{{ os }} {{ os_version }}-{{ release }} main
-Subproject commit 16bc1604c48821c12b708d7afa88d9612ebdd0da
+Subproject commit f2c8c68dccb142152d8e2120b29e597e24222ddc
--- /dev/null
+# must support Ubuntu focal, with dpkg 1.19.7
+# Enable the line below once we fully moved to YAML configuration
+#rm_conffile /etc/powerdns/recursor.lua 5.1~
+
--enable-dnstap \
--enable-nod
+# Stop installing the Lua config files once we fully moved to YAML configuration
override_dh_auto_install:
dh_auto_install
install -d debian/pdns-recursor/usr/share/pdns-recursor/lua-config
install -m 644 -t debian/pdns-recursor/usr/share/pdns-recursor/snmp RECURSOR-MIB.txt
rm -f debian/pdns-recursor/etc/powerdns/recursor.conf-dist
rm -f debian/pdns-recursor/etc/powerdns/recursor.yml-dist
- ./pdns_recursor --no-config --config=default | sed \
- -e 's!^# config-dir=.*!config-dir=/etc/powerdns!' \
- -e 's!^# hint-file=.*!&\nhint-file=/usr/share/dns/root.hints!' \
- -e 's!^# include-dir=.*!&\ninclude-dir=/etc/powerdns/recursor.d!' \
- -e 's!^# local-address=.*!local-address=127.0.0.1!' \
- -e 's!^# lua-config-file=.*!lua-config-file=/etc/powerdns/recursor.lua!' \
- -e 's!^# quiet=.*!quiet=yes!' \
- -e '/^# version-string=.*/d' \
- > debian/pdns-recursor/etc/powerdns/recursor.conf
+ @echo "\
+ dnssec:\n\
+ # validation: process # default\n\
+ trustanchorfile: /usr/share/dns/root.key\n\
+ recursor:\n\
+ hint_file: /usr/share/dns/root.hints\n\
+ include_dir: /etc/powerdns/recursor.d\n\
+ incoming:\n\
+ # listen:\n\
+ # - 127.0.0.1 # default\n\
+ outgoing:\n\
+ # source_address:\n\
+ # - 0.0.0.0 # default\n\
+ " > debian/pdns-recursor/etc/powerdns/recursor.conf
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
# This defines the distribution base layer
# Put only the bare minimum of common commands here, without dev tools
-@IF [ ${BUILDER_TARGET} = centos-7 -o ${BUILDER_TARGET} = el-7 ]
FROM centos:7 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = centos-7-amd64 -o ${BUILDER_TARGET} = el-7-amd64]
-FROM amd64/centos:7 as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
RUN touch /var/lib/rpm/* && yum install -y epel-release centos-release-scl-rh
+++ /dev/null
-Dockerfile.target.centos-7
\ No newline at end of file
+++ /dev/null
-# First do the source builds
-@INCLUDE Dockerfile.target.sdist
-
-# This defines the distribution base layer
-# Put only the bare minimum of common commands here, without dev tools
-@IF [ ${BUILDER_TARGET} = centos-8 ]
-FROM centos:8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = centos-8-stream ]
-FROM quay.io/centos/centos:stream8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = centos-8-amd64 ]
-FROM amd64/centos:8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = centos-8-arm64 ]
-FROM arm64v8/centos:8 as dist-base
-@ENDIF
-
-ARG BUILDER_CACHE_BUSTER=
-
-@IF [[ $BUILDER_TARGET = centos-*-stream ]]
-RUN touch /var/lib/rpm/* && dnf swap -y centos-linux-repos centos-stream-repos && dnf -y distro-sync
-@ENDIF
-
-RUN touch /var/lib/rpm/* && dnf install -y epel-release && \
- dnf install -y 'dnf-command(config-manager)' && \
- dnf config-manager --set-enabled powertools
-
-# Do the actual rpm build
-@INCLUDE Dockerfile.rpmbuild
-
-# Do a test install and verify
-# Can be skipped with skippackagetest=1 in the environment
-@EXEC [ "$skippackagetest" = "" ] && include Dockerfile.rpmtest
+++ /dev/null
-Dockerfile.target.centos-8
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.centos-8
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.centos-8
\ No newline at end of file
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = debian-bookworm ]
FROM debian:bookworm as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-bookworm-amd64 ]
-FROM amd64/debian:bookworm as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-bookworm-arm64 ]
-FROM arm64v8/debian:bookworm as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
+++ /dev/null
-Dockerfile.target.debian-bookworm
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.debian-bookworm
\ No newline at end of file
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = debian-bullseye ]
FROM debian:bullseye as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-bullseye-amd64 ]
-FROM amd64/debian:bullseye as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-bullseye-arm64 ]
-FROM arm64v8/debian:bullseye as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
+++ /dev/null
-Dockerfile.target.debian-bullseye
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.debian-bullseye
\ No newline at end of file
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = debian-buster ]
FROM debian:buster as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-buster-amd64 ]
-FROM amd64/debian:buster as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-buster-arm64 ]
-FROM arm64v8/debian:buster as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
+++ /dev/null
-Dockerfile.target.debian-buster
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.debian-buster
\ No newline at end of file
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = debian-trixie ]
FROM debian:trixie as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-trixie-amd64 ]
-FROM amd64/debian:trixie as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-trixie-arm64 ]
-FROM arm64v8/debian:trixie as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
+++ /dev/null
-Dockerfile.target.debian-trixie
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.debian-trixie
\ No newline at end of file
-Dockerfile.target.centos-7
\ No newline at end of file
+Dockerfile.target.oraclelinux-7
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.centos-7-amd64
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.oraclelinux-8-amd64
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.oraclelinux-8-arm64
\ No newline at end of file
# This defines the distribution base layer
# Put only the bare minimum of common commands here, without dev tools
-@IF [ ${BUILDER_TARGET} = oraclelinux-9 -o ${BUILDER_TARGET} = el-9 ]
FROM oraclelinux:9 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = oraclelinux-9-amd64 -o ${BUILDER_TARGET} = el-9-amd64 ]
-FROM amd64/oraclelinux:9 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = oraclelinux-9-arm64 -o ${BUILDER_TARGET} = el-9-arm64 ]
-FROM arm64v8/oraclelinux:9 as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
RUN touch /var/lib/rpm/* && dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm && \
+++ /dev/null
-Dockerfile.target.el-9
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.el-9
\ No newline at end of file
--- /dev/null
+# First do the source builds
+@INCLUDE Dockerfile.target.sdist
+
+# This defines the distribution base layer
+# Put only the bare minimum of common commands here, without dev tools
+FROM oraclelinux:7 as dist-base
+
+ARG BUILDER_CACHE_BUSTER=
+RUN touch /var/lib/rpm/* && yum install -y oracle-epel-release-el7 oracle-softwarecollection-release-el7 && \
+ yum-config-manager --add-repo=http://yum.oracle.com/repo/OracleLinux/OL7/optional/developer/$(uname -m)/ && \
+ yum install -y --nogpgcheck devtoolset-11-gcc-c++ scl-utils
+
+# Do the actual rpm build
+@INCLUDE Dockerfile.rpmbuild
+
+# Do a test install and verify
+# Can be skipped with skippackagetest=1 in the environment
+@EXEC [ "$skippackagetest" = "" ] && include Dockerfile.rpmtest
# This defines the distribution base layer
# Put only the bare minimum of common commands here, without dev tools
-@IF [ ${BUILDER_TARGET} = oraclelinux-8 -o ${BUILDER_TARGET} = el-8 ]
FROM oraclelinux:8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = oraclelinux-8-amd64 -o ${BUILDER_TARGET} = el-8-amd64 ]
-FROM amd64/oraclelinux:8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = oraclelinux-8-arm64 -o ${BUILDER_TARGET} = el-8-arm64 ]
-FROM arm64v8/oraclelinux:8 as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
RUN touch /var/lib/rpm/* && dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
+++ /dev/null
-Dockerfile.target.oraclelinux-8
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.oraclelinux-8
\ No newline at end of file
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = ubuntu-focal ]
FROM ubuntu:focal as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-focal-amd64 ]
-FROM amd64/ubuntu:focal as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-focal-arm64 ]
-FROM arm64v8/ubuntu:focal as dist-base
-@ENDIF
+
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
RUN apt-get update && apt-get -y dist-upgrade
+++ /dev/null
-Dockerfile.target.ubuntu-focal
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.ubuntu-focal
\ No newline at end of file
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = ubuntu-jammy ]
FROM ubuntu:jammy as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-jammy-amd64 ]
-FROM amd64/ubuntu:jammy as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-jammy-arm64 ]
-FROM arm64v8/ubuntu:jammy as dist-base
-@ENDIF
+
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
RUN apt-get update && apt-get -y dist-upgrade
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = ubuntu-lunar ]
FROM ubuntu:lunar as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-lunar-amd64 ]
-FROM amd64/ubuntu:lunar as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-lunar-arm64 ]
-FROM arm64v8/ubuntu:lunar as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
+++ /dev/null
-Dockerfile.target.ubuntu-lunar
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.ubuntu-lunar
\ No newline at end of file
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = ubuntu-mantic ]
FROM ubuntu:mantic as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-mantic-amd64 ]
-FROM amd64/ubuntu:mantic as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-mantic-arm64 ]
-FROM arm64v8/ubuntu:mantic as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
+++ /dev/null
-Dockerfile.target.ubuntu-mantic
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.ubuntu-mantic
\ No newline at end of file
# First do the source builds
@INCLUDE Dockerfile.target.sdist
-@IF [ ${BUILDER_TARGET} = ubuntu-noble ]
FROM ubuntu:noble as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-noble-amd64 ]
-FROM amd64/ubuntu:noble as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-noble-arm64 ]
-FROM arm64v8/ubuntu:noble as dist-base
-@ENDIF
ARG BUILDER_CACHE_BUSTER=
ARG APT_URL
+++ /dev/null
-Dockerfile.target.ubuntu-noble
\ No newline at end of file
+++ /dev/null
-Dockerfile.target.ubuntu-noble
\ No newline at end of file
component['version'] = (pkg.version if pkg.epoch == 0 else str(pkg.epoch) + ':' + pkg.version) + '-' + pkg.release
else:
component['version'] = (pkg.version if pkg.epoch == 0 else str(pkg.epoch) + ':' + pkg.version)
+ if hasattr(pkg, 'arch'):
+ component['version'] += '.' + pkg.arch
if hasattr(pkg, 'vendor') and pkg.vendor is not None:
component['supplier'] = {'name': pkg.vendor}
if hasattr(pkg, 'publisher') and pkg.publisher is not None:
appName = packageName
appInfos = getPackageInformations(pkgDB, packageName)
component = { 'name': appName, 'bom-ref': 'pkg:' + appName, 'type': 'application'}
- component['version'] = appInfos.version
+
+ if appInfos.release:
+ component['version'] = (appInfos.version if appInfos.epoch == 0 else str(appInfos.epoch) + ':' + appInfos.version) + '-' + appInfos.release
+ else:
+ component['version'] = (appInfos.version if appInfos.epoch == 0 else str(appInfos.epoch) + ':' + appInfos.version)
+
+ if hasattr(appInfos, 'arch'):
+ component['version'] += '.' + appInfos.arch
+
component['supplier'] = {'name': appInfos.vendor if appInfos.vendor != '<NULL>' else 'PowerDNS.COM BV', 'url': ['https://www.powerdns.com']}
component['licenses'] = [{'license': {'id': licenseToSPDXIdentifier(appInfos.license)}}]
depRelations['pkg:' + appName] = []
echo "${QUICHE_TARBALL_HASH}" "${QUICHE_TARBALL}" | sha256sum -c -
tar xf "${QUICHE_TARBALL}"
cd "quiche-${QUICHE_VERSION}"
+# Disable SONAME in the quiche shared library, we do not intend this library to be used by anyone else and it makes things more complicated since we rename it to libdnsdist-quiche
+sed -i 's/ffi = \["dep:cdylib-link-lines"\]/ffi = \[\]/' quiche/Cargo.toml
+sed -i 's,cdylib_link_lines::metabuild();,//cdylib_link_lines::metabuild();,' quiche/src/build.rs
RUST_BACKTRACE=1 cargo build --release --no-default-features --features ffi,boringssl-boring-crate --package quiche
install -m644 quiche/include/quiche.h "${INSTALL_PREFIX}"/include
{
- "version": "0.21.0",
+ "version": "0.22.0",
"license": "BSD-2-Clause",
"publisher": "https://github.com/cloudflare/quiche",
- "SHA256SUM": "ca0f953c34e1549930cfd44deac5e8a6d9e6c3c3df01e5a2d9bcf6d07246b6a4"
+ "SHA256SUM": "0af8744b07038ee4af8cdb94dd4c11f1a730001944a0ef2f3f03e63715b15268"
}
{
- "version": "1.75.0",
+ "version": "1.78.0",
"license": "MIT",
"publisher": "https://www.rust-lang.org/",
- "SHA256SUM_x86_64": "473978b6f8ff216389f9e89315211c6b683cf95a966196e7914b46e8cf0d74f6",
- "SHA256SUM_aarch64": "30828cd904fcfb47f1ac43627c7033c903889ea4aca538f53dcafbb3744a9a73"
+ "SHA256SUM_x86_64": "1377999f189d328ec183676c0e69f21af16e450f8d67f10d1f6cf746951a1d64",
+ "SHA256SUM_aarch64": "a76e6b659e9948f2bbd9d1c99b45348c3729bac7003d5f5b7fb5cacddb2bfcc1"
}
exit 1
fi
-for prog in pdns-recursor dnsdist pdns; do
+# pdns (auth) is handled seperately, it needs a special find condition which is hard to do with
+# vars, as we don't want the asterisks to expand prematurely. So repeat the body of the loop below
+# with a find condition for pdns to exclude accidentally matching pdns-recursor*.
+for prog in pdns-recursor dnsdist; do
if [ $(find ${SRCDIR}/dist -name "${prog}*" 2>/dev/null | wc -l) -ne 0 ]; then
dst=${DESTDIR}/${prog}/${BUILDER_VERSION}
mkdir -p ${dst}
cp ${BUILDER_TMP}/${BUILDER_VERSION}/sdist/${prog}*.tar.bz2 ${dst}
- if [ "${prog}" = "pdns" ]; then
- rm -f ${dst}/pdns-recursor*
- fi
tardirname=${prog}-${BUILDER_VERSION}-${BUILDER_TARGET}
"$tar" -cjf ${dst}/${tardirname}.tar.bz2 --transform="s,.*/,${tardirname}/,g" $(find ${SRCDIR} -type f)
fi
done
+prog=pdns
+if [ $(find ${SRCDIR}/dist -name 'pdns*' -a ! -name 'pdns-recursor*' 2>/dev/null | wc -l) -ne 0 ]; then
+ dst=${DESTDIR}/${prog}/${BUILDER_VERSION}
+ mkdir -p ${dst}
+ cp ${BUILDER_TMP}/${BUILDER_VERSION}/sdist/${prog}*.tar.bz2 ${dst}
+ tardirname=${prog}-${BUILDER_VERSION}-${BUILDER_TARGET}
+ "$tar" -cjf ${dst}/${tardirname}.tar.bz2 --transform="s,.*/,${tardirname}/,g" $(find ${SRCDIR} -type f)
+fi
BuildRequires: fstrm-devel
%systemd_requires
%endif
-%if 0%{?rhel} >= 8
+%if ( "%{_arch}" != "aarch64" && 0%{?rhel} >= 8 ) || ( "%{_arch}" == "aarch64" && 0%{?rhel} >= 9 )
BuildRequires: libbpf-devel
BuildRequires: libxdp-devel
%endif
%install
make install DESTDIR=%{buildroot}
-%{__mv} %{buildroot}%{_sysconfdir}/%{name}/recursor.conf{-dist,}
%{__mkdir} %{buildroot}%{_sysconfdir}/%{name}/recursor.d
# change user and group to pdns-recursor and add default include-dir
-sed -i \
- -e 's/# setuid=/setuid=pdns-recursor/' \
- -e 's/# setgid=/setgid=pdns-recursor/' \
- -e 's!# include-dir=.*!&\ninclude-dir=%{_sysconfdir}/%{name}/recursor.d!' \
- %{buildroot}%{_sysconfdir}/%{name}/recursor.conf
+cat << EOF > %{buildroot}%{_sysconfdir}/%{name}/recursor.conf
+dnssec:
+ # validation: process
+recursor:
+ include_dir: %{_sysconfdir}/%{name}/recursor.d
+ setuid: pdns-recursor
+ setgid: pdns-recursor
+incoming:
+ # listen:
+ # - 127.0.0.1
+outgoing:
+ # source_address:
+ # - 0.0.0.0
+EOF
%{__install } -d %{buildroot}/%{_sharedstatedir}/%{name}
PDNS_CHECK_RAGEL([pdns/dnslabeltext.cc], [www.powerdns.com])
PDNS_CHECK_CLOCK_GETTIME
-BOOST_REQUIRE([1.42])
-# Boost accumulators, as used by dnsbulktest and dnstcpbench, need 1.48+
-# to be compatible with C++11
-AM_CONDITIONAL([HAVE_BOOST_GE_148], [test "$boost_major_version" -ge 148])
-AS_IF([test "$boost_major_version" -ge 148], [
- AC_DEFINE(HAVE_BOOST_GE_148, [1], [Define to 1 if you have boost >= 1.48])
-])
+BOOST_REQUIRE([1.54])
BOOST_PROGRAM_OPTIONS([mt])
AS_IF([test "$boost_cv_lib_program_options" = "no"], [
CFLAGS="$PIE_CFLAGS $CFLAGS"
CXXFLAGS="$PIE_CFLAGS $CXXFLAGS"
-PROGRAM_LDFLAGS="$PIE_LDFLAGS $PROGRAM_LDFLAGS"
AS_IF([test "$ax_cxx_cv_filesystem_lib" != "none"],
- [PROGRAM_LDFLAGS="$PROGRAM_LDFLAGS -l$ax_cxx_cv_filesystem_lib"],
+ [CXXFS_LIBS="-l$ax_cxx_cv_filesystem_lib"],
[]
)
+AC_SUBST([CXXFS_LIBS])
+PROGRAM_LDFLAGS="$PIE_LDFLAGS $PROGRAM_LDFLAGS $CXXFS_LIBS"
AC_SUBST([PROGRAM_LDFLAGS])
PDNS_ENABLE_COVERAGE
if response.HasField('queryTimeSec'):
datestr = datetime.datetime.fromtimestamp(response.queryTimeSec).strftime('%Y-%m-%d %H:%M:%S')
if response.HasField('queryTimeUsec'):
- datestr = datestr + '.' + str(response.queryTimeUsec)
+ datestr = datestr + '.' + ("%06d" % response.queryTimeUsec)
print("- Query time: %s" % (datestr))
policystr = ''
for rr in response.rrs:
rrclass = 1
rdatastr = ''
- rrudr = 0
+ rrudr = 'N/A'
if rr.HasField('class'):
rrclass = getattr(rr, 'class')
rrtype = rr.type
if rr.HasField('udr'):
- rrudr = rr.udr
+ rrudr = str(rr.udr)
if (rrclass == 1 or rrclass == 255) and rr.HasField('rdata'):
if rrtype == 1:
rdatastr = socket.inet_ntop(socket.AF_INET, rr.rdata)
elif rrtype == 28:
rdatastr = socket.inet_ntop(socket.AF_INET6, rr.rdata)
- print("\t - %d, %d, %s, %d, %s, %d" % (rrclass,
+ print("\t - %d, %d, %s, %d, %s, %s" % (rrclass,
rrtype,
rr.name,
rr.ttl,
def printSummary(self, msg, typestr):
datestr = datetime.datetime.fromtimestamp(msg.timeSec).strftime('%Y-%m-%d %H:%M:%S')
if msg.HasField('timeUsec'):
- datestr = datestr + '.' + str(msg.timeUsec)
+ datestr = datestr + '.' + ("%06d" % msg.timeUsec)
ipfromstr = 'N/A'
iptostr = 'N/A'
toportstr = ''
if msg.HasField('requestorId'):
requestorId = msg.requestorId
- nod = 0
+ nod = 'N/A';
if msg.HasField('newlyObservedDomain'):
- nod = msg.newlyObservedDomain
+ nod = str(msg.newlyObservedDomain)
+
+ workerId = 'N/A'
+ if msg.HasField('workerId'):
+ workerId = str(msg.workerId)
+
+ pcCacheHit = 'N/A'
+ if msg.HasField('packetCacheHit'):
+ pcCacheHit = str(msg.packetCacheHit)
+
+ outgoingQs = 'N/A'
+ if msg.HasField('outgoingQueries'):
+ outgoingQs = str(msg.outgoingQueries)
print('[%s] %s of size %d: %s%s%s -> %s%s(%s) id: %d uuid: %s%s '
- 'requestorid: %s deviceid: %s devicename: %s serverid: %s nod: %d' % (datestr,
+ 'requestorid: %s deviceid: %s devicename: %s serverid: %s nod: %s workerId: %s pcCacheHit: %s outgoingQueries: %s' % (datestr,
typestr,
msg.inBytes,
ipfromstr,
deviceId,
deviceName,
serveridstr,
- nod))
+ nod,
+ workerId,
+ pcCacheHit,
+ outgoingQs))
for mt in msg.meta:
values = ''
for entry in mt.value.intVal:
values = ', '.join([values, str(entry)]) if values != '' else str(entry)
- print('- %s -> %s' % (mt.key, values))
+ print('- (meta) %s -> %s' % (mt.key, values))
def getRequestorSubnet(self, msg):
requestorstr = None
'list-autoprimaries:List all autoprimaries'
'add-zone-key:Add a ZSK or KSK to zone and specify algo&bits'
'backend-cmd:Perform one or more backend commands'
+ 'backend-lookup:Perform a backend record lookup'
'b2b-migrate:Move all data from one backend to another'
'bench-db:Bench database backend with queries, one zone per line'
'check-zone:Check a zone for correctness'
_pdnsutil_helper_local_() {
local cur prev cmd
- local _PDNSUTIL_ALL_CMDS="activate-tsig-key activate-zone-key add-record add-supermaster add-zone-key backend-cmd b2b-migrate bench-db change-slave-zone-master
+ local _PDNSUTIL_ALL_CMDS="activate-tsig-key activate-zone-key add-record add-supermaster add-zone-key backend-cmd backend-lookup b2b-migrate bench-db change-slave-zone-master
check-zone check-all-zones clear-zone create-bind-db create-slave-zone create-zone deactivate-tsig-key deactivate-zone-key delete-rrset
delete-tsig-key delete-zone disable-dnssec edit-zone export-zone-dnskey export-zone-key generate-tsig-key generate-zone-key get-meta
hash-zone-record increase-serial import-tsig-key import-zone-key load-zone list-algorithms list-keys list-zone list-all-zones
except KeyboardInterrupt:
pass
-for item in v4filter.items():
- print(f"{str(netaddr.IPAddress(item[0].value))} ({ACTIONS[item[1].action]}): {item[1].counter}")
-for item in v6filter.items():
- print(f"{str(socket.inet_ntop(socket.AF_INET6, item[0]))} ({ACTIONS[item[1].action]}): {item[1].counter}")
-for item in cidr4filter.items():
- addr = netaddr.IPAddress(socket.ntohl(item[0].addr))
- print(f"{str(addr)}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
-for item in cidr6filter.items():
- print(f"{str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
-for item in qnamefilter.items():
- print(f"{''.join(map(chr, item[0].qname)).strip()}/{INV_QTYPES[item[0].qtype]} ({ACTIONS[item[1].action]}): {item[1].counter}")
+if v4filter or v6filter or cidr4filter or cidr6filter:
+ print("Blocked networks:")
+ for item in v4filter.items():
+ print(f"- {str(netaddr.IPAddress(item[0].value))} ({ACTIONS[item[1].action]}): {item[1].counter}")
+ for item in v6filter.items():
+ print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0]))} ({ACTIONS[item[1].action]}): {item[1].counter}")
+ for item in cidr4filter.items():
+ addr = netaddr.IPAddress(socket.ntohl(item[0].addr))
+ print(f"- {str(addr)}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
+ for item in cidr6filter.items():
+ print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
+
+if qnamefilter:
+ print("Blocked query names:")
+ for item in qnamefilter.items():
+ print(f"- {''.join(map(chr, item[0].qname)).strip()}/{INV_QTYPES[item[0].qtype]} ({ACTIONS[item[1].action]}): {item[1].counter}")
+
+if parameters.xsk and xskDestinations:
+ print("Content of the AF_XDP (XSK) routing map:")
+ for item in xskDestinations.items():
+ print(f"- {str(netaddr.IPAddress(socket.ntohl(item[0].addr)))}:{str(socket.ntohs(item[0].port))}")
xdp.remove_xdp(parameters.interface, 0)
-local-address=0.0.0.0,::
-include-dir=/etc/powerdns/recursor.d
+recursor:
+ include_dir: /etc/powerdns/recursor.d
+
+incoming:
+ listen:
+ - 0.0.0.0
+ - '::'
+
dnsbulktest.1 \
dnstcpbench.1
-if HAVE_BOOST_GE_148
MANPAGES_INSTALL += dnsbulktest.1 \
dnstcpbench.1
-endif
if TOOLS
MANPAGES_INSTALL += $(MANPAGES_TARGET_TOOLS)
By default, the PowerDNS Authoritative Server requires the following libraries and headers:
-* `Boost <http://boost.org/>`_ 1.35 or newer
+* `Boost <http://boost.org/>`_ 1.54 or newer
* `OpenSSL <https://openssl.org>`_
To build from a Git repository clone, the following dependencies are also required:
-Generic MySQL backend
-=====================
+Generic MySQL/MariaDB backend
+==============================
* Native: Yes
* Master: Yes
zone transfer fails.
.. warning::
- While it is possible to run the Generic MySQL backend on top of MySQL
+ While it is possible to run the Generic MySQL/MariaDB backend on top of MySQL/MariaDB
views, we have received several reports of this causing performance
problems and memory leaks. Please know that when reporting problems when
running PowerDNS on top of a modified schema, our open source support
.. literalinclude:: ../../modules/gmysqlbackend/enable-foreign-keys.mysql.sql
:language: SQL
-Using MySQL replication
------------------------
+Using MySQL/MariaDB replication
+-------------------------------
-To support ``NATIVE`` domains, the ``binlog_format`` for the MySQL
+To support ``NATIVE`` domains, the ``binlog_format`` for the MySQL/MariaDB
replication **must** be set to ``MIXED`` or ``ROW`` to prevent
differences in data between replicated servers. See `"Setting
The Binary Log
Format" <http://dev.mysql.com/doc/refman/5.7/en/binary-log-setting.html>`__
+and `"Binary Log Formats" <https://mariadb.com/kb/en/binary-log-formats/>`__
for more information.
Otherwise, you will probably see:
+================================================+========+=========+===========+==========+==========+==============+==================================+=================================+==============+
| :doc:`BIND <bind>` | Yes | Yes | Yes | No | No | Yes | No | Yes | ``bind`` |
+------------------------------------------------+--------+---------+-----------+----------+----------+--------------+----------------------------------+---------------------------------+--------------+
-| :doc:`Generic Mysql <generic-mysql>` | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ``gmysql`` |
+| :doc:`Generic Mysql/Mariadb <generic-mysql>` | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ``gmysql`` |
+------------------------------------------------+--------+---------+-----------+----------+----------+--------------+----------------------------------+---------------------------------+--------------+
| :doc:`Generic ODBC <generic-odbc>` | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ``godbc`` |
+------------------------------------------------+--------+---------+-----------+----------+----------+--------------+----------------------------------+---------------------------------+--------------+
- ``simple``: Search the requested domain by comparing the
associatedDomain attributes with the domain string in the question.
-- ``tree``: Search entires by translating the domain string into a LDAP
+- ``tree``: Search entries by translating the domain string into a LDAP
dn. Your LDAP tree must be designed in the same way as the DNS LDAP
tree. The question for "myhost.linuxnetworks.de" would translate into
"dc=myhost,dc=linuxnetworks,dc=de,ou=hosts=..." and the entry where
:pullreq: 6555
:tickets: 6396
- Report unparseable data in stoul invalid_argument exception
+ Report unparsable data in stoul invalid_argument exception
.. change::
:tags: Improvements
:tags: Bug Fixes
:pullreq: 6396
- Report unparseable data in stoul ``invalid_argument`` exception.
+ Report unparsable data in stoul ``invalid_argument`` exception.
.. change::
:tags: New Features, Tools
Changelogs for 4.9.x
====================
+.. changelog::
+ :version: 4.9.1
+ :released: 28th of May 2024
+
+ This is release 4.9.1 of the Authoritative Server.
+
+ Please review the :doc:`Upgrade Notes <../upgrading>` before upgrading from versions < 4.9.x.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14253
+
+ autoconf: allow prerelease systemd versions (Chris Hofstaedtler)
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14251
+
+ ixfrdist: Fix broken 'uid' and 'gid' parsing for non-numerical values
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14229
+
+ YaHTTP: Enforce max # of request fields and max request line size
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14188
+
+ rpm: Change home directory to /var/lib/pdns
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14199
+
+ Fix memory leaks in the bind file format parser
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14186
+
+ dnsproxy: fix build on s390x (Chris Hofstaedtler)
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14191
+
+ m4: Add option for 64-bit time_t on 32-bit systems with glibc-2.34 (Sven Wegener)
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14189
+
+ pdnsutil check-zone: accept LUA A/AAAA as SVCB address targets
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14190
+
+ Properly finalize PKCS11 modules before releasing them (Aki Tuomi)
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14187
+
+ Wrap backend factories in smart pointers
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14058
+
+ don't crash when a catalog SOA is invalid
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14126
+
+ (optionally) drop whitespace on join
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13929
+
+ debian: adjust option name in shipped postinst
+
.. changelog::
:version: 4.9.0
:released: 15th of March 2024
parameters for pdnssec.
- `commit 2f2b014 <https://github.com/PowerDNS/pdns/commit/2f2b014>`__:
apply variant of code in `ticket
- 714 <https://github.com/PowerDNS/pdns/issues/714>`__ so we can lauch
+ 714 <https://github.com/PowerDNS/pdns/issues/714>`__ so we can launch
pipe backend scripts with parameters, plus add experimental code that
if pipe-command is a unix domain socket, we use that.
- `commit 9566683 <https://github.com/PowerDNS/pdns/commit/9566683>`__:
fact only made things worse.
- LDAP backend updates from its author Norbert Sendetzky. Reverse
lookups should work now too.
-- An error message about unparseable packets did not include the
+- An error message about unparsable packets did not include the
originating IP address (fixed by Mark Bergsma)
- PowerDNS can now be started via path resolution while running with a
guardian. Suggested by Maurice Nonnekes.
# Install some stuff into the venv.
requirements_file = source_root.joinpath(args.requirements_file)
pip = venv_directory.joinpath("bin").joinpath("pip")
- subprocess.run([pip, "install", "-U", "pip", "setuptools-git", "wheel"])
+ subprocess.run([pip, "install", "-U", "pip", "setuptools", "wheel"])
subprocess.run([pip, "install", "-r", requirements_file])
# Run sphinx to generate the man-pages.
* :ref:`setting-webserver-port`: Port to bind the webserver to.
* :ref:`setting-webserver-allow-from`: Netmasks that are allowed to connect to the webserver
* :ref:`setting-webserver-max-bodysize`: Maximum request/response body size in megabytes
+* :ref:`setting-webserver-connection-timeout`: Request/response timeout in seconds
Metrics Endpoint
records.
These records contain small snippets of configuration that enable dynamic
-behaviour based on requester IP address, requester's EDNS Client Subnet,
+behaviour based on requestor IP address, requestor's EDNS Client Subnet,
server availability or other factors.
Capabilities range from very simple to highly advanced multi-pool
interoperability, and strive to turn this functionality into a broadly
supported standard.
-To enable this feature, either set `:ref:`setting-enable-lua-records` in the configuration,
+To enable this feature, either set :ref:`setting-enable-lua-records` in the configuration,
or set the ``ENABLE-LUA-RECORDS`` per-zone metadata item to ``1``.
In addition, to benefit from the geographical features, make sure the PowerDNS
www IN LUA A "pickclosest({'192.0.2.1','192.0.2.2','198.51.100.1'})"
This uses the GeoIP backend to find indications of the geographical location of
-the requester and the listed IP addresses. It will return with one of the closest
+the requestor and the listed IP addresses. It will return with one of the closest
addresses.
:func:`pickclosest` and :func:`ifportup` can be combined as follows::
Advanced topics
---------------
-By default, LUA records are executed with ``return `` prefixed to them. This saves
-a lot of typing for common cases. To run actual Lua scripts, start a record with a ``;``
-which indicates no ``return `` should be prepended.
+
+By default, LUA records are executed as if they were the argument to Lua's ``return`` statement.
+This saves a lot of typing for common cases.
+To run actual Lua scripts, start a record with a semicolon (``;``). You need to add your own ``return`` statement.
To keep records more concise and readable, configuration can be stored in
separate records. The full example from above can also be written as::
Send a text command to a backend for execution. GSQL backends will
take SQL commands, other backends may take different things. Be
careful!
+backend-lookup *BACKEND* *NAME* [*TYPE* [*CLIENT-IP-SUBNET*]]
+ Perform a backend record lookup.
bench-db [*FILE*]
Perform a benchmark of the backend-database.
*FILE* can be a file with a list, one per line, of zone names to use for this.
``/etc`` and ``/home``, possibly being unable to write AXFR'd zones.
PowerDNS also reacts to notifies by immediately checking if the zone has
-updated and if so, retransfering it.
+updated and if so, retransferring it.
All backends which implement this feature must make sure that they can
handle transactions so as to not leave the zone in a half updated state.
the value of the :ref:`stat-qsize-q` variable. This represents the number of
packets waiting for database attention. During normal operations the
queue should be small.
+This number is a total over all receiver threads.
+
+The :ref:`setting-max-queue-length` and :ref:`setting-overload-queue-length` settings determine how PowerDNS deals with growing queues.
+If the queue for a single receiver thread (and its associated distributor threads) grows beyond the ``overload`` number, queries are answered only from the packet cache so the database can hopefully recover.
+If we reach the ``max`` number, we consider the situation hopeless and respawn the server process.
The value of :ref:`setting-queue-limit` should be set to only keep queries in
queue for as long as someone would be interested in knowing the answer. Many
qsize-q
^^^^^^^
-Number of packets waiting for database attention, only available if :ref:`setting-receiver-threads` > 1
+Number of packets waiting for database attention, only available if :ref:`setting-distributor-threads` > 1
.. _stat-query-cache-hit:
docutils!=0.15,<0.18
jinja2<3.1.0
pyyaml==6.0.1
-packaging==24.0
+packaging==24.1
setuptools-scm==8.0.3 # setup-requires for sphinxcontrib-openapi
-pbr # setup-requires for sphinxcontrib-fulltoc
+pbr==6.1.0 # setup-requires for sphinxcontrib-fulltoc
#
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --generate-hashes requirements.in
--hash=sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610 \
--hash=sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455
# via sphinx
-certifi==2023.7.22 \
- --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
- --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+certifi==2024.7.4 \
+ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
+ --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
# via requests
changelog==0.5.8 \
--hash=sha256:43b21840874130666b7534b76b402bbb914f8c9c413d5ea9d45850ca4767dafb \
--hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
--hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2
# via jinja2
-packaging==24.0 \
- --hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
- --hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
+packaging==24.1 \
+ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
+ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
# via
# -r requirements.in
# setuptools-scm
# sphinx
-pbr==6.0.0 \
- --hash=sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda \
- --hash=sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9
+pbr==6.1.0 \
+ --hash=sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24 \
+ --hash=sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a
# via -r requirements.in
pygments==2.15.1 \
--hash=sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c \
--hash=sha256:4edf0223a0685a7c485ae5a156b6f529ba1ee481a1417817935b20bde1956232 \
--hash=sha256:6fc9287dfc823fe9aa432463edd6cea47fa9ebbf488d7f289b322ffcfca075c7
# via sphinx
-tomli==2.0.1 \
- --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
- --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
- # via setuptools-scm
-typing-extensions==4.11.0 \
- --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \
- --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a
- # via setuptools-scm
-urllib3==2.0.7 \
- --hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \
- --hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e
+urllib3==2.2.2 \
+ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
+ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
# via requests
# WARNING: The following packages were not pinned, but pip requires them to be
-@ 86400 IN SOA pdns-public-ns1.powerdns.com. peter\.van\.dijk.powerdns.com. 2024051501 10800 3600 604800 10800
+@ 86400 IN SOA pdns-public-ns1.powerdns.com. peter\.van\.dijk.powerdns.com. 2024092001 10800 3600 604800 10800
@ 3600 IN NS pdns-public-ns1.powerdns.com.
@ 3600 IN NS pdns-public-ns2.powerdns.com.
auth-4.9.0-alpha1.security-status 60 IN TXT "2 Unsupported pre-release (no known vulnerabilities)"
auth-4.9.0-beta2.security-status 60 IN TXT "2 Unsupported pre-release (no known vulnerabilities)"
auth-4.9.0.security-status 60 IN TXT "1 OK"
+auth-4.9.1.security-status 60 IN TXT "1 OK"
; Auth Debian
auth-3.4.1-2.debian.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2015-01/ and https://doc.powerdns.com/3/security/powerdns-advisory-2015-02/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-03/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-04/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-05/"
recursor-4.9.4.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2024-02.html"
recursor-4.9.5.security-status 60 IN TXT "1 OK"
recursor-4.9.6.security-status 60 IN TXT "1 OK"
+recursor-4.9.7.security-status 60 IN TXT "1 OK"
+recursor-4.9.8.security-status 60 IN TXT "1 OK"
recursor-5.0.0-alpha1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-5.0.0-alpha2.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-5.0.0-beta1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-5.0.3.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2024-02.html"
recursor-5.0.4.security-status 60 IN TXT "1 OK"
recursor-5.0.5.security-status 60 IN TXT "1 OK"
-recursor-5.1.0-alpha1.security-status 60 IN TXT "1 OK"
+recursor-5.0.6.security-status 60 IN TXT "1 OK"
+recursor-5.0.7.security-status 60 IN TXT "1 OK"
+recursor-5.0.8.security-status 60 IN TXT "1 OK"
+recursor-5.1.0-alpha1.security-status 60 IN TXT "2 Superseded pre-release"
+recursor-5.1.0-beta1.security-status 60 IN TXT "2 Superseded pre-release"
+recursor-5.1.0-rc1.security-status 60 IN TXT "2 Superseded pre-release"
+recursor-5.1.0.security-status 60 IN TXT "1 OK"
+recursor-5.1.1.security-status 60 IN TXT "1 OK"
; Recursor Debian
recursor-3.6.2-2.debian.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2015-01/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/"
dnsdist-1.8.1.security-status 60 IN TXT "3 Upgrade now, see https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"
dnsdist-1.8.2.security-status 60 IN TXT "1 OK"
dnsdist-1.8.3.security-status 60 IN TXT "1 OK"
+dnsdist-1.8.4.security-status 60 IN TXT "1 OK"
dnsdist-1.9.0-alpha1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
dnsdist-1.9.0-alpha2.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
dnsdist-1.9.0-alpha3.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
dnsdist-1.9.2.security-status 60 IN TXT "3 Upgrade now, see https://dnsdist.org/security-advisories/powerdns-advisory-for-dnsdist-2024-03.html"
dnsdist-1.9.3.security-status 60 IN TXT "3 Upgrade now, see https://dnsdist.org/security-advisories/powerdns-advisory-for-dnsdist-2024-03.html"
dnsdist-1.9.4.security-status 60 IN TXT "1 OK"
+dnsdist-1.9.5.security-status 60 IN TXT "1 OK"
+dnsdist-1.9.6.security-status 60 IN TXT "1 OK"
.. deprecated:: 4.5.0
Renamed to :ref:`setting-allow-unsigned-autoprimary`.
+ Removed in 4.9.0
.. _setting-also-notify:
If this is turned off, DNAME records are treated as any other and served
only when queried explicitly.
+.. _setting-dnsproxy-udp-port-range:
+
+``dnsproxy-udp-port-range``
+---------------------------
+
+- String
+- Default: `10000 60000`
+
+If :ref:`setting-resolver` enables the DNS Proxy, this setting limits the
+port range the DNS Proxy's UDP port is chosen from.
+
+Default should be fine on most installs, but if you have conflicting local
+services, you may choose to limit the range.
+
.. _setting-dnssec-key-cache-ttl:
``dnssec-key-cache-ttl``
Amount of time (in seconds) a pre-computed hash entry will be considered as expired when unused. See :func:`pickchashed()`.
+.. _setting-lua-global-include-dir:
+
+``lua-global-include-dir``
+---------------------------
+
+- String
+- Default: empty
+- Example: ``/etc/pdns/lua-global/``
+
+When creating a Lua context, scan this directory for additional lua files. All files that end with
+.lua are loaded in order using ``POSIX`` as locale with Lua scripts.
+
.. _setting-lua-health-checks-expire-delay:
``lua-health-checks-expire-delay``
.. deprecated:: 4.5.0
Renamed to :ref:`setting-primary`.
+ Removed in 4.9.0.
- Boolean
- Default: no
- Default: 5000
If this many packets are waiting for database attention, consider the
-situation hopeless and respawn.
+situation hopeless and respawn the server process.
+This limit is per receiver thread.
.. _setting-max-signature-cache-entries:
If this many packets are waiting for database attention, answer any new
questions strictly from the packet cache. Packets not in the cache will
-be dropped, and :ref:`_stat-overload-drops` will be incremented.
+be dropped, and :ref:`stat-overload-drops` will be incremented.
.. _setting-prevent-self-notification:
Recursive DNS server to use for ALIAS lookups and the internal stub resolver. Only one address can be given.
+It is assumed that the specified recursive DNS server, and the network path to it, are trusted.
+
Examples::
resolver=127.0.0.1
.. deprecated:: 4.5.0
Renamed to :ref:`setting-secondary`.
+ Removed in 4.9.0.
.. _setting-slave-cycle-interval:
.. deprecated:: 4.5.0
Renamed to :ref:`setting-xfr-cycle-interval`.
+ Removed in 4.9.0.
.. _setting-slave-renotify:
.. deprecated:: 4.5.0
Renamed to :ref:`setting-secondary-do-renotify`.
+ Removed in 4.9.0.
- Boolean
- Default: no
.. deprecated:: 4.5.0
Renamed to :ref:`setting-autosecondary`.
+ Removed in 4.9.0.
- Boolean
- Default: no
The value between the hooks is a UUID that is generated for each request. This can be used to find all lines related to a single request.
.. note::
- The webserver logs these line on the NOTICE level. The :ref:`setting-loglevel` seting must be 5 or higher for these lines to end up in the log.
+ The webserver logs these line on the NOTICE level. The :ref:`setting-loglevel` setting must be 5 or higher for these lines to end up in the log.
.. _setting-webserver-max-bodysize:
Maximum request/response body size in megabytes.
+.. _setting-webserver-connection-timeout:
+
+``webserver-connection-timeout``
+--------------------------------
+.. versionadded:: 4.8.5
+
+- Integer
+- Default: 5
+
+Request/response timeout in seconds.
+
.. _setting-webserver-password:
``webserver-password``
Default of no implies the pre-4.8 behaviour of up to 100 RRs per AXFR chunk.
-If enabled, only a single RR will be put into each AXFR chunk, making some zones transferable when they were not.
+If enabled, only a single RR will be put into each AXFR chunk, making some zones transferable when they were not otherwise.
.. _setting-xfr-cycle-interval:
upgrade notes if your version is older than 3.4.2.
4.9.0 to 5.0.0/master
---------------
+---------------------
LUA records whitespace insertion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#include "json11.hpp"
#include <cassert>
#include <cmath>
+#include <cstdint>
#include <cstdlib>
#include <cstdio>
#include <limits>
unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
{
auto cursor = txn->getRWCursor(dbi);
- MDBOutVal maxidval, maxcontent;
+ MDBOutVal maxidval{};
+ MDBOutVal maxcontent{};
unsigned int maxid{0};
- if(!cursor.get(maxidval, maxcontent, MDB_LAST)) {
+ if (cursor.get(maxidval, maxcontent, MDB_LAST) == 0) {
maxid = maxidval.getNoStripHeader<unsigned int>();
}
return maxid;
unsigned int MDBGetRandomID(MDBRWTransaction& txn, MDBDbi& dbi)
{
auto cursor = txn->getRWCursor(dbi);
- unsigned int id;
- for(int attempts=0; attempts<20; attempts++) {
- MDBOutVal key, content;
+ unsigned int newID = 0;
+ for (int attempts = 0; attempts < 20; attempts++) {
+ MDBOutVal key{};
+ MDBOutVal content{};
// dns_random generates a random number in [0..signed_int_max-1]. We add 1 to avoid 0 and allow type_max.
// 0 is avoided because the put() interface uses it to mean "please allocate a number for me"
- id = dns_random(std::numeric_limits<signed int>::max()) + 1;
- if(cursor.find(MDBInVal(id), key, content)) {
- return id;
+ newID = dns_random(std::numeric_limits<signed int>::max()) + 1;
+ if (cursor.find(MDBInVal(newID), key, content) != 0) {
+ return newID;
}
}
throw std::runtime_error("MDBGetRandomID() could not assign an unused random ID");
#pragma once
+
#include <stdexcept>
#include <string_view>
+#include <sstream>
#include <iostream>
-#include "lmdb-safe.hh"
+
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
-#include <sstream>
-// using std::cout;
-// using std::endl;
+#include "lmdb-safe.hh"
/*
- Open issues:
-
- Everything should go into a namespace
- What is an error? What is an exception?
- could id=0 be magic? ('no such id')
- yes
- Is boost the best serializer?
- good default
- Perhaps use the separate index concept from multi_index
- perhaps get eiter to be of same type so for(auto& a : x) works
- make it more value "like" with unique_ptr
-*/
-
-
-/** Return the highest ID used in a database. Returns 0 for an empty DB.
- This makes us start everything at ID=1, which might make it possible to
- treat id 0 as special
-*/
+ * OPEN ISSUES:
+ *
+ * - Everything should go into a namespace.
+ * - Decide on what is an error and what is an exception.
+ * - Could id=0 be magic? (e.g. 'no such id') - yes.
+ * - Is boost the best serializer? It's a good default.
+ * - Perhaps use the separate index concept from multi_index.
+ * - Perhaps get eiter to be of same type so that for(auto& a : x) works.
+ * - Make it more value-like with unique_ptr.
+ */
+
+/**
+ * LMDB ID Vector Type.
+ */
+typedef std::vector<uint32_t> LmdbIdVec;
+
+/**
+ * Return the highest ID used in a database. Returns 0 for an empty DB. This makes us
+ * start everything at ID=1, which might make it possible to treat id 0 as special.
+ */
unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi);
-/** Return a randomly generated ID that is unique and not zero.
- May throw if the database is very full.
-*/
+/**
+ * Return a randomly generated ID that is unique and not zero. May throw if the database
+ * is very full.
+ */
unsigned int MDBGetRandomID(MDBRWTransaction& txn, MDBDbi& dbi);
-typedef std::vector<uint32_t> LMDBIDvec;
-
-/** This is our serialization interface.
- You can define your own serToString for your type if you know better
-*/
-template<typename T>
-std::string serToString(const T& t)
+/**
+ * This is our serialization interface. It can be specialized for other types.
+ */
+template <typename T>
+std::string serializeToBuffer(const T& value)
{
- std::string serial_str;
- boost::iostreams::back_insert_device<std::string> inserter(serial_str);
- boost::iostreams::stream<boost::iostreams::back_insert_device<std::string> > s(inserter);
- boost::archive::binary_oarchive oa(s, boost::archive::no_header | boost::archive::no_codecvt);
-
- oa << t;
- return serial_str;
+ std::string buffer;
+ boost::iostreams::back_insert_device<std::string> inserter(buffer);
+ boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>> inserterStream(inserter);
+ boost::archive::binary_oarchive outputArchive(inserterStream, boost::archive::no_header | boost::archive::no_codecvt);
+ outputArchive << value;
+ return buffer;
}
-template<typename T>
-void serFromString(const string_view& str, T& ret)
+template <typename T>
+void deserializeFromBuffer(const string_view& buffer, T& value)
{
- ret = T();
-
- boost::iostreams::array_source source(&str[0], str.size());
+ value = T();
+ boost::iostreams::array_source source(&buffer[0], buffer.size());
boost::iostreams::stream<boost::iostreams::array_source> stream(source);
- boost::archive::binary_iarchive in_archive(stream, boost::archive::no_header|boost::archive::no_codecvt);
- in_archive >> ret;
-
- /*
- std::istringstream istr{str};
- boost::archive::binary_iarchive oi(istr,boost::archive::no_header|boost::archive::no_codecvt );
- oi >> ret;
- */
+ boost::archive::binary_iarchive inputArchive(stream, boost::archive::no_header | boost::archive::no_codecvt);
+ inputArchive >> value;
}
-
template <class T, class Enable>
-inline std::string keyConv(const T& t);
+inline std::string keyConv(const T& value);
-template <class T, typename std::enable_if<std::is_arithmetic<T>::value,T>::type* = nullptr>
-inline std::string keyConv(const T& t)
+template <class T, typename std::enable_if<std::is_arithmetic<T>::value, T>::type* = nullptr>
+inline std::string keyConv(const T& value)
{
- return std::string((char*)&t, sizeof(t));
+ return std::string((char*)&value, sizeof(value));
}
-// this is how to override specific types.. it is ugly
-template<class T, typename std::enable_if<std::is_same<T, std::string>::value,T>::type* = nullptr>
-inline std::string keyConv(const T& t)
+/**
+ * keyConv specialization for std::string.
+ */
+template <class T, typename std::enable_if<std::is_same<T, std::string>::value, T>::type* = nullptr>
+inline std::string keyConv(const T& value)
{
- return t;
+ return value;
}
-
namespace {
inline MDBOutVal getKeyFromCombinedKey(MDBInVal combined) {
if (combined.d_mdbval.mv_size < sizeof(uint32_t)) {
if((*d_parent.d_txn)->get(d_parent.d_parent->d_main, id, data))
return false;
- serFromString(data.get<std::string>(), t);
+ deserializeFromBuffer(data.get<std::string>(), t);
return true;
}
// auto range = (*d_parent.d_txn)->prefix_range<N>(domain);
// auto range = prefix_range<N>(key);
- LMDBIDvec ids;
+ LmdbIdVec ids;
// because we know we only want one item, pass onlyOldest=true to consistently get the same one out of a set of duplicates
get_multi<N>(key, ids, true);
if(d_on_index) {
if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
throw std::runtime_error("Missing id in constructor");
- serFromString(d_data.get<std::string>(), d_t);
+ deserializeFromBuffer(d_data.get<std::string>(), d_t);
}
else
- serFromString(d_id.get<std::string>(), d_t);
+ deserializeFromBuffer(d_id.get<std::string>(), d_t);
}
explicit iter_t(Parent* parent, typename Parent::cursor_t&& cursor, const std::string& prefix) :
if(d_on_index) {
if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
throw std::runtime_error("Missing id in constructor");
- serFromString(d_data.get<std::string>(), d_t);
+ deserializeFromBuffer(d_data.get<std::string>(), d_t);
}
else
- serFromString(d_id.get<std::string>(), d_t);
+ deserializeFromBuffer(d_id.get<std::string>(), d_t);
}
// if(filter && !filter(data))
// goto next;
- serFromString(data.get<std::string>(), d_t);
+ deserializeFromBuffer(data.get<std::string>(), d_t);
}
else {
// if(filter && !filter(data))
// goto next;
- serFromString(d_id.get<std::string>(), d_t);
+ deserializeFromBuffer(d_id.get<std::string>(), d_t);
}
}
return *this;
};
template<int N>
- void get_multi(const typename std::tuple_element<N, tuple_t>::type::type& key, LMDBIDvec& ids, bool onlyOldest=false)
+ void get_multi(const typename std::tuple_element<N, tuple_t>::type::type& key, LmdbIdVec& ids, bool onlyOldest=false)
{
// std::cerr<<"in get_multi"<<std::endl;
typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
// flags = MDB_APPEND;
}
}
- (*d_txn)->put(d_parent->d_main, id, serToString(t), flags);
+ (*d_txn)->put(d_parent->d_main, id, serializeToBuffer(t), flags);
#define insertMacro(N) std::get<N>(d_parent->d_tuple).put(*d_txn, t, id);
insertMacro(0);
while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT)) {
first = false;
T t;
- serFromString(data.get<std::string>(), t);
+ deserializeFromBuffer(data.get<std::string>(), t);
clearIndex(key.get<uint32_t>(), t);
cursor.del();
}
--- /dev/null
+lib_probds = static_library(
+ 'probds',
+ 'murmur3.cc',
+ extra_files: [
+ 'murmur3.h',
+ ],
+)
+
+dep_probds = declare_dependency(
+ link_with: lib_probds,
+ include_directories: include_directories('.'),
+)
HTTPBase() {
HTTPBase::initialize();
};
+ virtual ~HTTPBase() = default;
virtual void initialize() {
kind = 0;
rpos = route.size();
upos = requrl.path.size();
break;
- } else {
- // match until url[upos] or next / if pattern is at end
- while (upos < requrl.path.size()) {
- if (route[rpos+1] == '\0' && requrl.path[upos] == '/') {
- break;
- }
- if (requrl.path[upos] == route[rpos+1]) {
- break;
- }
- upos++;
+ }
+ // match until url[upos] or next / if pattern is at end
+ while (upos < requrl.path.size()) {
+ if (route[rpos+1] == '\0' && requrl.path[upos] == '/') {
+ break;
+ }
+ if (requrl.path[upos] == route[rpos+1]) {
+ break;
}
- nend = upos;
- params[pname] = funcptr::tie(nstart, nend);
+ upos++;
+ }
+ nend = upos;
+ params[pname] = funcptr::tie(nstart, nend);
+ if (upos > 0) {
+ upos--;
+ }
+ else {
+ // If upos is zero, do not decrement it and then increment at bottom of loop, this disturbs Coverity.
+ // Only increment rpos and continue loop
+ rpos++;
+ continue;
}
- upos--;
}
else if (route[rpos] != requrl.path[upos]) {
break;
AC_PATH_PROG([SYSTEMCTL], [systemctl], [no])
AS_IF([test "$SYSTEMCTL" = "no"],
[AC_MSG_ERROR([systemctl not found])], [
- _systemd_version=`${SYSTEMCTL} --version|head -1 |cut -d" " -f 2`
+ _systemd_version=`${SYSTEMCTL} --version|head -1 | tr ".~" " " | cut -d" " -f 2`
if test $_systemd_version -ge 183; then
systemd_private_tmp=y
fi
)
)
+libpdns_uuidutils = declare_dependency(
+ link_whole: static_library(
+ 'pdns-uuidutils',
+ src_dir / 'uuid-utils.cc',
+ src_dir / 'uuid-utils.hh',
+ dependencies: [dep_rt, dep_boost],
+ )
+)
+
if get_option('module-lmdb') != 'disabled'
subdir('ext' / 'lmdb-safe')
endif
if dep_systemd.found()
systemd_service_conf = configuration_data()
- systemd_service_conf.set('BinDir', get_option('bindir'))
- systemd_service_conf.set('StaticBinDir', get_option('sbindir'))
+ systemd_service_conf.set('BinDir', get_option('prefix') / get_option('bindir'))
+ systemd_service_conf.set('StaticBinDir', get_option('prefix') / get_option('sbindir'))
systemd_service_user = get_option('systemd-service-user')
systemd_service_group = get_option('systemd-service-group')
systemd_service_conf.set('ServiceUser', systemd_service_user)
auth_service_conf_general = configuration_data()
auth_service_conf_general.merge_from(auth_service_conf)
auth_service_conf_general.set('Description', 'PowerDNS Authoritative Server')
+ auth_service_conf_general.set('ConfigName', '')
auth_service_conf_general.set('SocketDir', enable_socket_dir ? '--socket-dir=%t/pdns-auth' : '')
auth_service_conf_general.set('SyslogIdentifier', 'pdns-auth')
auth_service_conf_general.set('RuntimeDirectory', 'pdns-auth')
ixfrdist_service_conf_general = configuration_data()
ixfrdist_service_conf_general.merge_from(ixfrdist_service_conf)
ixfrdist_service_conf_general.set('Description', 'PowerDNS IXFR Distributor')
+ ixfrdist_service_conf_general.set('Config', '')
configure_file(
input: 'auth' / 'systemd' / 'ixfrdist.service.in',
ixfrdist_service_conf_instance = configuration_data()
ixfrdist_service_conf_instance.merge_from(ixfrdist_service_conf)
ixfrdist_service_conf_instance.set('Description', 'PowerDNS IXFR Distributor %i')
- ixfrdist_service_conf_instance.set('Config', '--config=' + get_option('sysconfdir') + '/ixfrdist-%.ymli')
+ ixfrdist_service_conf_instance.set('Config', '--config=' + get_option('sysconfdir') + '/ixfrdist-%i.yml')
configure_file(
input: 'auth' / 'systemd' / 'ixfrdist.service.in',
src_dir / 'unix_semaphore.cc',
src_dir / 'unix_utility.cc',
src_dir / 'utility.hh',
- src_dir / 'uuid-utils.cc',
- src_dir / 'uuid-utils.hh',
src_dir / 'validate.hh',
src_dir / 'version.cc',
src_dir / 'version.hh',
},
'pdns-auth-util': {
'main': src_dir / 'pdnsutil.cc',
+ 'export-dynamic': true,
'files-extra': libpdns_bind_dnssec_schema_gen,
'deps-extra': [
dep_modules,
'main': src_dir / 'ixplore.cc',
'manpages': ['ixplore.1'],
},
+ 'dnstcpbench': {
+ 'main': src_dir / 'dnstcpbench.cc',
+ 'manpages': ['dnstcpbench.1'],
+ },
+ 'dnsbulktest': {
+ 'main': src_dir / 'dnsbulktest.cc',
+ 'manpages': ['dnsbulktest.1'],
+ },
# Broken
# 'comfun' : {
# 'main': src_dir / 'comfun.cc',
src_dir / 'tcpiohandler.hh',
)
- if have_boost_1_48_0
- tools += {
- 'dnstcpbench': {
- 'main': src_dir / 'dnstcpbench.cc',
- 'manpages': ['dnstcpbench.1'],
- },
- 'dnsbulktest': {
- 'main': src_dir / 'dnsbulktest.cc',
- 'manpages': ['dnsbulktest.1'],
- },
- }
- endif
endif
if get_option('tools-ixfrdist')
endif
if get_option('fuzz-targets')
- tools += {
- 'fuzz-target-moadnsparser' : { 'main': src_dir / 'fuzz_moadnsparser.cc' },
- 'fuzz-target-packetcache' : { 'main': src_dir / 'fuzz_packetcache.cc' },
- 'fuzz-target-proxyprotocol' : { 'main': src_dir / 'fuzz_proxyprotocol.cc' },
- 'fuzz-target-dnslabeltext-parseRFC1035CharString' : { 'main': src_dir / 'fuzz_dnslabeltext_parseRFC1035CharString.cc' },
- 'fuzz-target-yahttp' : { 'main': src_dir / 'fuzz_yahttp.cc' },
- 'fuzz-target-zoneparsertng' : { 'main': src_dir / 'fuzz_zoneparsertng.cc' },
- }
+ fuzz_targets = [
+ 'moadnsparser',
+ 'packetcache',
+ 'proxyprotocol',
+ 'dnslabeltext-parseRFC1035CharString',
+ 'yahttp',
+ 'zoneparsertng',
+ ]
+
+ foreach target: fuzz_targets
+ source_file = src_dir / 'fuzz_' + target.underscorify() + '.cc'
+ tools += {
+ 'fuzz-target-' + target: { 'main': source_file }
+ }
+ endforeach
endif
libpdns_common = declare_dependency(
dependencies: [
deps,
libpdns_common,
+ libpdns_uuidutils,
deps_extra,
],
)
'man-pages',
command: [
python,
- docs_dir / 'generate-man-pages.py',
+ product_source_dir / docs_dir / 'generate-man-pages.py',
'--venv-name', 'venv-auth-man-pages',
'--requirements-file', docs_dir / 'requirements.txt',
'--source-directory', docs_dir,
)
endforeach
endif
+
+if get_option('unit-tests-backends')
+ start_test_stop = files('regression-tests' / 'start-test-stop')[0]
+endif
+
+if get_option('module-geoip') != 'disabled' and get_option('unit-tests-backends')
+ test(
+ 'pdns-auth-backend-geoip',
+ start_test_stop,
+ args: ['5300', 'geoip'],
+ workdir: product_source_dir / 'regression-tests',
+ depends: [pdns_auth],
+ )
+endif
if auto_var_init != 'disabled'
arg = '-ftrivial-auto-var-init=' + auto_var_init
- if not cxx.has_argument(arg)
- error('Compiler does not support ' + arg + ', which is needed for automatic variable initialization')
- subdir_done()
+ if cxx.has_argument(arg)
+ add_project_arguments(arg, language: ['c', 'cpp'])
+ else
+ warning('Compiler does not support ' + arg + ', which is needed for automatic variable initialization')
+ auto_var_init = 'unsupported by compiler'
endif
-
- add_project_arguments(arg, language: ['c', 'cpp'])
endif
summary('Auto Var Init', auto_var_init, section: 'Configuration')
--- /dev/null
+dep_boost_context = dependency('boost', modules: ['context'], required: true)
+
--- /dev/null
+dep_boost_filesystem = dependency('boost', modules: ['filesystem'], required: false)
+summary('Filesystem', dep_boost_filesystem.found(), bool_yn: true, section: 'Boost')
-dep_boost = dependency('boost', version: '>= 1.42', required: true)
-# Boost accumulators, as used by dnsbulktest and dnstcpbench, need 1.48+ to be compatible
-# with C++11.
-have_boost_1_48_0 = dep_boost.version().version_compare('>= 1.48.0')
-conf.set('HAVE_BOOST_GE_148', have_boost_1_48_0, description: 'Boost version >= 1.48.0')
+dep_boost = dependency('boost', version: '>= 1.54', required: true)
# conf.set('BOOST_CONTAINER_USE_STD_EXCEPTIONS', true, description: 'Boost use std exceptions')
add_project_arguments('-DBOOST_CONTAINER_USE_STD_EXCEPTIONS', language: ['c', 'cpp'])
summary('Boost', dep_boost.found(), bool_yn: true, section: 'Boost')
lib_cxx_fs = cxx.find_library('stdc++fs', disabler: true, required: false)
if lib_cxx_fs.found()
if cxx.links(prog, name: '-lstdc++fs is needed', dependencies: lib_cxx_fs)
- need_cxx_fs = '-lstdc++fs'
+ need_cxx_fs = true
dep_cxx_fs = declare_dependency(dependencies: lib_cxx_fs)
summary('Filesystem library', lib_cxx_fs, section: 'System')
endif
lib_cxx_fs = cxx.find_library('c++fs', disabler: true, required: false)
if lib_cxx_fs.found()
if cxx.links(prog, name: '-lc++fs is needed', dependencies: lib_cxx_fs)
- need_cxx_fs = '-lc++fs'
+ need_cxx_fs = true
dep_cxx_fs = declare_dependency(dependencies: lib_cxx_fs)
summary('Filesystem library', lib_cxx_fs, section: 'System')
else
--- /dev/null
+opt_dnstap = get_option('dnstap')
+dep_dnstap = dependency('libfstrm', required: opt_dnstap)
+
+if dep_dnstap.found()
+ funcs = [
+ 'fstrm_tcp_writer_init',
+ ]
+
+ foreach func: funcs
+ has = cxx.has_function(func, dependencies: dep_dnstap)
+ conf.set('HAVE_' + func.to_upper(), has, description: 'Have libfstram ' + func)
+ endforeach
+endif
+
+conf.set('HAVE_FSTRM', dep_dnstap.found(), description: 'libfstrm')
+summary('DNSTAP', dep_dnstap.found(), bool_yn: true, section: 'Configuration')
+
--- /dev/null
+opt_libcurl = get_option('libcurl')
+dep_libcurl = dependency('libcurl', version: '>= 7.21.3', required: opt_libcurl)
+conf.set('HAVE_LIBCURL', dep_libcurl.found(), description: 'Whether we have libcurl')
+summary('CURL', dep_libcurl.found(), bool_yn: true, section: 'Configuration')
--- /dev/null
+dep_libresolv = dependency('resolv', required: false)
+
+need = false
+if not dep_libresolv.found()
+ # Dependency resolving does not work for macOS
+ if build_machine.system() == 'darwin'
+ add_project_link_arguments('-lresolv', language: 'cpp')
+ need = true
+ endif
+else
+ need = true
+endif
+
+summary('Need -lresolv', need, bool_yn: true, section: 'System')
--- /dev/null
+opt_libsnmp = get_option('snmp')
+
+dep_libsnmp = declare_dependency()
+
+if get_option('snmp')
+ snmp_config = find_program('net-snmp-config', required: true)
+ snmp_ldflags_res = run_command(snmp_config, '--libs', check: true)
+ snmp_ldflags = snmp_ldflags_res.stdout().strip().split()
+ snmp_ldflags_res = run_command(snmp_config, '--agent-libs', check: true)
+ snmp_ldflags += snmp_ldflags_res.stdout().strip().split()
+
+ dep_libsnmp = declare_dependency(
+ link_args: snmp_ldflags,
+ )
+endif
+
+if dep_libsnmp.found()
+ funcs = [
+ 'snmp_select_info2',
+ ]
+
+ foreach func: funcs
+ define = 'HAVE_' + func.to_upper()
+ have_func = cxx.has_function(func, dependencies: dep_libsnmp)
+ conf.set(define, have_func, description: 'Have libsnmp ' + func)
+ endforeach
+endif
+
+conf.set('HAVE_LIBSSNMP', dep_libsnmp.found(), description: 'libsnmp')
+summary('SNMP', dep_libsnmp.found(), bool_yn: true, section: 'Configuration')
--- /dev/null
+opt_nod = get_option('nod')
+
+if not dep_boost_filesystem.found() and opt_nod
+ error('NOD support was requested but boost filesystem module not found')
+endif
+
+enable_nod = dep_boost_filesystem.found() and opt_nod
+dep_nod = declare_dependency(
+ dependencies: [dep_boost_filesystem, dep_probds],
+)
+
+conf.set('NOD_ENABLED', enable_nod, description: 'NOD')
+summary('NOD', enable_nod, bool_yn: true, section: 'Configuration')
--- /dev/null
+funcs = [
+ 'pthread_setaffinity_np',
+ 'pthread_getattr_np',
+ 'pthread_get_stackaddr_np',
+ 'pthread_get_stacksize_np',
+]
+
+foreach func: funcs
+ found = cxx.has_function(func, dependencies: dep_threads)
+ define = 'HAVE_' + func.to_upper()
+ conf.set(define, found, description: 'Have ' + func)
+ summary(func, found, bool_yn: true, section: 'POSIX Threads')
+endforeach
geoipinterface.cc geoipinterface.hh
libgeoipbackend_la_LDFLAGS = -module -avoid-version
-libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS) $(MMDB_LIBS)
+libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS) $(MMDB_LIBS) $(CXXFS_LIBS)
}
Netmask addr{"0.0.0.0/0"};
- if (pkt_p != nullptr)
+ if (pkt_p != nullptr) {
addr = Netmask(pkt_p->getRealRemote());
+ }
gl.netmask = 0;
bool GeoIPBackend::get(DNSResourceRecord& r)
{
- if (d_result.empty())
+ if (d_result.empty()) {
return false;
+ }
r = d_result.back();
d_result.pop_back();
{
ReadLock rl(&s_state_lock);
- for (GeoIPDomain dom : s_domains) {
+ for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == domain) {
SOAData sd;
this->getSOA(domain, sd);
return false;
ReadLock rl(&s_state_lock);
- for (GeoIPDomain dom : s_domains) {
+ for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == name) {
if (hasDNSSECkey(dom.domain)) {
meta[string("NSEC3NARROW")].push_back("1");
return false;
ReadLock rl(&s_state_lock);
- for (GeoIPDomain dom : s_domains) {
+ for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == name) {
if (hasDNSSECkey(dom.domain)) {
if (kind == "NSEC3NARROW")
if (!d_dnssec)
return false;
ReadLock rl(&s_state_lock);
- for (GeoIPDomain dom : s_domains) {
+ for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == name) {
regex_t reg;
regmatch_t regm[5];
WriteLock rl(&s_state_lock);
ostringstream path;
- for (GeoIPDomain dom : s_domains) {
+ for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == name) {
regex_t reg;
regmatch_t regm[5];
WriteLock rl(&s_state_lock);
unsigned int nextid = 1;
- for (GeoIPDomain dom : s_domains) {
+ for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == name) {
regex_t reg;
regmatch_t regm[5];
if (!d_dnssec)
return false;
WriteLock rl(&s_state_lock);
- for (GeoIPDomain dom : s_domains) {
+ for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == name) {
regex_t reg;
regmatch_t regm[5];
if (!d_dnssec)
return false;
WriteLock rl(&s_state_lock);
- for (GeoIPDomain dom : s_domains) {
+ for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == name) {
regex_t reg;
regmatch_t regm[5];
stringtok(parts2, parts1[0], ";");
/* try extension */
filename = parts2[0];
- size_t pos = filename.find_last_of(".");
+ size_t pos = filename.find_last_of('.');
if (pos != string::npos)
driver = filename.substr(pos + 1);
else
'geoipinterface.hh',
)
-module_deps = [deps, dep_geoip, dep_mmdb, dep_yaml_cpp]
+module_deps = [deps, dep_geoip, dep_mmdb, dep_yaml_cpp, dep_cxx_fs]
declare(suffix, "update-account-query", "", "update domains set account=? where name=?");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?");
- declare(suffix, "info-all-primary-query", "", "select d.id, d.name, d.type, d.notified_serial,d.options, d.catalog,r.content from records r join domains d on r.domain_id=d.id and r.name=d.name where r.type='SOA' and r.disabled=0 and d.type in ('MASTER', 'PRODUCER')");
+ declare(suffix, "info-all-primary-query", "", "select d.id, d.name, d.type, d.notified_serial,d.options, d.catalog,r.content from records r join domains d on r.domain_id=d.id and r.name=d.name where r.type='SOA' and r.disabled=0 and d.type in ('MASTER', 'PRODUCER') order by d.id");
declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0");
declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=?");
declare(suffix, "delete-domain-query", "", "delete from domains where name=?");
--lodbc
\ No newline at end of file
+$(UNIXODBC_LIBS)
declare(suffix, "update-account-query", "", "update domains set account=? where name=?");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?");
- declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')");
+ declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER') order by domains.id");
declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0");
declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=?");
declare(suffix, "delete-domain-query", "", "delete from domains where name=?");
declare(suffix, "update-account-query", "", "update domains set account=$1 where name=$2");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=$1 where id=$2");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=$1 where id=$2");
- declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=false and domains.type in ('MASTER', 'PRODUCER')");
+ declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=false and domains.type in ('MASTER', 'PRODUCER') order by domains.id");
declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=$1 and records.type='SOA' and records.disabled=false");
declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=$1");
declare(suffix, "delete-domain-query", "", "delete from domains where name=$1");
declare(suffix, "update-account-query", "", "update domains set account=:account where name=:domain");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id");
- declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')");
+ declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER') order by domains.id");
declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=:catalog and records.type='SOA' and records.disabled=0");
declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=:catalog");
declare(suffix, "delete-domain-query", "", "delete from domains where name=:domain");
*/
#include "ext/lmdb-safe/lmdb-safe.hh"
+#include <cstring>
#include <lmdb.h>
+#include <memory>
#include <stdexcept>
#include <utility>
#ifdef HAVE_CONFIG_H
uint32_t schemaversion;
- int rc;
- MDB_env* env = nullptr;
+ MDB_env* tmpEnv = nullptr;
- if ((rc = mdb_env_create(&env)) != 0) {
+ if (mdb_env_create(&tmpEnv) != 0) {
throw std::runtime_error("mdb_env_create failed");
}
- if ((rc = mdb_env_set_mapsize(env, 0)) != 0) {
+ std::unique_ptr<MDB_env, decltype(&mdb_env_close)> env{tmpEnv, mdb_env_close};
+
+ if (mdb_env_set_mapsize(tmpEnv, 0) != 0) {
throw std::runtime_error("mdb_env_set_mapsize failed");
}
- if ((rc = mdb_env_set_maxdbs(env, 20)) != 0) { // we need 17: 1 {"pdns"} + 4 {"domains", "keydata", "tsig", "metadata"} * 2 {v4, v5} * 2 {main, index in _0}
- mdb_env_close(env);
+ if (mdb_env_set_maxdbs(tmpEnv, 20) != 0) { // we need 17: 1 {"pdns"} + 4 {"domains", "keydata", "tsig", "metadata"} * 2 {v4, v5} * 2 {main, index in _0}
throw std::runtime_error("mdb_env_set_maxdbs failed");
}
- if ((rc = mdb_env_open(env, filename.c_str(), MDB_NOSUBDIR | MDB_RDONLY, 0600)) != 0) {
- if (rc == ENOENT) {
- // we don't have a database yet! report schema 0, with 0 shards
- return {0u, 0u};
+ {
+ int retCode = mdb_env_open(tmpEnv, filename.c_str(), MDB_NOSUBDIR | MDB_RDONLY, 0600);
+ if (retCode != 0) {
+ if (retCode == ENOENT) {
+ // we don't have a database yet! report schema 0, with 0 shards
+ return {0U, 0U};
+ }
+ throw std::runtime_error("mdb_env_open failed");
}
- mdb_env_close(env);
- throw std::runtime_error("mdb_env_open failed");
}
MDB_txn* txn = nullptr;
- if ((rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)) != 0) {
- mdb_env_close(env);
+ if (mdb_txn_begin(tmpEnv, nullptr, MDB_RDONLY, &txn) != 0) {
throw std::runtime_error("mdb_txn_begin failed");
}
MDB_dbi dbi;
- if ((rc = mdb_dbi_open(txn, "pdns", 0, &dbi)) != 0) {
- if (rc == MDB_NOTFOUND) {
- // this means nothing has been inited yet
- // we pretend this means 5
+ {
+ int retCode = mdb_dbi_open(txn, "pdns", 0, &dbi);
+ if (retCode != 0) {
+ if (retCode == MDB_NOTFOUND) {
+ // this means nothing has been inited yet
+ // we pretend this means 5
+ mdb_txn_abort(txn);
+ return {5U, 0U};
+ }
mdb_txn_abort(txn);
- mdb_env_close(env);
- return {5u, 0u};
+ throw std::runtime_error("mdb_dbi_open failed");
}
- mdb_txn_abort(txn);
- mdb_env_close(env);
- throw std::runtime_error("mdb_dbi_open failed");
}
MDB_val key, data;
key.mv_data = (char*)"schemaversion";
key.mv_size = strlen((char*)key.mv_data);
- if ((rc = mdb_get(txn, dbi, &key, &data)) != 0) {
- if (rc == MDB_NOTFOUND) {
- // this means nothing has been inited yet
- // we pretend this means 5
- mdb_txn_abort(txn);
- mdb_env_close(env);
- return {5u, 0u};
- }
+ {
+ int retCode = mdb_get(txn, dbi, &key, &data);
+ if (retCode != 0) {
+ if (retCode == MDB_NOTFOUND) {
+ // this means nothing has been inited yet
+ // we pretend this means 5
+ mdb_txn_abort(txn);
+ return {5U, 0U};
+ }
- throw std::runtime_error("mdb_get pdns.schemaversion failed");
+ throw std::runtime_error("mdb_get pdns.schemaversion failed");
+ }
}
if (data.mv_size == 4) {
key.mv_data = (char*)"shards";
key.mv_size = strlen((char*)key.mv_data);
- if ((rc = mdb_get(txn, dbi, &key, &data)) != 0) {
- if (rc == MDB_NOTFOUND) {
- cerr << "schemaversion was set, but shards was not. Dazed and confused, trying to exit." << endl;
- mdb_txn_abort(txn);
- mdb_env_close(env);
- exit(1);
- }
+ {
+ int retCode = mdb_get(txn, dbi, &key, &data);
+ if (retCode != 0) {
+ if (retCode == MDB_NOTFOUND) {
+ cerr << "schemaversion was set, but shards was not. Dazed and confused, trying to exit." << endl;
+ mdb_txn_abort(txn);
+ // NOLINTNEXTLINE(concurrency-mt-unsafe)
+ exit(1);
+ }
- throw std::runtime_error("mdb_get pdns.shards failed");
+ throw std::runtime_error("mdb_get pdns.shards failed");
+ }
}
if (data.mv_size == 4) {
}
mdb_txn_abort(txn);
- mdb_env_close(env);
return {schemaversion, shards};
}
BOOST_IS_BITWISE_SERIALIZABLE(ComboAddress);
template <>
-std::string serToString(const LMDBBackend::LMDBResourceRecord& lrr)
+std::string serializeToBuffer(const LMDBBackend::LMDBResourceRecord& value)
{
- std::string ret;
- uint16_t len = lrr.content.length();
- ret.reserve(2 + len + 7);
-
- ret.assign((const char*)&len, 2);
- ret += lrr.content;
- ret.append((const char*)&lrr.ttl, 4);
- ret.append(1, (char)lrr.auth);
- ret.append(1, (char)lrr.disabled);
- ret.append(1, (char)lrr.ordername);
- return ret;
+ std::string buffer;
+
+ // Data size of the resource record.
+ uint16_t len = value.content.length();
+
+ // Reserve space to store the size of the resource record + the content of the resource
+ // record + a few other things.
+ buffer.reserve(sizeof(len) + len + sizeof(value.ttl) + sizeof(value.auth) + sizeof(value.disabled) + sizeof(value.ordername));
+
+ // Store the size of the resource record.
+ // NOLINTNEXTLINE.
+ buffer.assign((const char*)&len, sizeof(len));
+
+ // Store the contents of the resource record.
+ buffer += value.content;
+
+ // The few other things.
+ // NOLINTNEXTLINE.
+ buffer.append((const char*)&value.ttl, sizeof(value.ttl));
+ buffer.append(1, (char)value.auth);
+ buffer.append(1, (char)value.disabled);
+ buffer.append(1, (char)value.ordername);
+
+ return buffer;
}
template <>
-std::string serToString(const vector<LMDBBackend::LMDBResourceRecord>& lrrs)
+std::string serializeToBuffer(const vector<LMDBBackend::LMDBResourceRecord>& value)
{
std::string ret;
- for (const auto& lrr : lrrs) {
- ret += serToString(lrr);
+ for (const auto& lrr : value) {
+ ret += serializeToBuffer(lrr);
}
return ret;
}
-static inline size_t serOneRRFromString(const string_view& str, LMDBBackend::LMDBResourceRecord& lrr)
+static inline size_t deserializeRRFromBuffer(const string_view& str, LMDBBackend::LMDBResourceRecord& lrr)
{
uint16_t len;
memcpy(&len, &str[0], 2);
}
template <>
-void serFromString(const string_view& str, LMDBBackend::LMDBResourceRecord& lrr)
+void deserializeFromBuffer(const string_view& buffer, LMDBBackend::LMDBResourceRecord& value)
{
- serOneRRFromString(str, lrr);
+ deserializeRRFromBuffer(buffer, value);
}
template <>
-void serFromString(const string_view& str, vector<LMDBBackend::LMDBResourceRecord>& lrrs)
+void deserializeFromBuffer(const string_view& buffer, vector<LMDBBackend::LMDBResourceRecord>& value)
{
- auto str_copy = str;
+ auto str_copy = buffer;
while (str_copy.size() >= 9) { // minimum length for a record is 10
LMDBBackend::LMDBResourceRecord lrr;
- auto rrLength = serOneRRFromString(str_copy, lrr);
- lrrs.emplace_back(lrr);
+ auto rrLength = deserializeRRFromBuffer(str_copy, lrr);
+ value.emplace_back(lrr);
str_copy.remove_prefix(rrLength);
}
}
rrs = _rrs.get<string>();
}
- rrs += serToString(lrr);
+ rrs += serializeToBuffer(lrr);
d_rwtxn->txn->put(d_rwtxn->db->dbi, matchName, rrs);
lrr.ttl = 0;
lrr.content = lrr.qname.toDNSStringLC();
lrr.auth = 0;
- string ser = serToString(lrr);
+ string ser = serializeToBuffer(lrr);
d_rwtxn->txn->put(d_rwtxn->db->dbi, co(lrr.domain_id, ordername, QType::NSEC3), ser);
lrr.ttl = 1;
lrr.content = ordername.toDNSString();
- ser = serToString(lrr);
+ ser = serializeToBuffer(lrr);
d_rwtxn->txn->put(d_rwtxn->db->dbi, co(lrr.domain_id, lrr.qname, QType::NSEC3), ser);
}
}
lrr.auth = nt.second;
lrr.ordername = true;
- std::string ser = serToString(lrr);
+ std::string ser = serializeToBuffer(lrr);
d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, lrr.qname, QType::ENT), ser);
}
return true;
lrr.ttl = 0;
lrr.auth = nt.second;
lrr.ordername = nt.second;
- ser = serToString(lrr);
+ ser = serializeToBuffer(lrr);
d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, lrr.qname, QType::ENT), ser);
if (!narrow && lrr.auth) {
lrr.content = lrr.qname.toDNSString();
lrr.auth = false;
lrr.ordername = false;
- ser = serToString(lrr);
+ ser = serializeToBuffer(lrr);
ordername = DNSName(toBase32Hex(hashQNameWithSalt(ns3prc, nt.first)));
d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, ordername, QType::NSEC3), ser);
lrr.ttl = 1;
lrr.content = ordername.toDNSString();
- ser = serToString(lrr);
+ ser = serializeToBuffer(lrr);
d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, lrr.qname, QType::NSEC3), ser);
}
}
adjustedRRSet.emplace_back(lrr);
}
- txn->txn->put(txn->db->dbi, match, serToString(adjustedRRSet));
+ txn->txn->put(txn->db->dbi, match, serializeToBuffer(adjustedRRSet));
}
if (needCommit)
abortTransaction();
- LMDBIDvec idvec;
+ LmdbIdVec idvec;
if (!d_handle_dups) {
// get domain id
{ // Remove metadata
auto txn = d_tmeta->getRWTransaction();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(domain, ids);
{ // Remove cryptokeys
auto txn = d_tkdb->getRWTransaction();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(domain, ids);
for (auto _id : ids) {
continue;
}
- serFromString(d_currentVal.get<string_view>(), d_currentrrset);
+ deserializeFromBuffer(d_currentVal.get<string_view>(), d_currentrrset);
d_currentrrsetpos = 0;
}
else {
MDBOutVal val;
if (!txn->txn->get(txn->db->dbi, co(di.id, g_rootdnsname, QType::SOA), val)) {
LMDBResourceRecord lrr;
- serFromString(val.get<string_view>(), lrr);
+ deserializeFromBuffer(val.get<string_view>(), lrr);
if (lrr.content.size() >= 5 * sizeof(uint32_t)) {
uint32_t serial;
// a SOA has five 32 bit fields, the first of which is the serial
compoundOrdername co;
MDBOutVal val;
if (!txn2->txn->get(txn2->db->dbi, co(di.id, g_rootdnsname, QType::SOA), val)) {
- serFromString(val.get<string_view>(), lrr);
+ deserializeFromBuffer(val.get<string_view>(), lrr);
memcpy(&st, &lrr.content[lrr.content.size() - sizeof(soatimes)], sizeof(soatimes));
if ((time_t)(di.last_check + ntohl(st.refresh)) > now) { // still fresh
return false;
{
meta.clear();
auto txn = d_tmeta->getROTransaction();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(name, ids);
DomainMeta dm;
{
auto txn = d_tmeta->getRWTransaction();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(name, ids);
DomainMeta dmeta;
bool LMDBBackend::getDomainKeys(const DNSName& name, std::vector<KeyData>& keys)
{
auto txn = d_tkdb->getROTransaction();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(name, ids);
KeyDataDB key;
for (;;) {
if (co.getDomainID(key.getNoStripHeader<StringView>()) != id) {
- //cout<<"Last record also not part of this zone!"<<endl;
- // this implies something is wrong in the database, nothing we can do
+ // cout<<"Last record also not part of this zone!"<<endl;
+ // this implies something is wrong in the database, nothing we can do
return false;
}
if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (!lrr.ttl) // the kind of NSEC3 we need
break;
}
}
for (;;) {
if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (!lrr.ttl)
break;
}
}
for (;;) {
if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (!lrr.ttl)
break;
}
// cout<<"Potentially stopping traverse at "<< co.getQName(key.get<StringView>()) <<", " << (co.getQName(key.get<StringView>()).canonCompare(qname))<<endl;
// cout<<"qname = "<<qname<<endl;
// cout<<"here = "<<co.getQName(key.get<StringView>())<<endl;
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (!lrr.ttl)
break;
}
for (;;) {
if (co.getDomainID(key.getNoStripHeader<StringView>()) != id) {
- //cout<<"Last record also not part of this zone!"<<endl;
- // this implies something is wrong in the database, nothing we can do
+ // cout<<"Last record also not part of this zone!"<<endl;
+ // this implies something is wrong in the database, nothing we can do
return false;
}
if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (!lrr.ttl) // the kind of NSEC3 we need
break;
}
}
for (;;) {
if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (!lrr.ttl)
break;
}
}
for (;;) {
if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (!lrr.ttl)
break;
}
// cout<<"After "<<co.getQName(key.get<StringView>()) <<endl;
if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (!lrr.ttl) {
break;
}
if (co.getDomainID(key.getNoStripHeader<string_view>()) == id && key.getNoStripHeader<StringView>().rfind(matchkey, 0) == 0)
continue;
LMDBResourceRecord lrr;
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (co.getQType(key.getNoStripHeader<string_view>()).getCode() && (lrr.auth || co.getQType(key.getNoStripHeader<string_view>()).getCode() == QType::NS))
break;
}
return false;
}
LMDBResourceRecord lrr;
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (co.getQType(key.getNoStripHeader<string_view>()).getCode() && (lrr.auth || co.getQType(key.getNoStripHeader<string_view>()).getCode() == QType::NS))
break;
}
int skips = 0;
for (;;) {
LMDBResourceRecord lrr;
- serFromString(val.get<StringView>(), lrr);
+ deserializeFromBuffer(val.get<StringView>(), lrr);
if (co.getQType(key.getNoStripHeader<string_view>()).getCode() && (lrr.auth || co.getQType(key.getNoStripHeader<string_view>()).getCode() == QType::NS)) {
after = co.getQName(key.getNoStripHeader<string_view>()) + zonename;
// cout <<"Found auth ("<<lrr.auth<<") or an NS record "<<after<<", type: "<<co.getQType(key.getNoStripHeader<string_view>()).toString()<<", ttl = "<<lrr.ttl<<endl;
}
before = co.getQName(key.getNoStripHeader<string_view>()) + zonename;
LMDBResourceRecord lrr;
- serFromString(val.get<string_view>(), lrr);
+ deserializeFromBuffer(val.get<string_view>(), lrr);
// cout<<"And before to "<<before<<", auth = "<<rr.auth<<endl;
if (co.getQType(key.getNoStripHeader<string_view>()).getCode() && (lrr.auth || co.getQType(key.getNoStripHeader<string_view>()) == QType::NS))
break;
vector<LMDBResourceRecord> lrrs;
if (co.getQType(key.getNoStripHeader<StringView>()) != QType::NSEC3) {
- serFromString(val.get<StringView>(), lrrs);
+ deserializeFromBuffer(val.get<StringView>(), lrrs);
bool changed = false;
vector<LMDBResourceRecord> newRRs;
for (auto& lrr : lrrs) {
newRRs.push_back(std::move(lrr));
}
if (changed) {
- cursor.put(key, serToString(newRRs));
+ cursor.put(key, serializeToBuffer(newRRs));
}
}
// cerr<<"here qname="<<qname<<" ordername="<<ordername<<" qtype="<<qtype<<" matchkey="<<makeHexDump(matchkey)<<endl;
int txngetrc;
if (!(txngetrc = txn->txn->get(txn->db->dbi, matchkey, val))) {
- serFromString(val.get<string_view>(), lrr);
+ deserializeFromBuffer(val.get<string_view>(), lrr);
if (needNSEC3) {
if (hasOrderName && lrr.content != ordername.toDNSStringLC()) {
lrr.auth = 0;
lrr.content = rel.toDNSStringLC();
- string str = serToString(lrr);
+ string str = serializeToBuffer(lrr);
txn->txn->put(txn->db->dbi, co(domain_id, ordername, QType::NSEC3), str);
lrr.ttl = 1;
lrr.content = ordername.toDNSStringLC();
- str = serToString(lrr);
+ str = serializeToBuffer(lrr);
txn->txn->put(txn->db->dbi, matchkey, str); // 2
}
lrr.ttl = 0;
lrr.auth = true;
- std::string ser = serToString(lrr);
+ std::string ser = serializeToBuffer(lrr);
txn->txn->put(txn->db->dbi, co(domain_id, lrr.qname, 0), ser);
bool LMDBBackend::getTSIGKey(const DNSName& name, DNSName& algorithm, string& content)
{
auto txn = d_ttsig->getROTransaction();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(name, ids);
TSIGKey key;
{
auto txn = d_ttsig->getRWTransaction();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(name, ids);
TSIGKey key;
{
auto txn = d_ttsig->getRWTransaction();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(name, ids);
TSIGKey key;
auto id = iter.getID();
- LMDBIDvec ids;
+ LmdbIdVec ids;
txn.get_multi<0>(di.zone, ids);
if (ids.size() != 1) {
/* www.ds9a.nl -> nl0ds9a0www0
root -> 0 <- we need this to keep lmdb happy
nl -> nl0
-
*/
if (t.empty()) {
throw std::out_of_range(std::string(__PRETTY_FUNCTION__) + " Attempt to serialize an unset dnsname");
'lmdbbackend.hh',
)
-module_deps = [deps, dep_lmdb_safe, dep_lmdb, dep_boost_serialization]
+module_deps = [deps, dep_lmdb_safe, dep_lmdb, dep_boost_serialization, dep_systemd]
#include "boost/algorithm/string/join.hpp"
#include "pdns/arguments.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/lua-auth4.hh"
+
class Lua2BackendAPIv2 : public DNSBackend, AuthLua4
{
private:
public:
Lua2BackendAPIv2(const string& suffix)
{
+ d_include_path = ::arg()["lua-global-include-dir"];
setArgPrefix("lua2" + suffix);
d_debug_log = mustDo("query-logging");
prepareContext();
std::stringstream stream;
for (const auto& pair : args.object_items()) {
+ stream << prefix << "[" << YaHTTP::Utility::encodeURL(pair.first, false) << "]=";
if (pair.second.is_bool()) {
stream << (pair.second.bool_value() ? "1" : "0");
}
- else if (pair.second.is_null()) {
- stream << prefix << "[" << YaHTTP::Utility::encodeURL(pair.first, false) << "]=";
- }
- else {
- stream << prefix << "[" << YaHTTP::Utility::encodeURL(pair.first, false) << "]=" << YaHTTP::Utility::encodeURL(HTTPConnector::asString(pair.second), false);
+ else if (!pair.second.is_null()) {
+ stream << YaHTTP::Utility::encodeURL(HTTPConnector::asString(pair.second), false);
}
stream << "&";
}
else if (method == "replaceRRSet") {
std::stringstream ss2;
for (size_t index = 0; index < parameters["rrset"].array_items().size(); index++) {
- ss2 << buildMemberListArgs("rrset[" + std::to_string(index) + "]", parameters["rrset"][index]);
+ ss2 << buildMemberListArgs("rrset[" + std::to_string(index) + "]", parameters["rrset"][index]) << "&";
}
- req.body = ss2.str();
+ req.body = ss2.str().substr(0, ss2.str().size() - 1); // remove trailing &
req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
req.headers["content-length"] = std::to_string(req.body.size());
verb = "PATCH";
if (d_socket == nullptr) {
return -1; // cannot receive :(
}
- char buffer[4096];
- int rd = -1;
- time_t t0 = 0;
+ std::array<char, 4096> buffer{};
+ time_t time0 = 0;
arl.initialize(&resp);
try {
- t0 = time((time_t*)nullptr);
- while (!arl.ready() && (labs(time((time_t*)nullptr) - t0) <= timeout)) {
- rd = d_socket->readWithTimeout(buffer, sizeof(buffer), timeout);
- if (rd == 0) {
+ time0 = time(nullptr);
+ while (!arl.ready() && (labs(time(nullptr) - time0) <= timeout)) {
+ auto readBytes = d_socket->readWithTimeout(buffer.data(), buffer.size(), timeout);
+ if (readBytes == 0) {
throw NetworkError("EOF while reading");
}
- if (rd < 0) {
- throw NetworkError(std::string(strerror(rd)));
- }
- arl.feed(std::string(buffer, rd));
+ arl.feed(std::string(buffer.data(), readBytes));
}
// timeout occurred.
if (!arl.ready()) {
throw PDNSException("Received unacceptable HTTP status code " + std::to_string(resp.status) + " from HTTP endpoint " + d_addr.toStringWithPort());
}
- int rv = -1;
std::string err;
output = Json::parse(resp.body, err);
if (output != nullptr) {
- return resp.body.size();
+ return static_cast<int>(resp.body.size());
}
g_log << Logger::Error << "Cannot parse JSON reply: " << err << endl;
- return rv;
+ return -1;
}
bin_PROGRAMS += calidns
-if HAVE_BOOST_GE_148
bin_PROGRAMS += \
dnsbulktest \
dnstcpbench
-endif
endif # TOOLS
if UNIT_TESTS
noinst_PROGRAMS += testrunner
-if HAVE_BOOST_GE_148
TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message BOOST_TEST_RANDOM=1 SRCDIR='$(srcdir)'
TESTS=testrunner
-else
-check-local:
- @echo "Unit tests disabled, boost is too old"
-endif
else
check-local:
+++ /dev/null
-# dnsdist
-`dnsdist` is a highly DNS-, DoS- and abuse-aware loadbalancer. Its goal in
-life is to route traffic to the best server, delivering top performance
-to legitimate users while shunting or blocking abusive traffic.
-
-`dnsdist` is dynamic, in the sense that its configuration can be changed at
-runtime, and that its statistics can be queried from a console-like
-interface.
-
-All `dnsdist` features are documented at [dnsdist.org](https://dnsdist.org).
-
-## Compiling from git
-
-Make sure to `autoreconf -vi` before running `configure`.
-
-## macOS Notes
-
-Install dependencies from Homebrew:
-
-```sh
-brew install autoconf automake boost libedit libsodium libtool lua pkg-config protobuf
-```
-
-Let configure know where to find libedit, and openssl or libressl:
-
-```sh
-./configure 'PKG_CONFIG_PATH=/usr/local/opt/libedit/lib/pkgconfig:/usr/local/opt/libressl/lib/pkgconfig'
-make
-```
::arg().set("receiver-threads", "Default number of receiver threads to start") = "1";
::arg().set("queue-limit", "Maximum number of milliseconds to queue a query") = "1500";
::arg().set("resolver", "Use this resolver for ALIAS and the internal stub resolver") = "no";
+ ::arg().set("dnsproxy-udp-port-range", "Select DNS Proxy outgoing UDP port from given range (lower upper)") = "10000 60000";
::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate") = "1232";
::arg().set("config-name", "Name of this virtual configuration - will rename the binary image") = "";
::arg().set("webserver-allow-from", "Webserver/API access is only allowed from these subnets") = "127.0.0.1,::1";
::arg().set("webserver-loglevel", "Amount of logging in the webserver (none, normal, detailed)") = "normal";
::arg().set("webserver-max-bodysize", "Webserver/API maximum request/response body size in megabytes") = "2";
+ ::arg().set("webserver-connection-timeout", "Webserver/API request/response timeout in seconds") = "5";
::arg().setSwitch("webserver-hash-plaintext-credentials", "Whether to hash passwords and api keys supplied in plaintext, to prevent keeping the plaintext version in memory at runtime") = "no";
::arg().setSwitch("query-logging", "Hint backends that queries should be logged") = "no";
::arg().set("lua-prequery-script", "Lua script with prequery handler (DO NOT USE)") = "";
::arg().set("lua-dnsupdate-policy-script", "Lua script with DNS update policy handler") = "";
+ ::arg().set("lua-global-include-dir", "Include *.lua files from this directory into Lua contexts") = "";
::arg().setSwitch("traceback-handler", "Enable the traceback handler (Linux only)") = "yes";
::arg().setSwitch("direct-dnskey", "Fetch DNSKEY, CDS and CDNSKEY RRs from backend during DNSKEY or CDS/CDNSKEY synthesis") = "no";
Utility::dropUserPrivs(newuid);
if (::arg().mustDo("resolver")) {
- DP = std::make_unique<DNSProxy>(::arg()["resolver"]);
+ DP = std::make_unique<DNSProxy>(::arg()["resolver"], ::arg()["dnsproxy-udp-port-range"]);
DP->go();
}
#endif /* COVERAGE */
//! The main function of pdns, the pdns process
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
int main(int argc, char** argv)
{
versionSetProduct(ProductAuthoritative);
::arg().laxParse(argc, argv); // do a lax parse
if (::arg().mustDo("version")) {
- showProductVersion();
- showBuildConfiguration();
+ cout << getProductVersion();
+ cout << getBuildConfiguration();
return 0;
}
DLOG(g_log << Logger::Warning << "Verbose logging in effect" << endl);
- showProductVersion();
+ for (const string& line : getProductVersionLines()) {
+ g_log << Logger::Info << line << endl;
+ }
try {
mainthread();
return rrs;
}
-void CommunicatorClass::suck(const DNSName& domain, const ComboAddress& remote, bool force)
+void CommunicatorClass::suck(const DNSName& domain, const ComboAddress& remote, bool force) // NOLINT(readability-function-cognitive-complexity)
{
{
auto data = d_data.lock();
}
if (!script.empty()) {
try {
- pdl = make_unique<AuthLua4>();
+ pdl = make_unique<AuthLua4>(::arg()["lua-global-include-dir"]);
pdl->loadFile(script);
g_log << Logger::Info << logPrefix << "loaded Lua script '" << script << "'" << endl;
}
err = parseResult(mdp, DNSName(), 0, 0, &res);
if (!err) {
- for(const auto& answer : mdp.d_answers)
- if (answer.first.d_type == QType::SOA)
+ for(const auto& answer : mdp.d_answers) {
+ if (answer.d_type == QType::SOA) {
d_soacount++;
+ }
+ }
}
}
else {
records->reserve(mdp.d_answers.size());
for(auto& r: mdp.d_answers) {
- if (r.first.d_type == QType::SOA) {
+ if (r.d_type == QType::SOA) {
d_soacount++;
}
- records->push_back(std::move(r.first));
+ records->push_back(std::move(r));
}
}
void AXFRRetriever::timeoutReadn(uint16_t bytes, uint16_t timeoutsec)
{
- time_t start=time(nullptr);
- int n=0;
- int numread;
- while(n<bytes) {
+ const time_t start = time(nullptr);
+ uint16_t bytesRead = 0;
+
+ while (bytesRead < bytes) {
// coverity[store_truncates_time_t]
- int res=waitForData(d_sock, static_cast<int>(timeoutsec - (time(nullptr) - start)));
- if(res<0)
- throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
- if(!res)
+ auto elapsed = time(nullptr) - start;
+ if (elapsed > timeoutsec) {
+ throw ResolverException("Timeout while reading data from remote nameserver over TCP");
+ }
+ auto res = waitForData(d_sock, static_cast<int>(timeoutsec - elapsed));
+ if (res < 0) {
+ throw ResolverException("Reading data from remote nameserver over TCP: " + stringerror());
+ }
+ if (res == 0) {
throw ResolverException("Timeout while reading data from remote nameserver over TCP");
+ }
- numread=recv(d_sock, &d_buf.at(n), bytes-n, 0);
- if(numread<0)
- throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
- if(numread==0)
+ auto received = recv(d_sock, &d_buf.at(bytesRead), bytes - bytesRead, 0);
+ if (received < 0) {
+ throw ResolverException("Reading data from remote nameserver over TCP: " + stringerror());
+ }
+ if (received == 0) {
throw ResolverException("Remote nameserver closed TCP connection");
- n+=numread;
+ }
+ bytesRead += static_cast<uint16_t>(received);
}
}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "bpf-filter.hh"
-#include "iputils.hh"
-#include "dolog.hh"
-
-#ifdef HAVE_EBPF
-
-#include <sys/syscall.h>
-#include <sys/resource.h>
-#include <linux/bpf.h>
-
-#include "ext/libbpf/libbpf.h"
-
-#include "misc.hh"
-
-static __u64 ptr_to_u64(const void *ptr)
-{
- return (__u64) (unsigned long) ptr;
-}
-
-/* these can be static as they are not declared in libbpf.h: */
-static int bpf_pin_map(int descriptor, const std::string& path)
-{
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.bpf_fd = descriptor;
- attr.pathname = ptr_to_u64(path.c_str());
- return syscall(SYS_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
-}
-
-static int bpf_load_pinned_map(const std::string& path)
-{
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.pathname = ptr_to_u64(path.c_str());
- return syscall(SYS_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
-}
-
-static void bpf_check_map_sizes(int descriptor, uint32_t expectedKeySize, uint32_t expectedValueSize)
-{
- struct bpf_map_info info;
- uint32_t info_len = sizeof(info);
- memset(&info, 0, sizeof(info));
-
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.info.bpf_fd = descriptor;
- attr.info.info_len = info_len;
- attr.info.info = ptr_to_u64(&info);
-
- int err = syscall(SYS_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
- if (err != 0) {
- throw std::runtime_error("Error checking the size of eBPF map: " + stringerror());
- }
- if (info_len != sizeof(info)) {
- throw std::runtime_error("Error checking the size of eBPF map: invalid info size returned");
- }
- if (info.key_size != expectedKeySize) {
- throw std::runtime_error("Error checking the size of eBPF map: key size mismatch (" + std::to_string(info.key_size) + " VS " + std::to_string(expectedKeySize) + ")");
- }
- if (info.value_size != expectedValueSize) {
- throw std::runtime_error("Error checking the size of eBPF map: value size mismatch (" + std::to_string(info.value_size) + " VS " + std::to_string(expectedValueSize) + ")");
- }
-}
-
-// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
-static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
- int max_entries, int map_flags)
-{
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.map_type = map_type;
- attr.key_size = key_size;
- attr.value_size = value_size;
- attr.max_entries = max_entries;
- attr.map_flags = map_flags;
- return syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-static int bpf_update_elem(int descriptor, void *key, void *value, unsigned long long flags)
-{
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.map_fd = descriptor;
- attr.key = ptr_to_u64(key);
- attr.value = ptr_to_u64(value);
- attr.flags = flags;
- return syscall(SYS_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
-
-static int bpf_lookup_elem(int descriptor, void *key, void *value)
-{
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.map_fd = descriptor;
- attr.key = ptr_to_u64(key);
- attr.value = ptr_to_u64(value);
- return syscall(SYS_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
-}
-
-static int bpf_delete_elem(int descriptor, void *key)
-{
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.map_fd = descriptor;
- attr.key = ptr_to_u64(key);
- return syscall(SYS_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
-}
-
-static int bpf_get_next_key(int descriptor, void *key, void *next_key)
-{
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.map_fd = descriptor;
- attr.key = ptr_to_u64(key);
- attr.next_key = ptr_to_u64(next_key);
- return syscall(SYS_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
-}
-
-static int bpf_prog_load(enum bpf_prog_type prog_type,
- const struct bpf_insn *insns, size_t prog_len,
- const char *license, int kern_version)
-{
- char log_buf[65535];
- union bpf_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.prog_type = prog_type;
- attr.insns = ptr_to_u64((void *) insns);
- attr.insn_cnt = static_cast<int>(prog_len / sizeof(struct bpf_insn));
- attr.license = ptr_to_u64((void *) license);
- attr.log_buf = ptr_to_u64(log_buf);
- attr.log_size = sizeof(log_buf);
- attr.log_level = 1;
- /* assign one field outside of struct init to make sure any
- * padding is zero initialized
- */
- attr.kern_version = kern_version;
-
- long res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
- if (res == -1) {
- if (errno == ENOSPC) {
- /* not enough space in the log buffer */
- attr.log_level = 0;
- attr.log_size = 0;
- attr.log_buf = ptr_to_u64(nullptr);
- res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
- if (res != -1) {
- return res;
- }
- }
- throw std::runtime_error("Error loading BPF program: (" + stringerror() + "):\n" + std::string(log_buf));
- }
- return res;
-}
-
-struct KeyV6
-{
- uint8_t src[16];
-};
-
-struct QNameKey
-{
- uint8_t qname[255];
-};
-
-struct QNameAndQTypeKey
-{
- uint8_t qname[255];
- uint16_t qtype;
-};
-
-struct QNameValue
-{
- uint64_t counter{0};
- uint16_t qtype{0};
-};
-
-
-BPFFilter::Map::Map(const BPFFilter::MapConfiguration& config, BPFFilter::MapFormat format): d_config(config)
-{
- if (d_config.d_type == BPFFilter::MapType::Filters) {
- /* special case, this is a map of eBPF programs */
- d_fd = FDWrapper(bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(uint32_t), sizeof(uint32_t), d_config.d_maxItems, 0));
- if (d_fd.getHandle() == -1) {
- throw std::runtime_error("Error creating a BPF program map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror());
- }
- }
- else {
- int keySize = 0;
- int valueSize = 0;
- int flags = 0;
- bpf_map_type type = BPF_MAP_TYPE_HASH;
- if (format == MapFormat::Legacy) {
- switch (d_config.d_type) {
- case MapType::IPv4:
- keySize = sizeof(uint32_t);
- valueSize = sizeof(uint64_t);
- break;
- case MapType::IPv6:
- keySize = sizeof(KeyV6);
- valueSize = sizeof(uint64_t);
- break;
- case MapType::QNames:
- keySize = sizeof(QNameKey);
- valueSize = sizeof(QNameValue);
- break;
- default:
- throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)) + " for legacy eBPF, perhaps you are trying to use an external program instead?");
- }
- }
- else {
- switch (d_config.d_type) {
- case MapType::IPv4:
- keySize = sizeof(uint32_t);
- valueSize = sizeof(CounterAndActionValue);
- break;
- case MapType::IPv6:
- keySize = sizeof(KeyV6);
- valueSize = sizeof(CounterAndActionValue);
- break;
- case MapType::CIDR4:
- keySize = sizeof(CIDR4);
- valueSize = sizeof(CounterAndActionValue);
- flags = BPF_F_NO_PREALLOC;
- type = BPF_MAP_TYPE_LPM_TRIE;
- break;
- case MapType::CIDR6:
- keySize = sizeof(CIDR6);
- valueSize = sizeof(CounterAndActionValue);
- flags = BPF_F_NO_PREALLOC;
- type = BPF_MAP_TYPE_LPM_TRIE;
- break;
- case MapType::QNames:
- keySize = sizeof(QNameAndQTypeKey);
- valueSize = sizeof(CounterAndActionValue);
- break;
- default:
- throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
- }
- }
-
- if (!d_config.d_pinnedPath.empty()) {
- /* try to load */
- d_fd = FDWrapper(bpf_load_pinned_map(d_config.d_pinnedPath));
- if (d_fd.getHandle() != -1) {
- /* sanity checks: key and value size */
- bpf_check_map_sizes(d_fd.getHandle(), keySize, valueSize);
- switch (d_config.d_type) {
- case MapType::IPv4: {
- uint32_t key = 0;
- while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
- ++d_count;
- }
- break;
- }
- case MapType::IPv6: {
- KeyV6 key;
- memset(&key, 0, sizeof(key));
- while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
- ++d_count;
- }
- break;
- }
- case MapType::CIDR4: {
- CIDR4 key;
- memset(&key, 0, sizeof(key));
- while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
- ++d_count;
- }
- break;
- }
- case MapType::CIDR6: {
- CIDR6 key;
- memset(&key, 0, sizeof(key));
- while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
- ++d_count;
- }
- break;
- }
- case MapType::QNames: {
- if (format == MapFormat::Legacy) {
- QNameKey key;
- memset(&key, 0, sizeof(key));
- while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
- ++d_count;
- }
- }
- else {
- QNameAndQTypeKey key;
- memset(&key, 0, sizeof(key));
- while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
- ++d_count;
- }
- }
- break;
- }
-
- default:
- throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
- }
- }
- }
-
- if (d_fd.getHandle() == -1) {
- d_fd = FDWrapper(bpf_create_map(type, keySize, valueSize, static_cast<int>(d_config.d_maxItems), flags));
- if (d_fd.getHandle() == -1) {
- throw std::runtime_error("Error creating a BPF map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror());
- }
-
- if (!d_config.d_pinnedPath.empty()) {
- if (bpf_pin_map(d_fd.getHandle(), d_config.d_pinnedPath) != 0) {
- throw std::runtime_error("Unable to pin map to path '" + d_config.d_pinnedPath + "': " + stringerror());
- }
- }
- }
- }
-}
-
-static FDWrapper loadProgram(const struct bpf_insn* filter, size_t filterSize)
-{
- auto descriptor = FDWrapper(bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER,
- filter,
- filterSize,
- "GPL",
- 0));
- if (descriptor.getHandle() == -1) {
- throw std::runtime_error("error loading BPF filter: " + stringerror());
- }
- return descriptor;
-}
-
-
-BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external) :
- d_mapFormat(format), d_external(external)
-{
- if (d_mapFormat != BPFFilter::MapFormat::Legacy && !d_external) {
- throw std::runtime_error("Unsupported eBPF map format, the current internal implemenation only supports the legacy format");
- }
-
- struct rlimit old_limit;
- if (getrlimit(RLIMIT_MEMLOCK, &old_limit) != 0) {
- throw std::runtime_error("Unable to get memory lock limit: " + stringerror());
- }
-
- const rlim_t new_limit_size = 1024 * 1024;
-
- /* Check if the current soft memlock limit is at least the limit */
- if (old_limit.rlim_cur < new_limit_size) {
- infolog("The current limit of locked memory (soft: %d, hard: %d) is too low for eBPF, trying to raise it to %d", old_limit.rlim_cur, old_limit.rlim_max, new_limit_size);
-
- struct rlimit new_limit;
- new_limit.rlim_cur = new_limit_size;
- new_limit.rlim_max = new_limit_size;
-
- if (setrlimit(RLIMIT_MEMLOCK, &new_limit) != 0) {
- warnlog("Unable to raise the maximum amount of locked memory for eBPF from %d to %d, consider raising RLIMIT_MEMLOCK or setting LimitMEMLOCK in the systemd unit: %d", old_limit.rlim_cur, new_limit.rlim_cur, stringerror());
- }
- }
-
- auto maps = d_maps.lock();
-
- maps->d_v4 = BPFFilter::Map(configs["ipv4"], d_mapFormat);
- maps->d_v6 = BPFFilter::Map(configs["ipv6"], d_mapFormat);
- maps->d_qnames = BPFFilter::Map(configs["qnames"], d_mapFormat);
-
- if (d_mapFormat != BPFFilter::MapFormat::Legacy) {
- maps->d_cidr4 = BPFFilter::Map(configs["cidr4"], d_mapFormat);
- maps->d_cidr6 = BPFFilter::Map(configs["cidr6"], d_mapFormat);
- }
-
- if (!external) {
- BPFFilter::MapConfiguration filters;
- filters.d_maxItems = 1;
- filters.d_type = BPFFilter::MapType::Filters;
- maps->d_filters = BPFFilter::Map(filters, d_mapFormat);
-
- const struct bpf_insn main_filter[] = {
-#include "bpf-filter.main.ebpf"
- };
-
- const struct bpf_insn qname_filter[] = {
-#include "bpf-filter.qname.ebpf"
- };
-
- try {
- d_mainfilter = loadProgram(main_filter,
- sizeof(main_filter));
- }
- catch (const std::exception& e) {
- throw std::runtime_error("Error load the main eBPF filter: " + std::string(e.what()));
- }
-
- try {
- d_qnamefilter = loadProgram(qname_filter,
- sizeof(qname_filter));
- }
- catch (const std::exception& e) {
- throw std::runtime_error("Error load the qname eBPF filter: " + std::string(e.what()));
- }
-
- uint32_t key = 0;
- int qnamefd = d_qnamefilter.getHandle();
- int res = bpf_update_elem(maps->d_filters.d_fd.getHandle(), &key, &qnamefd, BPF_ANY);
- if (res != 0) {
- throw std::runtime_error("Error updating BPF filters map: " + stringerror());
- }
- }
-}
-
-void BPFFilter::addSocket(int sock)
-{
- int descriptor = d_mainfilter.getHandle();
- int res = setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &descriptor, sizeof(descriptor));
-
- if (res != 0) {
- throw std::runtime_error("Error attaching BPF filter to this socket: " + stringerror());
- }
-}
-
-void BPFFilter::removeSocket(int sock)
-{
- int descriptor = d_mainfilter.getHandle();
- int res = setsockopt(sock, SOL_SOCKET, SO_DETACH_BPF, &descriptor, sizeof(descriptor));
-
- if (res != 0) {
- throw std::runtime_error("Error detaching BPF filter from this socket: " + stringerror());
- }
-}
-
-void BPFFilter::block(const ComboAddress& addr, BPFFilter::MatchAction action)
-{
- CounterAndActionValue value;
- value.counter = 0;
- value.action = action;
-
- int res = 0;
- if (addr.isIPv4()) {
- uint32_t key = htonl(addr.sin4.sin_addr.s_addr);
- auto maps = d_maps.lock();
- auto& map = maps->d_v4;
- if (map.d_count >= map.d_config.d_maxItems) {
- throw std::runtime_error("Table full when trying to block " + addr.toString());
- }
-
- res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
- if (res != -1) {
- throw std::runtime_error("Trying to block an already blocked address: " + addr.toString());
- }
-
- res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
- if (res == 0) {
- ++map.d_count;
- }
- }
- else if (addr.isIPv6()) {
- uint8_t key[16];
- static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
- for (size_t idx = 0; idx < sizeof(key); idx++) {
- key[idx] = addr.sin6.sin6_addr.s6_addr[idx];
- }
-
- auto maps = d_maps.lock();
- auto& map = maps->d_v6;
- if (map.d_count >= map.d_config.d_maxItems) {
- throw std::runtime_error("Table full when trying to block " + addr.toString());
- }
-
- res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
- if (res != -1) {
- throw std::runtime_error("Trying to block an already blocked address: " + addr.toString());
- }
-
- res = bpf_update_elem(map.d_fd.getHandle(), key, &value, BPF_NOEXIST);
- if (res == 0) {
- map.d_count++;
- }
- }
-
- if (res != 0) {
- throw std::runtime_error("Error adding blocked address " + addr.toString() + ": " + stringerror());
- }
-}
-
-void BPFFilter::unblock(const ComboAddress& addr)
-{
- int res = 0;
- if (addr.isIPv4()) {
- uint32_t key = htonl(addr.sin4.sin_addr.s_addr);
- auto maps = d_maps.lock();
- auto& map = maps->d_v4;
- res = bpf_delete_elem(map.d_fd.getHandle(), &key);
- if (res == 0) {
- --map.d_count;
- }
- }
- else if (addr.isIPv6()) {
- uint8_t key[16];
- static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
- for (size_t idx = 0; idx < sizeof(key); idx++) {
- key[idx] = addr.sin6.sin6_addr.s6_addr[idx];
- }
-
- auto maps = d_maps.lock();
- auto& map = maps->d_v6;
- res = bpf_delete_elem(map.d_fd.getHandle(), key);
- if (res == 0) {
- --map.d_count;
- }
- }
-
- if (res != 0) {
- throw std::runtime_error("Error removing blocked address " + addr.toString() + ": " + stringerror());
- }
-}
-
-void BPFFilter::addRangeRule(const Netmask& addr, bool force, BPFFilter::MatchAction action)
-{
- CounterAndActionValue value;
-
- int res = 0;
- if (addr.isIPv4()) {
- CIDR4 key(addr);
- auto maps = d_maps.lock();
- auto& map = maps->d_cidr4;
- if (map.d_fd.getHandle() == -1) {
- throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
- }
- if (map.d_count >= map.d_config.d_maxItems) {
- throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
- }
-
- res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
- if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
- throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
- }
-
- value.counter = 0;
- value.action = action;
-
- res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, force ? BPF_ANY : BPF_NOEXIST);
- if (res == 0) {
- ++map.d_count;
- }
- }
- else if (addr.isIPv6()) {
- CIDR6 key(addr);
-
- auto maps = d_maps.lock();
- auto& map = maps->d_cidr6;
- if (map.d_fd.getHandle() == -1) {
- throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
- }
- if (map.d_count >= map.d_config.d_maxItems) {
- throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
- }
-
- res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
- if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
- throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
- }
-
- value.counter = 0;
- value.action = action;
-
- res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
- if (res == 0) {
- map.d_count++;
- }
- }
-
- if (res != 0) {
- throw std::runtime_error("Error adding this rule: " + addr.toString() + ": " + stringerror());
- }
-}
-
-void BPFFilter::rmRangeRule(const Netmask& addr)
-{
- int res = 0;
- CounterAndActionValue value;
- value.counter = 0;
- value.action = MatchAction::Pass;
- if (addr.isIPv4()) {
- CIDR4 key(addr);
- auto maps = d_maps.lock();
- auto& map = maps->d_cidr4;
- if (map.d_fd.getHandle() == -1) {
- throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
- }
- res = bpf_delete_elem(map.d_fd.getHandle(), &key);
- if (res == 0) {
- --map.d_count;
- }
- else {
- throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
- }
- }
- else if (addr.isIPv6()) {
- CIDR6 key(addr);
-
- auto maps = d_maps.lock();
- auto& map = maps->d_cidr6;
- if (map.d_fd.getHandle() == -1) {
- throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
- }
- res = bpf_delete_elem(map.d_fd.getHandle(), &key);
- if (res == 0) {
- --map.d_count;
- }
- else {
- throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
- }
- }
-
- if (res != 0) {
- throw std::runtime_error("Error removing this rule: " + addr.toString() + ": " + stringerror());
- }
-}
-
-void BPFFilter::block(const DNSName& qname, BPFFilter::MatchAction action, uint16_t qtype)
-{
- CounterAndActionValue cadvalue;
- QNameValue qvalue;
- void* value = nullptr;
-
- if (d_external) {
- cadvalue.counter = 0;
- cadvalue.action = action;
- value = &cadvalue;
- }
- else {
- qvalue.counter = 0;
- qvalue.qtype = qtype;
- value = &qvalue;
- }
-
- QNameAndQTypeKey key;
- memset(&key, 0, sizeof(key));
-
- std::string keyStr = qname.toDNSStringLC();
- if (keyStr.size() > sizeof(key.qname)) {
- throw std::runtime_error("Invalid QName to block " + qname.toLogString());
- }
- memcpy(key.qname, keyStr.c_str(), keyStr.size());
- key.qtype = qtype;
-
- {
- auto maps = d_maps.lock();
- auto& map = maps->d_qnames;
- if (map.d_count >= map.d_config.d_maxItems) {
- throw std::runtime_error("Table full when trying to block " + qname.toLogString());
- }
-
- int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, value);
- if (res != -1) {
- throw std::runtime_error("Trying to block an already blocked qname: " + qname.toLogString());
- }
- res = bpf_update_elem(map.d_fd.getHandle(), &key, value, BPF_NOEXIST);
- if (res == 0) {
- ++map.d_count;
- }
-
- if (res != 0) {
- throw std::runtime_error("Error adding blocked qname " + qname.toLogString() + ": " + stringerror());
- }
- }
-}
-
-void BPFFilter::unblock(const DNSName& qname, uint16_t qtype)
-{
- QNameAndQTypeKey key;
- memset(&key, 0, sizeof(key));
- std::string keyStr = qname.toDNSStringLC();
-
- if (keyStr.size() > sizeof(key.qname)) {
- throw std::runtime_error("Invalid QName to block " + qname.toLogString());
- }
- memcpy(key.qname, keyStr.c_str(), keyStr.size());
- key.qtype = qtype;
-
- {
- auto maps = d_maps.lock();
- auto& map = maps->d_qnames;
- int res = bpf_delete_elem(map.d_fd.getHandle(), &key);
- if (res == 0) {
- --map.d_count;
- }
- else {
- throw std::runtime_error("Error removing qname address " + qname.toLogString() + ": " + stringerror());
- }
- }
-}
-
-std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats()
-{
- std::vector<std::pair<ComboAddress, uint64_t> > result;
- {
- auto maps = d_maps.lock();
- result.reserve(maps->d_v4.d_count + maps->d_v6.d_count);
- }
-
- sockaddr_in v4Addr{};
- memset(&v4Addr, 0, sizeof(v4Addr));
- v4Addr.sin_family = AF_INET;
-
- uint32_t v4Key = 0;
- uint32_t nextV4Key{};
- CounterAndActionValue value{};
-
- std::array<uint8_t, 16> v6Key{};
- std::array<uint8_t, 16> nextV6Key{};
- sockaddr_in6 v6Addr{};
- memset(&v6Addr, 0, sizeof(v6Addr));
- v6Addr.sin6_family = AF_INET6;
-
- static_assert(sizeof(v6Addr.sin6_addr.s6_addr) == v6Key.size(), "POSIX mandates s6_addr to be an array of 16 uint8_t");
- memset(&v6Key, 0, sizeof(v6Key));
-
- auto maps = d_maps.lock();
-
- {
- auto& map = maps->d_v4;
- int res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key);
-
- while (res == 0) {
- v4Key = nextV4Key;
- if (bpf_lookup_elem(map.d_fd.getHandle(), &v4Key, &value) == 0) {
- v4Addr.sin_addr.s_addr = ntohl(v4Key);
- result.emplace_back(ComboAddress(&v4Addr), value.counter);
- }
-
- res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key);
- }
- }
-
- {
- auto& map = maps->d_v6;
- int res = bpf_get_next_key(map.d_fd.getHandle(), v6Key.data(), nextV6Key.data());
-
- while (res == 0) {
- if (bpf_lookup_elem(map.d_fd.getHandle(), nextV6Key.data(), &value) == 0) {
- memcpy(&v6Addr.sin6_addr.s6_addr, nextV6Key.data(), nextV6Key.size());
-
- result.emplace_back(ComboAddress(&v6Addr), value.counter);
- }
-
- res = bpf_get_next_key(map.d_fd.getHandle(), nextV6Key.data(), nextV6Key.data());
- }
- }
-
- return result;
-}
-
-std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule()
-{
- CIDR4 cidr4[2];
- CIDR6 cidr6[2];
- std::vector<std::pair<Netmask, CounterAndActionValue>> result;
-
- sockaddr_in v4Addr;
- sockaddr_in6 v6Addr;
- CounterAndActionValue value;
-
- memset(cidr4, 0, sizeof(cidr4));
- memset(cidr6, 0, sizeof(cidr6));
- memset(&v4Addr, 0, sizeof(v4Addr));
- memset(&v6Addr, 0, sizeof(v6Addr));
- v4Addr.sin_family = AF_INET;
- v6Addr.sin6_family = AF_INET6;
- auto maps = d_maps.lock();
- result.reserve(maps->d_cidr4.d_count + maps->d_cidr6.d_count);
- {
- auto& map = maps->d_cidr4;
- int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[0], &cidr4[1]);
- while (res == 0) {
- if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr4[1], &value) == 0) {
- v4Addr.sin_addr.s_addr = cidr4[1].addr.s_addr;
- result.emplace_back(Netmask(&v4Addr, cidr4[1].cidr), value);
- }
-
- res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[1], &cidr4[1]);
- }
- }
-
- {
- auto& map = maps->d_cidr6;
- int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[0], &cidr6[1]);
- while (res == 0) {
- if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr6[1], &value) == 0) {
- v6Addr.sin6_addr = cidr6[1].addr;
- result.emplace_back(Netmask(&v6Addr, cidr6[1].cidr), value);
- }
-
- res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[1], &cidr6[1]);
- }
- }
- return result;
-}
-
-std::vector<std::tuple<DNSName, uint16_t, uint64_t> > BPFFilter::getQNameStats()
-{
- std::vector<std::tuple<DNSName, uint16_t, uint64_t> > result;
-
- if (d_mapFormat == MapFormat::Legacy) {
- QNameKey key = { { 0 } };
- QNameKey nextKey = { { 0 } };
- QNameValue value;
-
- auto maps = d_maps.lock();
- auto& map = maps->d_qnames;
- result.reserve(map.d_count);
- int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey);
-
- while (res == 0) {
- if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
- nextKey.qname[sizeof(nextKey.qname) - 1 ] = '\0';
- result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), value.qtype, value.counter);
- }
-
- res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
- }
- }
- else {
- QNameAndQTypeKey key;
- QNameAndQTypeKey nextKey;
- memset(&key, 0, sizeof(key));
- memset(&nextKey, 0, sizeof(nextKey));
- CounterAndActionValue value;
-
- auto maps = d_maps.lock();
- auto& map = maps->d_qnames;
- result.reserve(map.d_count);
- int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey);
-
- while (res == 0) {
- if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
- nextKey.qname[sizeof(nextKey.qname) - 1 ] = '\0';
- result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), key.qtype, value.counter);
- }
-
- res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
- }
- }
-
- return result;
-}
-
-uint64_t BPFFilter::getHits(const ComboAddress& requestor)
-{
- CounterAndActionValue counter;
-
- if (requestor.isIPv4()) {
- uint32_t key = htonl(requestor.sin4.sin_addr.s_addr);
-
- auto maps = d_maps.lock();
- auto& map = maps->d_v4;
- int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter);
- if (res == 0) {
- return counter.counter;
- }
- }
- else if (requestor.isIPv6()) {
- uint8_t key[16];
- static_assert(sizeof(requestor.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
- for (size_t idx = 0; idx < sizeof(key); idx++) {
- key[idx] = requestor.sin6.sin6_addr.s6_addr[idx];
- }
-
- auto maps = d_maps.lock();
- auto& map = maps->d_v6;
- int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter);
- if (res == 0) {
- return counter.counter;
- }
- }
-
- return 0;
-}
-
-#else
-
-BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external)
-{
-}
-
-void BPFFilter::addSocket(int)
-{
- throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::removeSocket(int)
-{
- throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::block(const ComboAddress&, BPFFilter::MatchAction)
-{
- throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::unblock(const ComboAddress&)
-{
- throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::block(const DNSName&, BPFFilter::MatchAction, uint16_t)
-{
- throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::unblock(const DNSName&, uint16_t)
-{
- throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::addRangeRule(const Netmask&, bool, BPFFilter::MatchAction)
-{
- throw std::runtime_error("eBPF support not enabled");
-}
-void BPFFilter::rmRangeRule(const Netmask&)
-{
- throw std::runtime_error("eBPF support not enabled");
-}
-
-std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule(){
- std::vector<std::pair<Netmask, CounterAndActionValue>> result;
- return result;
-}
-std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats()
-{
- std::vector<std::pair<ComboAddress, uint64_t> > result;
- return result;
-}
-
-std::vector<std::tuple<DNSName, uint16_t, uint64_t> > BPFFilter::getQNameStats()
-{
- std::vector<std::tuple<DNSName, uint16_t, uint64_t> > result;
- return result;
-}
-
-uint64_t BPFFilter::getHits(const ComboAddress&)
-{
- return 0;
-}
-#endif /* HAVE_EBPF */
-
-bool BPFFilter::supportsMatchAction(MatchAction action) const
-{
-#ifdef HAVE_EBPF
- if (action == BPFFilter::MatchAction::Drop) {
- return true;
- }
- return d_mapFormat == BPFFilter::MapFormat::WithActions;
-#endif /* HAVE_EBPF */
- return false;
-}
-
-bool BPFFilter::isExternal() const
-{
-#ifdef HAVE_EBPF
- return d_external;
-#endif /* HAVE_EBPF */
- return false;
-}
+++ /dev/null
-
-#include <net/sock.h>
-#include <linux/types.h>
-#include <uapi/linux/tcp.h>
-#include <uapi/linux/udp.h>
-#include <uapi/linux/ip.h>
-#include <uapi/linux/ipv6.h>
-#include <bcc/proto.h>
-
-struct dnsheader {
- unsigned id :16; /* query identification number */
-#if BYTE_ORDER == BIG_ENDIAN
- /* fields in third byte */
- unsigned qr: 1; /* response flag */
- unsigned opcode: 4; /* purpose of message */
- unsigned aa: 1; /* authoritative answer */
- unsigned tc: 1; /* truncated message */
- unsigned rd: 1; /* recursion desired */
- /* fields in fourth byte */
- unsigned ra: 1; /* recursion available */
- unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
- unsigned ad: 1; /* authentic data from named */
- unsigned cd: 1; /* checking disabled by resolver */
- unsigned rcode :4; /* response code */
-#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
- /* fields in third byte */
- unsigned rd :1; /* recursion desired */
- unsigned tc :1; /* truncated message */
- unsigned aa :1; /* authoritative answer */
- unsigned opcode :4; /* purpose of message */
- unsigned qr :1; /* response flag */
- /* fields in fourth byte */
- unsigned rcode :4; /* response code */
- unsigned cd: 1; /* checking disabled by resolver */
- unsigned ad: 1; /* authentic data from named */
- unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
- unsigned ra :1; /* recursion available */
-#endif
- /* remaining bytes */
- unsigned qdcount :16; /* number of question entries */
- unsigned ancount :16; /* number of answer entries */
- unsigned nscount :16; /* number of authority entries */
- unsigned arcount :16; /* number of resource entries */
-};
-
-struct QNameKey
-{
- uint8_t qname[255];
-};
-
-struct KeyV6
-{
- uint8_t src[16];
-};
-
-struct QNameValue
-{
- u64 counter;
- u16 qtype;
-};
-
-BPF_TABLE("hash", u32, u64, v4filter, 1024);
-BPF_TABLE("hash", struct KeyV6, u64, v6filter, 1024);
-BPF_TABLE("hash", struct QNameKey, struct QNameValue, qnamefilter, 1024);
-BPF_TABLE("prog", int, int, progsarray, 1);
-
-int bpf_qname_filter(struct __sk_buff *skb)
-{
- uint32_t qname_off = skb->cb[0];
- ssize_t labellen = skb->cb[3];
- size_t idx = 2;
- struct QNameKey qkey = { 0 };
- u32 val = skb->cb[1];
- if (val) {
- qkey.qname[0] = val;
- }
- val = skb->cb[2];
- if (val) {
- qkey.qname[1] = val;
- }
- uint8_t temp;
-
-#define FILL_ONE_KEY \
- temp = load_byte(skb, qname_off + idx); \
- labellen--; \
- if (labellen < 0) { \
- labellen = temp; \
- if (labellen == 0) { \
- goto end; \
- } \
- } else if (temp >= 'A' && temp <= 'Z') { \
- temp += ('a' - 'A'); \
- } \
- qkey.qname[idx] = temp; \
- idx++;
-
- /* 2 - 52 */
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- /* 52 - 102 */
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- /* 102 - 152 */
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- /* 152 - 202 */
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- /* 202 - 252 */
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- /* 252 - 254 */
- FILL_ONE_KEY
- FILL_ONE_KEY
-
- /* the only value that makes sense for
- qkey.qname[255] is 0, and it's already
- there */
- end:
-
- {
- idx++;
- u16 qtype = load_half(skb, (qname_off + idx));
-
- struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
- if (qvalue &&
- (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
- __sync_fetch_and_add(&qvalue->counter, 1);
- return 0;
- }
- }
-
- return 2147483647;
-}
-
-int bpf_dns_filter(struct __sk_buff *skb) {
- u8 ip_proto;
- int proto_off;
- /* nh_off will contain a negative offset, used in BPF to get access to
- the MAC/network layers, as positive values are used to get access to
- the transport layer */
- int nh_off = BPF_LL_OFF + ETH_HLEN;
-
- if (skb->protocol == ntohs(0x0800)) {
- u32 key;
- int off = nh_off + offsetof(struct iphdr, saddr);
- key = load_word(skb, off);
-
- u64* counter = v4filter.lookup(&key);
- if (counter) {
- __sync_fetch_and_add(counter, 1);
- return 0;
- }
-
- ip_proto = load_byte(skb, nh_off + offsetof(struct iphdr, protocol));
- proto_off = nh_off + sizeof(struct iphdr);
- }
- else if (skb->protocol == ntohs(0x86DD)) {
- struct KeyV6 key;
- int off = nh_off + offsetof(struct ipv6hdr, saddr);
- key.src[0] = load_byte(skb, off++);
- key.src[1] = load_byte(skb, off++);
- key.src[2] = load_byte(skb, off++);
- key.src[3] = load_byte(skb, off++);
- key.src[4] = load_byte(skb, off++);
- key.src[5] = load_byte(skb, off++);
- key.src[6] = load_byte(skb, off++);
- key.src[7] = load_byte(skb, off++);
- key.src[8] = load_byte(skb, off++);
- key.src[9] = load_byte(skb, off++);
- key.src[10] = load_byte(skb, off++);
- key.src[11] = load_byte(skb, off++);
- key.src[12] = load_byte(skb, off++);
- key.src[13] = load_byte(skb, off++);
- key.src[14] = load_byte(skb, off++);
- key.src[15] = load_byte(skb, off++);
-
- u64* counter = v6filter.lookup(&key);
- if (counter) {
- __sync_fetch_and_add(counter, 1);
- return 0;
- }
-
- ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
- proto_off = nh_off + sizeof(struct ipv6hdr);
- }
- else {
- /* neither IPv4 not IPv6, well */
- return 2147483647;
- }
-
- /* allow TCP */
- if (ip_proto == IPPROTO_TCP) {
- return 2147483647;
- }
-
- struct QNameKey qkey = { 0 };
- /* switch to positive offsets here, as we have seen some issues
- when accessing the content of the transport layer with negative offsets
- https://github.com/PowerDNS/pdns/issues/9626 */
- int dns_off = sizeof(struct udphdr);
- int qname_off = dns_off + sizeof(struct dnsheader);
- skb->cb[0] = (uint32_t) qname_off;
- u16 qtype;
-
- uint8_t temp = load_byte(skb, qname_off);
- if (temp > 63) {
- return 0;
- }
-
- if (temp == 0) {
- /* root, nothing else to see */
- qtype = load_half(skb, (qname_off + 1));
-
- struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
- if (qvalue &&
- (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
- __sync_fetch_and_add(&qvalue->counter, 1);
- return 0;
- }
- return 2147483647;
- }
-
- ssize_t labellen = temp;
- skb->cb[1] = temp;
- qkey.qname[0] = temp;
-
- temp = load_byte(skb, qname_off + 1);
- labellen--;
- if (temp >= 'A' && temp <= 'Z') {
- temp += ('a' - 'A');
- }
- skb->cb[2] = temp;
- skb->cb[3] = labellen;
- progsarray.call(skb, 0);
-
- return 2147483647;
-}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-#include "config.h"
-
-#include <unordered_map>
-
-#include "iputils.hh"
-#include "lock.hh"
-#include <netinet/in.h>
-#include <stdexcept>
-
-class BPFFilter
-{
-public:
- enum class MapType : uint8_t {
- IPv4,
- IPv6,
- QNames,
- Filters,
- CIDR4,
- CIDR6
- };
-
- enum class MapFormat : uint8_t {
- Legacy = 0,
- WithActions = 1
- };
-
- enum class MatchAction : uint8_t {
- Pass = 0,
- Drop = 1,
- Truncate = 2
- };
- static std::string toString(MatchAction s) noexcept
- {
- switch (s) {
- case MatchAction::Pass:
- return "Pass";
- case MatchAction::Drop:
- return "Drop";
- case MatchAction::Truncate:
- return "Truncate";
- }
- return "Unknown";
- }
-
- struct MapConfiguration
- {
- std::string d_pinnedPath;
- uint32_t d_maxItems{0};
- MapType d_type;
- };
-
- struct CounterAndActionValue
- {
- uint64_t counter{0};
- BPFFilter::MatchAction action{BPFFilter::MatchAction::Pass};
- };
-
-
- BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external);
- BPFFilter(const BPFFilter&) = delete;
- BPFFilter(BPFFilter&&) = delete;
- BPFFilter& operator=(const BPFFilter&) = delete;
- BPFFilter& operator=(BPFFilter&&) = delete;
-
- void addSocket(int sock);
- void removeSocket(int sock);
- void block(const ComboAddress& addr, MatchAction action);
- void addRangeRule(const Netmask& address, bool force, BPFFilter::MatchAction action);
- void block(const DNSName& qname, MatchAction action, uint16_t qtype=255);
- void unblock(const ComboAddress& addr);
- void rmRangeRule(const Netmask& address);
- void unblock(const DNSName& qname, uint16_t qtype=255);
-
- std::vector<std::pair<ComboAddress, uint64_t> > getAddrStats();
- std::vector<std::pair<Netmask, CounterAndActionValue>> getRangeRule();
- std::vector<std::tuple<DNSName, uint16_t, uint64_t> > getQNameStats();
-
- uint64_t getHits(const ComboAddress& requestor);
-
- bool supportsMatchAction(MatchAction action) const;
- bool isExternal() const;
-
-private:
-#ifdef HAVE_EBPF
- struct Map
- {
- Map()
- {
- }
- Map(const MapConfiguration&, MapFormat);
- MapConfiguration d_config;
- uint32_t d_count{0};
- FDWrapper d_fd;
- };
-
- struct Maps
- {
- Map d_v4;
- Map d_v6;
- Map d_cidr4;
- Map d_cidr6;
- Map d_qnames;
- /* The qname filter program held in d_qnamefilter is
- stored in an eBPF map, so we can call it from the
- main filter. This is the only entry in that map. */
- Map d_filters;
- };
-
- LockGuarded<Maps> d_maps;
-
- /* main eBPF program */
- FDWrapper d_mainfilter;
- /* qname filtering program */
- FDWrapper d_qnamefilter;
- struct CIDR4
- {
- uint32_t cidr;
- struct in_addr addr;
- explicit CIDR4(Netmask address)
- {
- if (!address.isIPv4()) {
- throw std::runtime_error("ComboAddress is invalid");
- }
- addr = address.getNetwork().sin4.sin_addr;
- cidr = address.getBits();
- }
- CIDR4() = default;
- };
- struct CIDR6
- {
- uint32_t cidr;
- struct in6_addr addr;
- CIDR6(Netmask address)
- {
- if (!address.isIPv6()) {
- throw std::runtime_error("ComboAddress is invalid");
- }
- addr = address.getNetwork().sin6.sin6_addr;
- cidr = address.getBits();
- }
- CIDR6() = default;
- };
- /* whether the maps are in the 'old' format, which we need
- to keep to prevent going over the 4k instructions per eBPF
- program limit in kernels < 5.2, as well as the complexity limit:
- - 32k in Linux 3.18
- - 64k in Linux 4.7
- - 96k in Linux 4.12
- - 128k in Linux 4.14,
- - 1M in Linux 5.2 */
- MapFormat d_mapFormat;
-
- /* whether the filter is internal, using our own eBPF programs,
- or external where we only update the maps but the filtering is
- done by an external program. */
- bool d_external;
-#endif /* HAVE_EBPF */
-};
-using CounterAndActionValue = BPFFilter::CounterAndActionValue;
+++ /dev/null
-/* generated from the bpf_dns_filter() function in bpf-filter.ebpf.src */
-BPF_MOV64_REG(BPF_REG_6,BPF_REG_1),
-BPF_MOV64_IMM(BPF_REG_7,2147483647),
-BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,16),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,ntohs(0x86dd),11),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_1,ntohs(0x0800),109),
-BPF_LD_ABS(BPF_W,-2097126),
-BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_0,-256),
-BPF_LD_MAP_FD(BPF_REG_1,maps->d_v4.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_0,0,98),
-BPF_LD_ABS(BPF_B,-2097129),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,39),
-BPF_LD_ABS(BPF_B,-2097130),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-256),
-BPF_LD_ABS(BPF_B,-2097129),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-255),
-BPF_LD_ABS(BPF_B,-2097128),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-254),
-BPF_LD_ABS(BPF_B,-2097127),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-253),
-BPF_LD_ABS(BPF_B,-2097126),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-252),
-BPF_LD_ABS(BPF_B,-2097125),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-251),
-BPF_LD_ABS(BPF_B,-2097124),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-250),
-BPF_LD_ABS(BPF_B,-2097123),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-249),
-BPF_LD_ABS(BPF_B,-2097122),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-248),
-BPF_LD_ABS(BPF_B,-2097121),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-247),
-BPF_LD_ABS(BPF_B,-2097120),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-246),
-BPF_LD_ABS(BPF_B,-2097119),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-245),
-BPF_LD_ABS(BPF_B,-2097118),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-244),
-BPF_LD_ABS(BPF_B,-2097117),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-243),
-BPF_LD_ABS(BPF_B,-2097116),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-242),
-BPF_LD_ABS(BPF_B,-2097115),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-241),
-BPF_LD_MAP_FD(BPF_REG_1,maps->d_v6.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_0,0,58),
-BPF_LD_ABS(BPF_B,-2097132),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_0,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,6,58),
-BPF_MOV64_IMM(BPF_REG_1,0),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-2),
-BPF_STX_MEM(BPF_H,BPF_REG_10,BPF_REG_1,-4),
-BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_1,-8),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-16),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-24),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-32),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-40),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-48),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-56),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-64),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-72),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-80),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-88),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-96),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-104),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-112),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-120),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-128),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-136),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-144),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-152),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-160),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-168),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-176),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-184),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-192),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-200),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-208),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-216),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-224),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-232),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-240),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-248),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-256),
-BPF_MOV64_IMM(BPF_REG_1,20),
-BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_1,48),
-BPF_LD_ABS(BPF_B,20),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_MOV64_IMM(BPF_REG_7,0),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_8,63,17),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_8,0,18),
-BPF_LD_ABS(BPF_H,21),
-BPF_MOV64_REG(BPF_REG_6,BPF_REG_0),
-BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
-BPF_MOV64_IMM(BPF_REG_7,2147483647),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,0,7),
-BPF_LDX_MEM(BPF_H,BPF_REG_1,BPF_REG_0,8),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,255,2),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_6,65535),
-BPF_JMP_REG(BPF_JNE,BPF_REG_1,BPF_REG_6,3),
-BPF_MOV64_IMM(BPF_REG_1,1),
-BPF_RAW_INSN(BPF_STX|BPF_XADD|BPF_DW,BPF_REG_0,BPF_REG_1,0,0),
-BPF_MOV64_IMM(BPF_REG_7,0),
-BPF_MOV64_REG(BPF_REG_0,BPF_REG_7),
-BPF_EXIT_INSN(),
-BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_8,52),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_8,-256),
-BPF_LD_ABS(BPF_B,21),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-65),
-BPF_ALU64_IMM(BPF_LSH,BPF_REG_2,32),
-BPF_ALU64_IMM(BPF_RSH,BPF_REG_2,32),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,32),
-BPF_MOV64_IMM(BPF_REG_3,26),
-BPF_JMP_REG(BPF_JGT,BPF_REG_3,BPF_REG_2,1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_8,60),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_1,56),
-BPF_LD_MAP_FD(BPF_REG_2,maps->d_filters.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_6),
-BPF_MOV64_IMM(BPF_REG_3,0),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_tail_call),
-BPF_MOV64_IMM(BPF_REG_7,2147483647),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,-25),
+++ /dev/null
-/* generated from the bpf_qname_filter() function in bpf-filter.ebpf.src */
-BPF_MOV64_REG(BPF_REG_6,BPF_REG_1),
-BPF_LDX_MEM(BPF_W,BPF_REG_8,BPF_REG_6,60),
-BPF_LDX_MEM(BPF_W,BPF_REG_7,BPF_REG_6,48),
-BPF_MOV64_IMM(BPF_REG_1,0),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-2),
-BPF_STX_MEM(BPF_H,BPF_REG_10,BPF_REG_1,-4),
-BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_1,-8),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-16),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-24),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-32),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-40),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-48),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-56),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-64),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-72),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-80),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-88),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-96),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-104),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-112),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-120),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-128),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-136),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-144),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-152),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-160),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-168),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-176),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-184),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-192),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-200),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-208),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-216),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-224),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-232),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-240),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-248),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-256),
-BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,52),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,1),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-256),
-BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,56),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,1),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-255),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,2),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_2,0,0),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,3),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,4024),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-254),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,3),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,4),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,4008),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-253),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,4),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,5),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3992),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-252),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,5),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,6),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3976),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-251),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,6),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,7),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3960),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-250),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,7),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,8),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3944),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-249),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,8),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,9),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3928),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-248),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,9),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,10),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3912),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-247),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,10),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,11),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3896),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-246),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,11),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,12),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3880),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-245),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,12),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,13),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3864),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-244),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,13),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,14),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3848),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-243),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,14),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,15),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3832),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-242),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,15),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,16),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3816),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-241),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,16),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,17),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3800),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-240),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,17),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,18),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3784),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-239),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,18),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,19),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3768),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-238),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,19),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,20),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3752),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-237),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,20),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,21),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3736),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-236),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,21),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,22),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3720),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-235),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,22),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,23),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3704),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-234),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,23),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,24),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3688),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-233),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,24),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,25),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3672),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-232),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,25),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,26),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3656),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-231),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,26),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,27),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3640),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-230),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,27),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,28),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3624),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-229),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,28),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,29),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3608),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-228),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,29),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,30),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3592),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-227),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,30),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,31),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3576),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-226),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,31),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,32),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3560),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-225),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,32),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,33),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3544),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-224),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,33),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,34),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3528),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-223),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,34),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,35),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3512),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-222),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,35),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,36),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3496),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-221),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,36),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,37),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3480),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-220),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,37),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,38),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3464),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-219),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,38),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,39),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3448),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-218),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,39),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,40),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3432),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-217),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,40),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,41),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3416),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-216),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,41),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,42),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3400),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-215),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,42),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,43),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3384),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-214),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,43),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,44),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3368),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-213),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,44),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,45),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3352),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-212),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,45),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,46),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3336),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-211),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,46),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,47),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3320),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-210),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,47),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,48),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3304),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-209),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,48),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,49),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3288),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-208),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,49),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,50),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3272),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-207),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,50),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,51),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3256),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-206),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,51),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,52),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3240),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-205),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,52),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,53),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3224),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-204),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,53),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,54),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3208),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-203),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,54),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,55),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3192),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-202),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,55),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,56),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3176),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-201),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,56),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,57),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3160),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-200),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,57),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,58),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3144),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-199),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,58),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,59),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3128),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-198),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,59),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,60),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3112),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-197),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,60),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,61),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3096),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-196),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,61),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,62),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3080),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-195),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,62),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,63),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3064),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-194),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,63),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,64),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3048),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-193),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,64),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,65),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3032),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-192),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,65),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,66),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3016),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-191),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,66),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,67),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3000),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-190),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,67),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,68),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2984),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-189),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,68),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,69),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2968),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-188),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,69),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,70),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2952),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-187),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,70),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,71),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2936),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-186),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,71),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,72),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2920),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-185),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,72),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,73),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2904),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-184),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,73),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,74),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2888),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-183),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,74),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,75),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2872),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-182),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,75),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,76),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2856),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-181),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,76),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,77),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2840),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-180),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,77),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,78),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2824),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-179),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,78),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,79),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2808),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-178),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,79),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,80),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2792),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-177),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,80),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,81),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2776),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-176),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,81),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,82),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2760),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-175),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,82),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,83),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2744),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-174),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,83),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,84),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2728),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-173),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,84),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,85),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2712),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-172),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,85),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,86),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2696),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-171),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,86),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,87),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2680),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-170),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,87),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,88),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2664),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-169),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,88),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,89),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2648),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-168),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,89),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,90),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2632),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-167),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,90),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,91),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2616),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-166),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,91),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,92),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2600),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-165),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,92),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,93),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2584),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-164),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,93),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,94),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2568),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-163),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,94),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,95),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2552),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-162),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,95),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,96),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2536),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-161),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,96),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,97),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2520),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-160),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,97),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,98),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2504),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-159),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,98),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,99),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2488),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-158),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,99),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,100),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2472),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-157),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,100),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,101),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2456),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-156),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,101),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,102),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2440),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-155),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,102),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,103),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2424),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-154),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,103),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,104),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2408),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-153),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,104),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,105),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2392),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-152),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,105),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,106),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2376),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-151),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,106),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,107),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2360),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-150),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,107),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,108),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2344),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-149),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,108),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,109),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2328),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-148),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,109),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,110),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2312),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-147),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,110),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,111),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2296),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-146),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,111),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,112),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2280),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-145),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,112),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,113),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2264),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-144),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,113),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,114),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2248),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-143),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,114),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,115),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2232),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-142),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,115),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,116),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2216),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-141),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,116),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,117),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2200),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-140),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,117),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,118),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2184),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-139),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,118),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,119),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2168),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-138),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,119),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,120),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2152),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-137),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,120),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,121),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2136),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-136),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,121),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,122),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2120),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-135),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,122),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,123),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2104),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-134),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,123),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,124),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2088),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-133),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,124),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,125),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2072),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-132),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,125),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,126),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2056),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-131),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,126),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,127),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2040),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-130),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,127),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,128),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2024),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-129),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,128),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,129),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2008),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-128),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,129),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,130),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1992),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-127),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,130),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,131),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1976),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-126),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,131),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,132),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1960),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-125),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,132),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,133),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1944),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-124),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,133),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,134),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1928),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-123),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,134),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,135),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1912),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-122),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,135),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,136),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1896),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-121),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,136),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,137),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1880),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-120),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,137),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,138),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1864),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-119),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,138),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,139),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1848),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-118),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,139),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,140),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1832),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-117),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,140),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,141),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1816),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-116),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,141),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,142),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1800),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-115),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,142),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,143),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1784),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-114),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,143),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,144),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1768),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-113),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,144),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,145),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1752),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-112),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,145),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,146),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1736),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-111),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,146),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,147),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1720),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-110),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,147),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,148),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1704),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-109),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,148),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,149),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1688),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-108),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,149),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,150),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1672),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-107),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,150),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,151),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1656),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-106),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,151),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,152),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1640),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-105),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,152),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,153),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1624),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-104),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,153),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,154),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1608),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-103),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,154),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,155),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1592),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-102),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,155),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,156),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1576),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-101),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,156),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,157),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1560),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-100),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,157),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,158),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1544),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-99),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,158),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,159),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1528),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-98),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,159),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,160),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1512),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-97),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,160),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,161),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1496),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-96),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,161),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,162),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1480),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-95),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,162),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,163),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1464),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-94),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,163),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,164),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1448),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-93),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,164),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,165),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1432),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-92),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,165),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,166),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1416),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-91),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,166),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,167),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1400),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-90),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,167),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,168),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1384),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-89),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,168),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,169),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1368),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-88),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,169),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,170),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1352),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-87),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,170),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,171),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1336),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-86),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,171),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,172),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1320),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-85),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,172),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,173),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1304),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-84),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,173),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,174),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1288),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-83),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,174),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,175),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1272),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-82),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,175),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,176),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1256),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-81),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,176),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,177),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1240),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-80),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,177),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,178),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1224),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-79),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,178),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,179),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1208),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-78),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,179),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,180),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1192),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-77),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,180),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,181),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1176),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-76),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,181),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,182),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1160),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-75),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,182),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,183),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1144),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-74),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,183),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,184),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1128),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-73),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,184),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,185),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1112),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-72),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,185),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,186),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1096),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-71),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,186),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,187),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1080),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-70),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,187),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,188),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1064),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-69),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,188),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,189),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1048),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-68),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,189),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,190),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1032),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-67),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,190),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,191),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1016),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-66),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,191),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,192),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1000),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-65),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,192),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,193),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,984),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-64),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,193),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,194),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,968),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-63),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,194),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,195),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,952),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-62),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,195),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,196),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,936),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-61),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,196),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,197),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,920),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-60),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,197),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,198),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,904),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-59),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,198),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,199),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,888),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-58),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,199),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,200),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,872),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-57),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,200),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,201),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,856),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-56),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,201),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,202),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,840),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-55),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,202),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,203),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,824),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-54),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,203),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,204),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,808),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-53),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,204),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,205),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,792),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-52),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,205),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,206),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,776),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-51),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,206),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,207),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,760),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-50),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,207),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,208),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,744),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-49),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,208),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,209),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,728),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-48),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,209),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,210),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,712),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-47),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,210),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,211),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,696),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-46),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,211),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,212),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,680),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-45),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,212),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,213),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,664),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-44),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,213),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,214),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,648),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-43),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,214),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,215),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,632),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-42),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,215),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,216),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,616),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-41),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,216),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,217),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,600),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-40),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,217),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,218),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,584),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-39),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,218),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,219),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,568),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-38),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,219),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,220),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,552),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-37),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,220),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,221),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,536),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-36),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,221),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,222),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,520),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-35),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,222),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,223),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,504),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-34),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,223),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,224),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,488),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-33),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,224),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,225),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,472),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-32),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,225),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,226),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,456),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-31),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,226),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,227),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,440),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-30),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,227),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,228),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,424),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-29),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,228),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,229),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,408),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-28),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,229),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,230),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,392),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-27),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,230),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,231),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,376),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-26),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,231),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,232),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,360),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-25),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,232),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,233),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,344),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-24),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,233),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,234),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,328),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-23),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,234),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,235),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,312),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-22),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,235),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,236),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,296),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-21),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,236),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,237),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,280),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-20),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,237),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,238),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,264),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-19),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,238),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,239),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,248),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-18),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,239),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,240),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,232),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-17),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,240),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,241),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,216),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-16),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,241),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,242),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,200),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-15),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,242),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,243),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,184),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-14),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,243),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,244),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,168),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-13),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,244),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,245),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,152),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-12),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,245),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,246),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,136),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-11),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,246),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,247),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,120),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-10),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,247),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,248),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,104),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-9),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,248),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,249),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,88),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-8),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,249),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,250),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,72),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-7),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,250),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,251),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,56),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-6),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,251),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,252),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,40),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-5),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,252),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,253),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,24),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-4),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,253),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,254),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,8),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,5),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-3),
-BPF_MOV64_IMM(BPF_REG_9,255),
-BPF_ALU64_REG(BPF_ADD,BPF_REG_9,BPF_REG_7),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_H,BPF_REG_0,BPF_REG_9,0,0),
-BPF_MOV64_REG(BPF_REG_6,BPF_REG_0),
-BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
-BPF_MOV64_IMM(BPF_REG_1,2147483647),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,0,7),
-BPF_LDX_MEM(BPF_H,BPF_REG_2,BPF_REG_0,8),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_2,255,2),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_6,65535),
-BPF_JMP_REG(BPF_JNE,BPF_REG_6,BPF_REG_2,3),
-BPF_MOV64_IMM(BPF_REG_1,1),
-BPF_RAW_INSN(BPF_STX|BPF_XADD|BPF_DW,BPF_REG_0,BPF_REG_1,0,0),
-BPF_MOV64_IMM(BPF_REG_1,0),
-BPF_MOV64_REG(BPF_REG_0,BPF_REG_1),
-BPF_EXIT_INSN(),
template <typename S, typename T>
void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front)
{
- typedef typename T::template index<S>::type sequence_t;
- sequence_t& sidx = collection.template get<S>();
- typename sequence_t::iterator si = collection.template project<S>(iter);
- if (front)
- sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue
- else
- sidx.relocate(sidx.end(), si); // back
+ auto& sidx = collection.template get<S>();
+ auto siter = collection.template project<S>(iter);
+ if (front) {
+ sidx.relocate(sidx.begin(), siter); // at the beginning of the delete queue
+ }
+ else {
+ sidx.relocate(sidx.end(), siter); // back
+ }
}
template <typename S, typename T>
uint64_t totErased = 0;
time_t now = time(nullptr);
- for (auto& mc : maps) {
- auto map = mc.d_map.write_lock();
+ for (auto& shard : maps) {
+ auto map = shard.d_map.write_lock();
uint64_t lookAt = (map->size() + 9) / 10; // Look at 10% of this shard
uint64_t erased = 0;
{
uint64_t delcount = 0;
- for (auto& mc : maps) {
- auto map = mc.d_map.write_lock();
+ for (auto& shard : maps) {
+ auto map = shard.d_map.write_lock();
delcount += map->size();
map->clear();
}
std::string prefix(match);
prefix.resize(prefix.size() - 1);
DNSName dprefix(prefix);
- for (auto& mc : maps) {
- auto map = mc.d_map.write_lock();
+ for (auto& shard : maps) {
+ auto map = shard.d_map.write_lock();
auto& idx = boost::multi_index::get<N>(*map);
auto iter = idx.lower_bound(dprefix);
auto start = iter;
}
template <typename N, typename T>
-uint64_t purgeExactLockedCollection(T& mc, const DNSName& qname)
+uint64_t purgeExactLockedCollection(T& shard, const DNSName& qname)
{
uint64_t delcount = 0;
- auto map = mc.d_map.write_lock();
+ auto map = shard.d_map.write_lock();
auto& idx = boost::multi_index::get<N>(*map);
auto range = idx.equal_range(qname);
if (range.first != range.second) {
}
template <typename S, typename Index>
-bool lruReplacingInsert(Index& i, const typename Index::value_type& x)
+bool lruReplacingInsert(Index& index, const typename Index::value_type& value)
{
- auto inserted = i.insert(x);
+ auto inserted = index.insert(value);
if (!inserted.second) {
- moveCacheItemToBack<S>(i, inserted.first);
- i.replace(inserted.first, x);
+ moveCacheItemToBack<S>(index, inserted.first);
+ index.replace(inserted.first, value);
return false;
}
return true;
// there can be MANY OF THESE
void CommunicatorClass::retrievalLoopThread()
{
- setThreadName("pdns/comm-retre");
+ setThreadName("pdns/comm-retri");
for (;;) {
d_suck_sem.wait();
SuckRequest sr;
static size_t const pwhash_prefix_size = pwhash_prefix.size();
#endif
-uint64_t const CredentialsHolder::s_defaultWorkFactor{1024U}; /* N */
-uint64_t const CredentialsHolder::s_defaultParallelFactor{1U}; /* p */
-uint64_t const CredentialsHolder::s_defaultBlockSize{8U}; /* r */
-
SensitiveData::SensitiveData(std::string&& data) :
d_data(std::move(data))
{
static bool isHashingAvailable();
static SensitiveData readFromTerminal();
- static uint64_t const s_defaultWorkFactor;
- static uint64_t const s_defaultParallelFactor;
- static uint64_t const s_defaultBlockSize;
+ static uint64_t constexpr s_defaultWorkFactor{1024U}; /* N */
+ static uint64_t constexpr s_defaultParallelFactor{1U}; /* p */
+ static uint64_t constexpr s_defaultBlockSize{8U}; /* r */
private:
SensitiveData d_credentials;
return retval;
}
-void DNSSECKeeper::getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL)
+void DNSSECKeeper::getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL, DNSPacket* packet)
{
if(rrs.empty()) {
return;
DNSZoneRecord dzr;
- db.lookup(QType(QType::RRSIG), !rr.wildcardname.empty() ? rr.wildcardname : rr.dr.d_name, rr.domain_id);
+ db.lookup(QType(QType::RRSIG), !rr.wildcardname.empty() ? rr.wildcardname : rr.dr.d_name, rr.domain_id, packet);
while(db.get(dzr)) {
auto rrsig = getRR<RRSIGRecordContent>(dzr.dr);
if (rrsig->d_type == rr.dr.d_type) {
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "delaypipe.hh"
-#include "misc.hh"
-#include "gettime.hh"
-#include <thread>
-#include "threadname.hh"
-
-template<class T>
-ObjectPipe<T>::ObjectPipe()
-{
- auto [sender, receiver] = pdns::channel::createObjectQueue<T>(pdns::channel::SenderBlockingMode::SenderBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, 0, false);
- d_sender = std::move(sender);
- d_receiver = std::move(receiver);
-}
-
-template<class T>
-void ObjectPipe<T>::close()
-{
- d_sender.close();
-}
-
-template<class T>
-void ObjectPipe<T>::write(T& t)
-{
- auto ptr = std::make_unique<T>(t);
- if (!d_sender.send(std::move(ptr))) {
- unixDie("writing to the DelayPipe");
- }
-}
-
-template<class T>
-int ObjectPipe<T>::readTimeout(T* t, double msec)
-{
- while (true) {
- int ret = waitForData(d_receiver.getDescriptor(), 0, 1000*msec);
- if (ret < 0) {
- if (errno == EINTR) {
- continue;
- }
- unixDie("waiting for data in object pipe");
- }
- else if (ret == 0) {
- return -1;
- }
-
- try {
- auto tmp = d_receiver.receive();
- if (!tmp) {
- if (d_receiver.isClosed()) {
- return 0;
- }
- continue;
- }
-
- *t = **tmp;
- return 1;
- }
- catch (const std::exception& e) {
- throw std::runtime_error("reading from the delay pipe: " + std::string(e.what()));
- }
- }
-}
-
-
-template<class T>
-DelayPipe<T>::DelayPipe() : d_thread(&DelayPipe<T>::worker, this)
-{
-}
-
-template<class T>
-void DelayPipe<T>::gettime(struct timespec* ts)
-{
- ::gettime(ts);
-}
-
-
-template<class T>
-void DelayPipe<T>::submit(T& t, int msec)
-{
- struct timespec now;
- gettime(&now);
- now.tv_nsec += msec*1e6;
- while(now.tv_nsec > 1e9) {
- now.tv_sec++;
- now.tv_nsec-=1e9;
- }
- Combo c{t, now};
- d_pipe.write(c);
-}
-
-template<class T>
-DelayPipe<T>::~DelayPipe()
-{
- d_pipe.close();
- d_thread.join();
-}
-
-
-
-template<class T>
-void DelayPipe<T>::worker()
-{
- setThreadName("dnsdist/delayPi");
- Combo c;
- for(;;) {
- /* this code is slightly too subtle, but I don't see how it could be any simpler.
- So we have a set of work to do, and we need to wait until the time arrives to do it.
- Simultaneously new work might come in. So we try to combine both of these things by
- setting a timeout on listening to the pipe over which new work comes in. This timeout
- is equal to the wait until the first thing that needs to be done.
-
- Two additional cases exist: we have no work to wait for, so we can wait infinitely long.
- The other special case is that the first we have to do.. is in the past, so we need to do it
- immediately. */
-
-
- double delay=-1; // infinite
- struct timespec now;
- if(!d_work.empty()) {
- gettime(&now);
- delay=1000*tsdelta(d_work.begin()->first, now);
- if(delay < 0) {
- delay=0; // don't wait - we have work that is late already!
- }
- }
- if(delay != 0 ) {
- int ret = d_pipe.readTimeout(&c, delay);
- if(ret > 0) { // we got an object
- d_work.emplace(c.when, c.what);
- }
- else if(ret==0) { // EOF
- break;
- }
- else {
- ;
- }
- gettime(&now);
- }
-
- tscomp cmp;
-
- for(auto iter = d_work.begin() ; iter != d_work.end(); ) { // do the needful
- if(cmp(iter->first, now)) {
- iter->second();
- d_work.erase(iter++);
- }
- else {
- break;
- }
- }
- }
-}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-#include <time.h>
-#include <thread>
-
-#include "channel.hh"
-
-/**
- General idea: many threads submit work to this class, but only one executes it. The work should therefore be entirely trivial.
- The implementation is that submitter threads create an object that represents the work, and it gets sent over a pipe
- to the worker thread.
-
- The worker thread meanwhile listens on this pipe (non-blocking), with a delay set to the next object that needs to be executed.
- If meanwhile new work comes in, all objects who's time has come are executed, a new sleep time is calculated.
-*/
-
-
-/* ObjectPipe facilitates the type-safe passing of types over a pipe */
-
-template<class T>
-class ObjectPipe
-{
-public:
- ObjectPipe();
- void write(T& t);
- int readTimeout(T* t, double msec); //!< -1 is timeout, 0 is no data, 1 is data. msec<0 waits infinitely long. msec==0 = undefined
- void close();
-private:
- pdns::channel::Sender<T> d_sender;
- pdns::channel::Receiver<T> d_receiver;
-};
-
-template<class T>
-class DelayPipe
-{
-public:
- DelayPipe();
- ~DelayPipe();
- void submit(T& t, int msec); //!< don't try for more than 4294 msec
-
-private:
- void worker();
- struct Combo
- {
- T what;
- struct timespec when;
- };
-
- double tsdelta(const struct timespec& a, const struct timespec& b) // read as a-b
- {
- return 1.0*(a.tv_sec-b.tv_sec)+1.0*(a.tv_nsec-b.tv_nsec)/1000000000.0;
- }
-
- ObjectPipe<Combo> d_pipe;
- struct tscomp {
- bool operator()(const struct timespec& a, const struct timespec& b) const
- {
- return std::tie(a.tv_sec, a.tv_nsec) < std::tie(b.tv_sec, b.tv_nsec);
- }
- };
- std::multimap<struct timespec, T, tscomp> d_work;
- void gettime(struct timespec* ts);
- std::thread d_thread;
-};
-
-#include "delaypipe.cc"
#endif
#include "dns.hh"
#include "misc.hh"
+#include "views.hh"
#include <stdexcept>
#include <iostream>
#include <boost/algorithm/string.hpp>
}
// goal is to hash based purely on the question name, and turn error into 'default'
-uint32_t hashQuestion(const uint8_t* packet, uint16_t packet_len, uint32_t init, bool& ok)
+uint32_t hashQuestion(const uint8_t* packet, uint16_t packet_len, uint32_t init, bool& wasOK)
{
if (packet_len < sizeof(dnsheader)) {
- ok = false;
+ wasOK = false;
return init;
}
- // C++ 17 does not have std::u8string_view
- std::basic_string_view<uint8_t> name(packet + sizeof(dnsheader), packet_len - sizeof(dnsheader));
- std::basic_string_view<uint8_t>::size_type len = 0;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ pdns::views::UnsignedCharView name(packet + sizeof(dnsheader), packet_len - sizeof(dnsheader));
+ pdns::views::UnsignedCharView::size_type len = 0;
while (len < name.length()) {
uint8_t labellen = name[len++];
if (labellen == 0) {
- ok = true;
+ wasOK = true;
// len is name.length() at max as it was < before the increment
return burtleCI(name.data(), len, init);
}
len += labellen;
}
// We've encountered a label that is too long
- ok = false;
+ wasOK = false;
return init;
}
+static const std::array<std::string, 4> placeNames = {
+ "QUESTION",
+ "ANSWER",
+ "AUTHORITY",
+ "ADDITIONAL"
+};
+
+std::string DNSResourceRecord::placeString(uint8_t place)
+{
+ if (place >= placeNames.size()) {
+ return "?";
+ }
+ return placeNames.at(place);
+}
ADDITIONAL = 3
}; //!< Type describing the positioning within, say, a DNSPacket
+ [[nodiscard]] static std::string placeString(uint8_t place);
void setContent(const string& content);
[[nodiscard]] string getZoneRepresentation(bool noDot = false) const;
}
dnsResult.rcode = mdp.d_header.rcode;
for (auto i = mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
- if (i->first.d_place == 1 && i->first.d_type == mdp.d_qtype) {
- dnsResult.ips.emplace_back(i->first.getContent()->getZoneRepresentation());
+ if (i->d_place == 1 && i->d_type == mdp.d_qtype) {
+ dnsResult.ips.emplace_back(i->getContent()->getZoneRepresentation());
}
- if (i->first.d_place == 2 && i->first.d_type == QType::SOA) {
+ if (i->d_place == 2 && i->d_type == QType::SOA) {
dnsResult.seenauthsoa = true;
}
if (!g_quiet) {
- cout << i->first.d_place - 1 << "\t" << i->first.d_name << "\tIN\t" << DNSRecordContent::NumberToType(i->first.d_type);
- cout << "\t" << i->first.d_ttl << "\t" << i->first.getContent()->getZoneRepresentation() << "\n";
+ cout << i->d_place - 1 << "\t" << i->d_name << "\tIN\t" << DNSRecordContent::NumberToType(i->d_type);
+ cout << "\t" << i->d_ttl << "\t" << i->getContent()->getZoneRepresentation() << "\n";
}
}
dns.cc dns.hh \
dns_random.hh \
dnscrypt.cc dnscrypt.hh \
+ dnsdist-actions.hh \
dnsdist-async.cc dnsdist-async.hh \
- dnsdist-backend.cc \
+ dnsdist-backend.cc dnsdist-backend.hh \
dnsdist-backoff.hh \
dnsdist-cache.cc dnsdist-cache.hh \
dnsdist-carbon.cc dnsdist-carbon.hh \
dnsdist-concurrent-connections.hh \
+ dnsdist-configuration.cc dnsdist-configuration.hh \
dnsdist-console.cc dnsdist-console.hh \
dnsdist-crypto.cc dnsdist-crypto.hh \
dnsdist-discovery.cc dnsdist-discovery.hh \
dnsdist-dnscrypt.cc \
dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-dnsquestion.cc \
dnsdist-doh-common.cc dnsdist-doh-common.hh \
dnsdist-downstream-connection.hh \
dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
dnsdist-ecs.cc dnsdist-ecs.hh \
dnsdist-edns.cc dnsdist-edns.hh \
+ dnsdist-frontend.cc dnsdist-frontend.hh \
dnsdist-healthchecks.cc dnsdist-healthchecks.hh \
dnsdist-idstate.cc dnsdist-idstate.hh \
dnsdist-internal-queries.cc dnsdist-internal-queries.hh \
dnsdist-protobuf.cc dnsdist-protobuf.hh \
dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
+ dnsdist-query-count.hh dnsdist-query-count.cc \
dnsdist-random.cc dnsdist-random.hh \
dnsdist-resolver.cc dnsdist-resolver.hh \
dnsdist-rings.cc dnsdist-rings.hh \
dns.cc dns.hh \
dnscrypt.cc dnscrypt.hh \
dnsdist-async.cc dnsdist-async.hh \
- dnsdist-backend.cc \
+ dnsdist-backend.cc dnsdist-backend.hh \
dnsdist-backoff.hh \
dnsdist-cache.cc dnsdist-cache.hh \
dnsdist-concurrent-connections.hh \
+ dnsdist-configuration.cc dnsdist-configuration.hh \
dnsdist-crypto.cc dnsdist-crypto.hh \
dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-dnsquestion.cc \
dnsdist-doh-common.cc dnsdist-doh-common.hh \
dnsdist-downstream-connection.hh \
dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
dnsdist-ecs.cc dnsdist-ecs.hh \
dnsdist-edns.cc dnsdist-edns.hh \
+ dnsdist-frontend.cc dnsdist-frontend.hh \
dnsdist-idstate.cc dnsdist-idstate.hh \
dnsdist-kvs.cc dnsdist-kvs.hh \
dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
test-luawrapper.cc \
test-mplexer.cc \
test-proxy_protocol_cc.cc \
+ test-sholder_hh.cc \
testrunner.cc \
threadname.hh threadname.cc \
uuid-utils.hh uuid-utils.cc \
if HAVE_DNS_OVER_TLS
if HAVE_GNUTLS
-dnsdist_LDADD += -lgnutls
+dnsdist_LDADD += $(GNUTLS_LIBS)
endif
endif
if HAVE_DNS_OVER_HTTPS
if HAVE_GNUTLS
-dnsdist_LDADD += -lgnutls
+dnsdist_LDADD += $(GNUTLS_LIBS)
endif
if HAVE_LIBH2OEVLOOP
channel.hh channel.cc \
dns.cc dns.hh \
dnsdist-cache.cc dnsdist-cache.hh \
+ dnsdist-configuration.cc dnsdist-configuration.hh \
dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-dnsquestion.cc \
dnsdist-ecs.cc dnsdist-ecs.hh \
dnsdist-idstate.hh \
dnsdist-protocols.cc dnsdist-protocols.hh \
+++ /dev/null
-../README-dnsdist.md
\ No newline at end of file
--- /dev/null
+# dnsdist
+`dnsdist` is a highly DNS-, DoS- and abuse-aware loadbalancer. Its goal in
+life is to route traffic to the best server, delivering top performance
+to legitimate users while shunting or blocking abusive traffic.
+
+`dnsdist` is dynamic, in the sense that its configuration can be changed at
+runtime, and that its statistics can be queried from a console-like
+interface.
+
+All `dnsdist` features are documented at [dnsdist.org](https://dnsdist.org).
+
+## Compiling from git
+
+Make sure to `autoreconf -vi` before running `configure`.
+
+## macOS Notes
+
+Install dependencies from Homebrew:
+
+```sh
+brew install autoconf automake boost libedit libsodium libtool lua pkg-config protobuf
+```
+
+Let configure know where to find libedit, and openssl or libressl:
+
+```sh
+./configure 'PKG_CONFIG_PATH=/usr/local/opt/libedit/lib/pkgconfig:/usr/local/opt/libressl/lib/pkgconfig'
+make
+```
+++ /dev/null
-../bpf-filter.cc
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "bpf-filter.hh"
+#include "iputils.hh"
+#include "dolog.hh"
+
+#ifdef HAVE_EBPF
+
+#include <sys/syscall.h>
+#include <sys/resource.h>
+#include <linux/bpf.h>
+
+#include "ext/libbpf/libbpf.h"
+
+#include "misc.hh"
+
+static __u64 ptr_to_u64(const void* ptr)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
+ return (__u64)(unsigned long)ptr;
+}
+
+/* these can be static as they are not declared in libbpf.h: */
+static int bpf_pin_map(int descriptor, const std::string& path)
+{
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.bpf_fd = descriptor;
+ attr.pathname = ptr_to_u64(path.c_str());
+ return syscall(SYS_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
+}
+
+static int bpf_load_pinned_map(const std::string& path)
+{
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.pathname = ptr_to_u64(path.c_str());
+ return syscall(SYS_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+}
+
+static void bpf_check_map_sizes(int descriptor, uint32_t expectedKeySize, uint32_t expectedValueSize)
+{
+ struct bpf_map_info info;
+ uint32_t info_len = sizeof(info);
+ memset(&info, 0, sizeof(info));
+
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.info.bpf_fd = descriptor;
+ attr.info.info_len = info_len;
+ attr.info.info = ptr_to_u64(&info);
+
+ int err = syscall(SYS_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
+ if (err != 0) {
+ throw std::runtime_error("Error checking the size of eBPF map: " + stringerror());
+ }
+ if (info_len != sizeof(info)) {
+ throw std::runtime_error("Error checking the size of eBPF map: invalid info size returned");
+ }
+ if (info.key_size != expectedKeySize) {
+ throw std::runtime_error("Error checking the size of eBPF map: key size mismatch (" + std::to_string(info.key_size) + " VS " + std::to_string(expectedKeySize) + ")");
+ }
+ if (info.value_size != expectedValueSize) {
+ throw std::runtime_error("Error checking the size of eBPF map: value size mismatch (" + std::to_string(info.value_size) + " VS " + std::to_string(expectedValueSize) + ")");
+ }
+}
+
+// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
+static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
+ int max_entries, int map_flags)
+{
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.map_type = map_type;
+ attr.key_size = key_size;
+ attr.value_size = value_size;
+ attr.max_entries = max_entries;
+ attr.map_flags = map_flags;
+ return syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
+}
+
+static int bpf_update_elem(int descriptor, void* key, void* value, unsigned long long flags)
+{
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.map_fd = descriptor;
+ attr.key = ptr_to_u64(key);
+ attr.value = ptr_to_u64(value);
+ attr.flags = flags;
+ return syscall(SYS_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
+}
+
+static int bpf_lookup_elem(int descriptor, void* key, void* value)
+{
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.map_fd = descriptor;
+ attr.key = ptr_to_u64(key);
+ attr.value = ptr_to_u64(value);
+ return syscall(SYS_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
+}
+
+static int bpf_delete_elem(int descriptor, void* key)
+{
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.map_fd = descriptor;
+ attr.key = ptr_to_u64(key);
+ return syscall(SYS_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
+}
+
+static int bpf_get_next_key(int descriptor, void* key, void* next_key)
+{
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.map_fd = descriptor;
+ attr.key = ptr_to_u64(key);
+ attr.next_key = ptr_to_u64(next_key);
+ return syscall(SYS_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
+}
+
+static int bpf_prog_load(enum bpf_prog_type prog_type,
+ const struct bpf_insn* insns, size_t prog_len,
+ const char* license, int kern_version)
+{
+ char log_buf[65535];
+ union bpf_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = prog_type;
+ attr.insns = ptr_to_u64((void*)insns);
+ attr.insn_cnt = static_cast<int>(prog_len / sizeof(struct bpf_insn));
+ attr.license = ptr_to_u64((void*)license);
+ attr.log_buf = ptr_to_u64(log_buf);
+ attr.log_size = sizeof(log_buf);
+ attr.log_level = 1;
+ /* assign one field outside of struct init to make sure any
+ * padding is zero initialized
+ */
+ attr.kern_version = kern_version;
+
+ long res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
+ if (res == -1) {
+ if (errno == ENOSPC) {
+ /* not enough space in the log buffer */
+ attr.log_level = 0;
+ attr.log_size = 0;
+ attr.log_buf = ptr_to_u64(nullptr);
+ res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
+ if (res != -1) {
+ return res;
+ }
+ }
+ throw std::runtime_error("Error loading BPF program: (" + stringerror() + "):\n" + std::string(log_buf));
+ }
+ return res;
+}
+
+struct KeyV6
+{
+ uint8_t src[16];
+};
+
+struct QNameKey
+{
+ uint8_t qname[255];
+};
+
+struct QNameAndQTypeKey
+{
+ uint8_t qname[255];
+ uint16_t qtype;
+};
+
+struct QNameValue
+{
+ uint64_t counter{0};
+ uint16_t qtype{0};
+};
+
+BPFFilter::Map::Map(BPFFilter::MapConfiguration config, BPFFilter::MapFormat format) :
+ d_config(std::move(config))
+{
+ if (d_config.d_type == BPFFilter::MapType::Filters) {
+ /* special case, this is a map of eBPF programs */
+ d_fd = FDWrapper(bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(uint32_t), sizeof(uint32_t), d_config.d_maxItems, 0));
+ if (d_fd.getHandle() == -1) {
+ throw std::runtime_error("Error creating a BPF program map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror());
+ }
+ }
+ else {
+ int keySize = 0;
+ int valueSize = 0;
+ int flags = 0;
+ bpf_map_type type = BPF_MAP_TYPE_HASH;
+ if (format == MapFormat::Legacy) {
+ switch (d_config.d_type) {
+ case MapType::IPv4:
+ keySize = sizeof(uint32_t);
+ valueSize = sizeof(uint64_t);
+ break;
+ case MapType::IPv6:
+ keySize = sizeof(KeyV6);
+ valueSize = sizeof(uint64_t);
+ break;
+ case MapType::QNames:
+ keySize = sizeof(QNameKey);
+ valueSize = sizeof(QNameValue);
+ break;
+ default:
+ throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)) + " for legacy eBPF, perhaps you are trying to use an external program instead?");
+ }
+ }
+ else {
+ switch (d_config.d_type) {
+ case MapType::IPv4:
+ keySize = sizeof(uint32_t);
+ valueSize = sizeof(CounterAndActionValue);
+ break;
+ case MapType::IPv6:
+ keySize = sizeof(KeyV6);
+ valueSize = sizeof(CounterAndActionValue);
+ break;
+ case MapType::CIDR4:
+ keySize = sizeof(CIDR4);
+ valueSize = sizeof(CounterAndActionValue);
+ flags = BPF_F_NO_PREALLOC;
+ type = BPF_MAP_TYPE_LPM_TRIE;
+ break;
+ case MapType::CIDR6:
+ keySize = sizeof(CIDR6);
+ valueSize = sizeof(CounterAndActionValue);
+ flags = BPF_F_NO_PREALLOC;
+ type = BPF_MAP_TYPE_LPM_TRIE;
+ break;
+ case MapType::QNames:
+ keySize = sizeof(QNameAndQTypeKey);
+ valueSize = sizeof(CounterAndActionValue);
+ break;
+ default:
+ throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
+ }
+ }
+
+ if (!d_config.d_pinnedPath.empty()) {
+ /* try to load */
+ d_fd = FDWrapper(bpf_load_pinned_map(d_config.d_pinnedPath));
+ if (d_fd.getHandle() != -1) {
+ /* sanity checks: key and value size */
+ bpf_check_map_sizes(d_fd.getHandle(), keySize, valueSize);
+ switch (d_config.d_type) {
+ case MapType::IPv4: {
+ uint32_t key = 0;
+ while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+ ++d_count;
+ }
+ break;
+ }
+ case MapType::IPv6: {
+ KeyV6 key;
+ memset(&key, 0, sizeof(key));
+ while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+ ++d_count;
+ }
+ break;
+ }
+ case MapType::CIDR4: {
+ CIDR4 key;
+ memset(&key, 0, sizeof(key));
+ while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+ ++d_count;
+ }
+ break;
+ }
+ case MapType::CIDR6: {
+ CIDR6 key;
+ memset(&key, 0, sizeof(key));
+ while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+ ++d_count;
+ }
+ break;
+ }
+ case MapType::QNames: {
+ if (format == MapFormat::Legacy) {
+ QNameKey key;
+ memset(&key, 0, sizeof(key));
+ while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+ ++d_count;
+ }
+ }
+ else {
+ QNameAndQTypeKey key;
+ memset(&key, 0, sizeof(key));
+ while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+ ++d_count;
+ }
+ }
+ break;
+ }
+
+ default:
+ throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
+ }
+ }
+ }
+
+ if (d_fd.getHandle() == -1) {
+ d_fd = FDWrapper(bpf_create_map(type, keySize, valueSize, static_cast<int>(d_config.d_maxItems), flags));
+ if (d_fd.getHandle() == -1) {
+ throw std::runtime_error("Error creating a BPF map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror());
+ }
+
+ if (!d_config.d_pinnedPath.empty()) {
+ if (bpf_pin_map(d_fd.getHandle(), d_config.d_pinnedPath) != 0) {
+ throw std::runtime_error("Unable to pin map to path '" + d_config.d_pinnedPath + "': " + stringerror());
+ }
+ }
+ }
+ }
+}
+
+static FDWrapper loadProgram(const struct bpf_insn* filter, size_t filterSize)
+{
+ auto descriptor = FDWrapper(bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER,
+ filter,
+ filterSize,
+ "GPL",
+ 0));
+ if (descriptor.getHandle() == -1) {
+ throw std::runtime_error("error loading BPF filter: " + stringerror());
+ }
+ return descriptor;
+}
+
+BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external) :
+ d_mapFormat(format), d_external(external)
+{
+ if (d_mapFormat != BPFFilter::MapFormat::Legacy && !d_external) {
+ throw std::runtime_error("Unsupported eBPF map format, the current internal implemenation only supports the legacy format");
+ }
+
+ struct rlimit old_limit;
+ if (getrlimit(RLIMIT_MEMLOCK, &old_limit) != 0) {
+ throw std::runtime_error("Unable to get memory lock limit: " + stringerror());
+ }
+
+ const rlim_t new_limit_size = 1024 * 1024;
+
+ /* Check if the current soft memlock limit is at least the limit */
+ if (old_limit.rlim_cur < new_limit_size) {
+ infolog("The current limit of locked memory (soft: %d, hard: %d) is too low for eBPF, trying to raise it to %d", old_limit.rlim_cur, old_limit.rlim_max, new_limit_size);
+
+ struct rlimit new_limit;
+ new_limit.rlim_cur = new_limit_size;
+ new_limit.rlim_max = new_limit_size;
+
+ if (setrlimit(RLIMIT_MEMLOCK, &new_limit) != 0) {
+ warnlog("Unable to raise the maximum amount of locked memory for eBPF from %d to %d, consider raising RLIMIT_MEMLOCK or setting LimitMEMLOCK in the systemd unit: %d", old_limit.rlim_cur, new_limit.rlim_cur, stringerror());
+ }
+ }
+
+ auto maps = d_maps.lock();
+
+ maps->d_v4 = BPFFilter::Map(configs["ipv4"], d_mapFormat);
+ maps->d_v6 = BPFFilter::Map(configs["ipv6"], d_mapFormat);
+ maps->d_qnames = BPFFilter::Map(configs["qnames"], d_mapFormat);
+
+ if (d_mapFormat != BPFFilter::MapFormat::Legacy) {
+ maps->d_cidr4 = BPFFilter::Map(configs["cidr4"], d_mapFormat);
+ maps->d_cidr6 = BPFFilter::Map(configs["cidr6"], d_mapFormat);
+ }
+
+ if (!external) {
+ BPFFilter::MapConfiguration filters;
+ filters.d_maxItems = 1;
+ filters.d_type = BPFFilter::MapType::Filters;
+ maps->d_filters = BPFFilter::Map(std::move(filters), d_mapFormat);
+
+ const struct bpf_insn main_filter[] = {
+#include "bpf-filter.main.ebpf"
+ };
+
+ const struct bpf_insn qname_filter[] = {
+#include "bpf-filter.qname.ebpf"
+ };
+
+ try {
+ d_mainfilter = loadProgram(main_filter,
+ sizeof(main_filter));
+ }
+ catch (const std::exception& e) {
+ throw std::runtime_error("Error load the main eBPF filter: " + std::string(e.what()));
+ }
+
+ try {
+ d_qnamefilter = loadProgram(qname_filter,
+ sizeof(qname_filter));
+ }
+ catch (const std::exception& e) {
+ throw std::runtime_error("Error load the qname eBPF filter: " + std::string(e.what()));
+ }
+
+ uint32_t key = 0;
+ int qnamefd = d_qnamefilter.getHandle();
+ int res = bpf_update_elem(maps->d_filters.d_fd.getHandle(), &key, &qnamefd, BPF_ANY);
+ if (res != 0) {
+ throw std::runtime_error("Error updating BPF filters map: " + stringerror());
+ }
+ }
+}
+
+void BPFFilter::addSocket(int sock)
+{
+ int descriptor = d_mainfilter.getHandle();
+ int res = setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &descriptor, sizeof(descriptor));
+
+ if (res != 0) {
+ throw std::runtime_error("Error attaching BPF filter to this socket: " + stringerror());
+ }
+}
+
+void BPFFilter::removeSocket(int sock)
+{
+ int descriptor = d_mainfilter.getHandle();
+ int res = setsockopt(sock, SOL_SOCKET, SO_DETACH_BPF, &descriptor, sizeof(descriptor));
+
+ if (res != 0) {
+ throw std::runtime_error("Error detaching BPF filter from this socket: " + stringerror());
+ }
+}
+
+void BPFFilter::block(const ComboAddress& addr, BPFFilter::MatchAction action)
+{
+ CounterAndActionValue value;
+ value.counter = 0;
+ value.action = action;
+
+ int res = 0;
+ if (addr.isIPv4()) {
+ uint32_t key = htonl(addr.sin4.sin_addr.s_addr);
+ auto maps = d_maps.lock();
+ auto& map = maps->d_v4;
+ if (map.d_count >= map.d_config.d_maxItems) {
+ throw std::runtime_error("Table full when trying to block " + addr.toString());
+ }
+
+ res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
+ if (res != -1) {
+ throw std::runtime_error("Trying to block an already blocked address: " + addr.toString());
+ }
+
+ res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
+ if (res == 0) {
+ ++map.d_count;
+ }
+ }
+ else if (addr.isIPv6()) {
+ uint8_t key[16];
+ static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+ for (size_t idx = 0; idx < sizeof(key); idx++) {
+ key[idx] = addr.sin6.sin6_addr.s6_addr[idx];
+ }
+
+ auto maps = d_maps.lock();
+ auto& map = maps->d_v6;
+ if (map.d_count >= map.d_config.d_maxItems) {
+ throw std::runtime_error("Table full when trying to block " + addr.toString());
+ }
+
+ res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
+ if (res != -1) {
+ throw std::runtime_error("Trying to block an already blocked address: " + addr.toString());
+ }
+
+ res = bpf_update_elem(map.d_fd.getHandle(), key, &value, BPF_NOEXIST);
+ if (res == 0) {
+ map.d_count++;
+ }
+ }
+
+ if (res != 0) {
+ throw std::runtime_error("Error adding blocked address " + addr.toString() + ": " + stringerror());
+ }
+}
+
+void BPFFilter::unblock(const ComboAddress& addr)
+{
+ int res = 0;
+ if (addr.isIPv4()) {
+ uint32_t key = htonl(addr.sin4.sin_addr.s_addr);
+ auto maps = d_maps.lock();
+ auto& map = maps->d_v4;
+ res = bpf_delete_elem(map.d_fd.getHandle(), &key);
+ if (res == 0) {
+ --map.d_count;
+ }
+ }
+ else if (addr.isIPv6()) {
+ uint8_t key[16];
+ static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+ for (size_t idx = 0; idx < sizeof(key); idx++) {
+ key[idx] = addr.sin6.sin6_addr.s6_addr[idx];
+ }
+
+ auto maps = d_maps.lock();
+ auto& map = maps->d_v6;
+ res = bpf_delete_elem(map.d_fd.getHandle(), key);
+ if (res == 0) {
+ --map.d_count;
+ }
+ }
+
+ if (res != 0) {
+ throw std::runtime_error("Error removing blocked address " + addr.toString() + ": " + stringerror());
+ }
+}
+
+void BPFFilter::addRangeRule(const Netmask& addr, bool force, BPFFilter::MatchAction action)
+{
+ CounterAndActionValue value;
+
+ int res = 0;
+ if (addr.isIPv4()) {
+ CIDR4 key(addr);
+ auto maps = d_maps.lock();
+ auto& map = maps->d_cidr4;
+ if (map.d_fd.getHandle() == -1) {
+ throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
+ }
+ if (map.d_count >= map.d_config.d_maxItems) {
+ throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
+ }
+
+ res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
+ if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
+ throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
+ }
+
+ value.counter = 0;
+ value.action = action;
+
+ res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, force ? BPF_ANY : BPF_NOEXIST);
+ if (res == 0) {
+ ++map.d_count;
+ }
+ }
+ else if (addr.isIPv6()) {
+ CIDR6 key(addr);
+
+ auto maps = d_maps.lock();
+ auto& map = maps->d_cidr6;
+ if (map.d_fd.getHandle() == -1) {
+ throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
+ }
+ if (map.d_count >= map.d_config.d_maxItems) {
+ throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
+ }
+
+ res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
+ if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
+ throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
+ }
+
+ value.counter = 0;
+ value.action = action;
+
+ res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
+ if (res == 0) {
+ map.d_count++;
+ }
+ }
+
+ if (res != 0) {
+ throw std::runtime_error("Error adding this rule: " + addr.toString() + ": " + stringerror());
+ }
+}
+
+void BPFFilter::rmRangeRule(const Netmask& addr)
+{
+ int res = 0;
+ CounterAndActionValue value;
+ value.counter = 0;
+ value.action = MatchAction::Pass;
+ if (addr.isIPv4()) {
+ CIDR4 key(addr);
+ auto maps = d_maps.lock();
+ auto& map = maps->d_cidr4;
+ if (map.d_fd.getHandle() == -1) {
+ throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
+ }
+ res = bpf_delete_elem(map.d_fd.getHandle(), &key);
+ if (res == 0) {
+ --map.d_count;
+ }
+ else {
+ throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
+ }
+ }
+ else if (addr.isIPv6()) {
+ CIDR6 key(addr);
+
+ auto maps = d_maps.lock();
+ auto& map = maps->d_cidr6;
+ if (map.d_fd.getHandle() == -1) {
+ throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
+ }
+ res = bpf_delete_elem(map.d_fd.getHandle(), &key);
+ if (res == 0) {
+ --map.d_count;
+ }
+ else {
+ throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
+ }
+ }
+
+ if (res != 0) {
+ throw std::runtime_error("Error removing this rule: " + addr.toString() + ": " + stringerror());
+ }
+}
+
+void BPFFilter::block(const DNSName& qname, BPFFilter::MatchAction action, uint16_t qtype)
+{
+ CounterAndActionValue cadvalue;
+ QNameValue qvalue;
+ void* value = nullptr;
+
+ if (d_external) {
+ cadvalue.counter = 0;
+ cadvalue.action = action;
+ value = &cadvalue;
+ }
+ else {
+ qvalue.counter = 0;
+ qvalue.qtype = qtype;
+ value = &qvalue;
+ }
+
+ QNameAndQTypeKey key;
+ memset(&key, 0, sizeof(key));
+
+ std::string keyStr = qname.toDNSStringLC();
+ if (keyStr.size() > sizeof(key.qname)) {
+ throw std::runtime_error("Invalid QName to block " + qname.toLogString());
+ }
+ memcpy(key.qname, keyStr.c_str(), keyStr.size());
+ key.qtype = qtype;
+
+ {
+ auto maps = d_maps.lock();
+ auto& map = maps->d_qnames;
+ if (map.d_count >= map.d_config.d_maxItems) {
+ throw std::runtime_error("Table full when trying to block " + qname.toLogString());
+ }
+
+ int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, value);
+ if (res != -1) {
+ throw std::runtime_error("Trying to block an already blocked qname: " + qname.toLogString());
+ }
+ res = bpf_update_elem(map.d_fd.getHandle(), &key, value, BPF_NOEXIST);
+ if (res == 0) {
+ ++map.d_count;
+ }
+
+ if (res != 0) {
+ throw std::runtime_error("Error adding blocked qname " + qname.toLogString() + ": " + stringerror());
+ }
+ }
+}
+
+void BPFFilter::unblock(const DNSName& qname, uint16_t qtype)
+{
+ QNameAndQTypeKey key;
+ memset(&key, 0, sizeof(key));
+ std::string keyStr = qname.toDNSStringLC();
+
+ if (keyStr.size() > sizeof(key.qname)) {
+ throw std::runtime_error("Invalid QName to block " + qname.toLogString());
+ }
+ memcpy(key.qname, keyStr.c_str(), keyStr.size());
+ key.qtype = qtype;
+
+ {
+ auto maps = d_maps.lock();
+ auto& map = maps->d_qnames;
+ int res = bpf_delete_elem(map.d_fd.getHandle(), &key);
+ if (res == 0) {
+ --map.d_count;
+ }
+ else {
+ throw std::runtime_error("Error removing qname address " + qname.toLogString() + ": " + stringerror());
+ }
+ }
+}
+
+std::vector<std::pair<ComboAddress, uint64_t>> BPFFilter::getAddrStats()
+{
+ std::vector<std::pair<ComboAddress, uint64_t>> result;
+ {
+ auto maps = d_maps.lock();
+ result.reserve(maps->d_v4.d_count + maps->d_v6.d_count);
+ }
+
+ sockaddr_in v4Addr{};
+ memset(&v4Addr, 0, sizeof(v4Addr));
+ v4Addr.sin_family = AF_INET;
+
+ uint32_t v4Key = 0;
+ uint32_t nextV4Key{};
+ CounterAndActionValue value{};
+
+ std::array<uint8_t, 16> v6Key{};
+ std::array<uint8_t, 16> nextV6Key{};
+ sockaddr_in6 v6Addr{};
+ memset(&v6Addr, 0, sizeof(v6Addr));
+ v6Addr.sin6_family = AF_INET6;
+
+ static_assert(sizeof(v6Addr.sin6_addr.s6_addr) == v6Key.size(), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+ memset(&v6Key, 0, sizeof(v6Key));
+
+ auto maps = d_maps.lock();
+
+ {
+ auto& map = maps->d_v4;
+ int res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key);
+
+ while (res == 0) {
+ v4Key = nextV4Key;
+ if (bpf_lookup_elem(map.d_fd.getHandle(), &v4Key, &value) == 0) {
+ v4Addr.sin_addr.s_addr = ntohl(v4Key);
+ result.emplace_back(ComboAddress(&v4Addr), value.counter);
+ }
+
+ res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key);
+ }
+ }
+
+ {
+ auto& map = maps->d_v6;
+ int res = bpf_get_next_key(map.d_fd.getHandle(), v6Key.data(), nextV6Key.data());
+
+ while (res == 0) {
+ if (bpf_lookup_elem(map.d_fd.getHandle(), nextV6Key.data(), &value) == 0) {
+ memcpy(&v6Addr.sin6_addr.s6_addr, nextV6Key.data(), nextV6Key.size());
+
+ result.emplace_back(ComboAddress(&v6Addr), value.counter);
+ }
+
+ res = bpf_get_next_key(map.d_fd.getHandle(), nextV6Key.data(), nextV6Key.data());
+ }
+ }
+
+ return result;
+}
+
+std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule()
+{
+ CIDR4 cidr4[2];
+ CIDR6 cidr6[2];
+ std::vector<std::pair<Netmask, CounterAndActionValue>> result;
+
+ sockaddr_in v4Addr;
+ sockaddr_in6 v6Addr;
+ CounterAndActionValue value;
+
+ memset(cidr4, 0, sizeof(cidr4));
+ memset(cidr6, 0, sizeof(cidr6));
+ memset(&v4Addr, 0, sizeof(v4Addr));
+ memset(&v6Addr, 0, sizeof(v6Addr));
+ v4Addr.sin_family = AF_INET;
+ v6Addr.sin6_family = AF_INET6;
+ auto maps = d_maps.lock();
+ result.reserve(maps->d_cidr4.d_count + maps->d_cidr6.d_count);
+ {
+ auto& map = maps->d_cidr4;
+ int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[0], &cidr4[1]);
+ while (res == 0) {
+ if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr4[1], &value) == 0) {
+ v4Addr.sin_addr.s_addr = cidr4[1].addr.s_addr;
+ result.emplace_back(Netmask(&v4Addr, cidr4[1].cidr), value);
+ }
+
+ res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[1], &cidr4[1]);
+ }
+ }
+
+ {
+ auto& map = maps->d_cidr6;
+ int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[0], &cidr6[1]);
+ while (res == 0) {
+ if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr6[1], &value) == 0) {
+ v6Addr.sin6_addr = cidr6[1].addr;
+ result.emplace_back(Netmask(&v6Addr, cidr6[1].cidr), value);
+ }
+
+ res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[1], &cidr6[1]);
+ }
+ }
+ return result;
+}
+
+std::vector<std::tuple<DNSName, uint16_t, uint64_t>> BPFFilter::getQNameStats()
+{
+ std::vector<std::tuple<DNSName, uint16_t, uint64_t>> result;
+
+ if (d_mapFormat == MapFormat::Legacy) {
+ QNameKey key = {{0}};
+ QNameKey nextKey = {{0}};
+ QNameValue value;
+
+ auto maps = d_maps.lock();
+ auto& map = maps->d_qnames;
+ result.reserve(map.d_count);
+ int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey);
+
+ while (res == 0) {
+ if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
+ nextKey.qname[sizeof(nextKey.qname) - 1] = '\0';
+ result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), value.qtype, value.counter);
+ }
+
+ res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
+ }
+ }
+ else {
+ QNameAndQTypeKey key;
+ QNameAndQTypeKey nextKey;
+ memset(&key, 0, sizeof(key));
+ memset(&nextKey, 0, sizeof(nextKey));
+ CounterAndActionValue value;
+
+ auto maps = d_maps.lock();
+ auto& map = maps->d_qnames;
+ result.reserve(map.d_count);
+ int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey);
+
+ while (res == 0) {
+ if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
+ nextKey.qname[sizeof(nextKey.qname) - 1] = '\0';
+ result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), key.qtype, value.counter);
+ }
+
+ res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
+ }
+ }
+
+ return result;
+}
+
+uint64_t BPFFilter::getHits(const ComboAddress& requestor)
+{
+ CounterAndActionValue counter;
+
+ if (requestor.isIPv4()) {
+ uint32_t key = htonl(requestor.sin4.sin_addr.s_addr);
+
+ auto maps = d_maps.lock();
+ auto& map = maps->d_v4;
+ int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter);
+ if (res == 0) {
+ return counter.counter;
+ }
+ }
+ else if (requestor.isIPv6()) {
+ uint8_t key[16];
+ static_assert(sizeof(requestor.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+ for (size_t idx = 0; idx < sizeof(key); idx++) {
+ key[idx] = requestor.sin6.sin6_addr.s6_addr[idx];
+ }
+
+ auto maps = d_maps.lock();
+ auto& map = maps->d_v6;
+ int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter);
+ if (res == 0) {
+ return counter.counter;
+ }
+ }
+
+ return 0;
+}
+
+#else
+
+BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external)
+{
+}
+
+void BPFFilter::addSocket(int)
+{
+ throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::removeSocket(int)
+{
+ throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::block(const ComboAddress&, BPFFilter::MatchAction)
+{
+ throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::unblock(const ComboAddress&)
+{
+ throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::block(const DNSName&, BPFFilter::MatchAction, uint16_t)
+{
+ throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::unblock(const DNSName&, uint16_t)
+{
+ throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::addRangeRule(const Netmask&, bool, BPFFilter::MatchAction)
+{
+ throw std::runtime_error("eBPF support not enabled");
+}
+void BPFFilter::rmRangeRule(const Netmask&)
+{
+ throw std::runtime_error("eBPF support not enabled");
+}
+
+std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule()
+{
+ std::vector<std::pair<Netmask, CounterAndActionValue>> result;
+ return result;
+}
+std::vector<std::pair<ComboAddress, uint64_t>> BPFFilter::getAddrStats()
+{
+ std::vector<std::pair<ComboAddress, uint64_t>> result;
+ return result;
+}
+
+std::vector<std::tuple<DNSName, uint16_t, uint64_t>> BPFFilter::getQNameStats()
+{
+ std::vector<std::tuple<DNSName, uint16_t, uint64_t>> result;
+ return result;
+}
+
+uint64_t BPFFilter::getHits(const ComboAddress&)
+{
+ return 0;
+}
+#endif /* HAVE_EBPF */
+
+bool BPFFilter::supportsMatchAction(MatchAction action) const
+{
+#ifdef HAVE_EBPF
+ if (action == BPFFilter::MatchAction::Drop) {
+ return true;
+ }
+ return d_mapFormat == BPFFilter::MapFormat::WithActions;
+#endif /* HAVE_EBPF */
+ return false;
+}
+
+bool BPFFilter::isExternal() const
+{
+#ifdef HAVE_EBPF
+ return d_external;
+#endif /* HAVE_EBPF */
+ return false;
+}
+++ /dev/null
-../bpf-filter.ebpf.src
\ No newline at end of file
--- /dev/null
+
+#include <net/sock.h>
+#include <linux/types.h>
+#include <uapi/linux/tcp.h>
+#include <uapi/linux/udp.h>
+#include <uapi/linux/ip.h>
+#include <uapi/linux/ipv6.h>
+#include <bcc/proto.h>
+
+struct dnsheader {
+ unsigned id :16; /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+ /* fields in third byte */
+ unsigned qr: 1; /* response flag */
+ unsigned opcode: 4; /* purpose of message */
+ unsigned aa: 1; /* authoritative answer */
+ unsigned tc: 1; /* truncated message */
+ unsigned rd: 1; /* recursion desired */
+ /* fields in fourth byte */
+ unsigned ra: 1; /* recursion available */
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ad: 1; /* authentic data from named */
+ unsigned cd: 1; /* checking disabled by resolver */
+ unsigned rcode :4; /* response code */
+#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+ /* fields in third byte */
+ unsigned rd :1; /* recursion desired */
+ unsigned tc :1; /* truncated message */
+ unsigned aa :1; /* authoritative answer */
+ unsigned opcode :4; /* purpose of message */
+ unsigned qr :1; /* response flag */
+ /* fields in fourth byte */
+ unsigned rcode :4; /* response code */
+ unsigned cd: 1; /* checking disabled by resolver */
+ unsigned ad: 1; /* authentic data from named */
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ra :1; /* recursion available */
+#endif
+ /* remaining bytes */
+ unsigned qdcount :16; /* number of question entries */
+ unsigned ancount :16; /* number of answer entries */
+ unsigned nscount :16; /* number of authority entries */
+ unsigned arcount :16; /* number of resource entries */
+};
+
+struct QNameKey
+{
+ uint8_t qname[255];
+};
+
+struct KeyV6
+{
+ uint8_t src[16];
+};
+
+struct QNameValue
+{
+ u64 counter;
+ u16 qtype;
+};
+
+BPF_TABLE("hash", u32, u64, v4filter, 1024);
+BPF_TABLE("hash", struct KeyV6, u64, v6filter, 1024);
+BPF_TABLE("hash", struct QNameKey, struct QNameValue, qnamefilter, 1024);
+BPF_TABLE("prog", int, int, progsarray, 1);
+
+int bpf_qname_filter(struct __sk_buff *skb)
+{
+ uint32_t qname_off = skb->cb[0];
+ ssize_t labellen = skb->cb[3];
+ size_t idx = 2;
+ struct QNameKey qkey = { 0 };
+ u32 val = skb->cb[1];
+ if (val) {
+ qkey.qname[0] = val;
+ }
+ val = skb->cb[2];
+ if (val) {
+ qkey.qname[1] = val;
+ }
+ uint8_t temp;
+
+#define FILL_ONE_KEY \
+ temp = load_byte(skb, qname_off + idx); \
+ labellen--; \
+ if (labellen < 0) { \
+ labellen = temp; \
+ if (labellen == 0) { \
+ goto end; \
+ } \
+ } else if (temp >= 'A' && temp <= 'Z') { \
+ temp += ('a' - 'A'); \
+ } \
+ qkey.qname[idx] = temp; \
+ idx++;
+
+ /* 2 - 52 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 52 - 102 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 102 - 152 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 152 - 202 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 202 - 252 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* 252 - 254 */
+ FILL_ONE_KEY
+ FILL_ONE_KEY
+
+ /* the only value that makes sense for
+ qkey.qname[255] is 0, and it's already
+ there */
+ end:
+
+ {
+ idx++;
+ u16 qtype = load_half(skb, (qname_off + idx));
+
+ struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
+ if (qvalue &&
+ (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
+ __sync_fetch_and_add(&qvalue->counter, 1);
+ return 0;
+ }
+ }
+
+ return 2147483647;
+}
+
+int bpf_dns_filter(struct __sk_buff *skb) {
+ u8 ip_proto;
+ int proto_off;
+ /* nh_off will contain a negative offset, used in BPF to get access to
+ the MAC/network layers, as positive values are used to get access to
+ the transport layer */
+ int nh_off = BPF_LL_OFF + ETH_HLEN;
+
+ if (skb->protocol == ntohs(0x0800)) {
+ u32 key;
+ int off = nh_off + offsetof(struct iphdr, saddr);
+ key = load_word(skb, off);
+
+ u64* counter = v4filter.lookup(&key);
+ if (counter) {
+ __sync_fetch_and_add(counter, 1);
+ return 0;
+ }
+
+ ip_proto = load_byte(skb, nh_off + offsetof(struct iphdr, protocol));
+ proto_off = nh_off + sizeof(struct iphdr);
+ }
+ else if (skb->protocol == ntohs(0x86DD)) {
+ struct KeyV6 key;
+ int off = nh_off + offsetof(struct ipv6hdr, saddr);
+ key.src[0] = load_byte(skb, off++);
+ key.src[1] = load_byte(skb, off++);
+ key.src[2] = load_byte(skb, off++);
+ key.src[3] = load_byte(skb, off++);
+ key.src[4] = load_byte(skb, off++);
+ key.src[5] = load_byte(skb, off++);
+ key.src[6] = load_byte(skb, off++);
+ key.src[7] = load_byte(skb, off++);
+ key.src[8] = load_byte(skb, off++);
+ key.src[9] = load_byte(skb, off++);
+ key.src[10] = load_byte(skb, off++);
+ key.src[11] = load_byte(skb, off++);
+ key.src[12] = load_byte(skb, off++);
+ key.src[13] = load_byte(skb, off++);
+ key.src[14] = load_byte(skb, off++);
+ key.src[15] = load_byte(skb, off++);
+
+ u64* counter = v6filter.lookup(&key);
+ if (counter) {
+ __sync_fetch_and_add(counter, 1);
+ return 0;
+ }
+
+ ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
+ proto_off = nh_off + sizeof(struct ipv6hdr);
+ }
+ else {
+ /* neither IPv4 not IPv6, well */
+ return 2147483647;
+ }
+
+ /* allow TCP */
+ if (ip_proto == IPPROTO_TCP) {
+ return 2147483647;
+ }
+
+ struct QNameKey qkey = { 0 };
+ /* switch to positive offsets here, as we have seen some issues
+ when accessing the content of the transport layer with negative offsets
+ https://github.com/PowerDNS/pdns/issues/9626 */
+ int dns_off = sizeof(struct udphdr);
+ int qname_off = dns_off + sizeof(struct dnsheader);
+ skb->cb[0] = (uint32_t) qname_off;
+ u16 qtype;
+
+ uint8_t temp = load_byte(skb, qname_off);
+ if (temp > 63) {
+ return 0;
+ }
+
+ if (temp == 0) {
+ /* root, nothing else to see */
+ qtype = load_half(skb, (qname_off + 1));
+
+ struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
+ if (qvalue &&
+ (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
+ __sync_fetch_and_add(&qvalue->counter, 1);
+ return 0;
+ }
+ return 2147483647;
+ }
+
+ ssize_t labellen = temp;
+ skb->cb[1] = temp;
+ qkey.qname[0] = temp;
+
+ temp = load_byte(skb, qname_off + 1);
+ labellen--;
+ if (temp >= 'A' && temp <= 'Z') {
+ temp += ('a' - 'A');
+ }
+ skb->cb[2] = temp;
+ skb->cb[3] = labellen;
+ progsarray.call(skb, 0);
+
+ return 2147483647;
+}
+++ /dev/null
-../bpf-filter.hh
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "config.h"
+
+#include <unordered_map>
+
+#include "iputils.hh"
+#include "lock.hh"
+#include <netinet/in.h>
+#include <stdexcept>
+
+class BPFFilter
+{
+public:
+ enum class MapType : uint8_t
+ {
+ IPv4,
+ IPv6,
+ QNames,
+ Filters,
+ CIDR4,
+ CIDR6
+ };
+
+ enum class MapFormat : uint8_t
+ {
+ Legacy = 0,
+ WithActions = 1
+ };
+
+ enum class MatchAction : uint8_t
+ {
+ Pass = 0,
+ Drop = 1,
+ Truncate = 2
+ };
+ static std::string toString(MatchAction s) noexcept
+ {
+ switch (s) {
+ case MatchAction::Pass:
+ return "Pass";
+ case MatchAction::Drop:
+ return "Drop";
+ case MatchAction::Truncate:
+ return "Truncate";
+ }
+ return "Unknown";
+ }
+
+ struct MapConfiguration
+ {
+ std::string d_pinnedPath;
+ uint32_t d_maxItems{0};
+ MapType d_type;
+ };
+
+ struct CounterAndActionValue
+ {
+ uint64_t counter{0};
+ BPFFilter::MatchAction action{BPFFilter::MatchAction::Pass};
+ };
+
+ BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external);
+ BPFFilter(const BPFFilter&) = delete;
+ BPFFilter(BPFFilter&&) = delete;
+ BPFFilter& operator=(const BPFFilter&) = delete;
+ BPFFilter& operator=(BPFFilter&&) = delete;
+
+ void addSocket(int sock);
+ void removeSocket(int sock);
+ void block(const ComboAddress& addr, MatchAction action);
+ void addRangeRule(const Netmask& address, bool force, BPFFilter::MatchAction action);
+ void block(const DNSName& qname, MatchAction action, uint16_t qtype = 255);
+ void unblock(const ComboAddress& addr);
+ void rmRangeRule(const Netmask& address);
+ void unblock(const DNSName& qname, uint16_t qtype = 255);
+
+ std::vector<std::pair<ComboAddress, uint64_t>> getAddrStats();
+ std::vector<std::pair<Netmask, CounterAndActionValue>> getRangeRule();
+ std::vector<std::tuple<DNSName, uint16_t, uint64_t>> getQNameStats();
+
+ uint64_t getHits(const ComboAddress& requestor);
+
+ bool supportsMatchAction(MatchAction action) const;
+ bool isExternal() const;
+
+private:
+#ifdef HAVE_EBPF
+ struct Map
+ {
+ Map()
+ {
+ }
+ Map(MapConfiguration, MapFormat);
+ MapConfiguration d_config;
+ uint32_t d_count{0};
+ FDWrapper d_fd;
+ };
+
+ struct Maps
+ {
+ Map d_v4;
+ Map d_v6;
+ Map d_cidr4;
+ Map d_cidr6;
+ Map d_qnames;
+ /* The qname filter program held in d_qnamefilter is
+ stored in an eBPF map, so we can call it from the
+ main filter. This is the only entry in that map. */
+ Map d_filters;
+ };
+
+ LockGuarded<Maps> d_maps;
+
+ /* main eBPF program */
+ FDWrapper d_mainfilter;
+ /* qname filtering program */
+ FDWrapper d_qnamefilter;
+ struct CIDR4
+ {
+ uint32_t cidr;
+ struct in_addr addr;
+ explicit CIDR4(Netmask address)
+ {
+ if (!address.isIPv4()) {
+ throw std::runtime_error("ComboAddress is invalid");
+ }
+ addr = address.getNetwork().sin4.sin_addr;
+ cidr = address.getBits();
+ }
+ CIDR4() = default;
+ };
+ struct CIDR6
+ {
+ uint32_t cidr;
+ struct in6_addr addr;
+ CIDR6(Netmask address)
+ {
+ if (!address.isIPv6()) {
+ throw std::runtime_error("ComboAddress is invalid");
+ }
+ addr = address.getNetwork().sin6.sin6_addr;
+ cidr = address.getBits();
+ }
+ CIDR6() = default;
+ };
+ /* whether the maps are in the 'old' format, which we need
+ to keep to prevent going over the 4k instructions per eBPF
+ program limit in kernels < 5.2, as well as the complexity limit:
+ - 32k in Linux 3.18
+ - 64k in Linux 4.7
+ - 96k in Linux 4.12
+ - 128k in Linux 4.14,
+ - 1M in Linux 5.2 */
+ MapFormat d_mapFormat;
+
+ /* whether the filter is internal, using our own eBPF programs,
+ or external where we only update the maps but the filtering is
+ done by an external program. */
+ bool d_external;
+#endif /* HAVE_EBPF */
+};
+using CounterAndActionValue = BPFFilter::CounterAndActionValue;
+++ /dev/null
-../bpf-filter.main.ebpf
\ No newline at end of file
--- /dev/null
+/* generated from the bpf_dns_filter() function in bpf-filter.ebpf.src */
+BPF_MOV64_REG(BPF_REG_6,BPF_REG_1),
+BPF_MOV64_IMM(BPF_REG_7,2147483647),
+BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,16),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,ntohs(0x86dd),11),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_1,ntohs(0x0800),109),
+BPF_LD_ABS(BPF_W,-2097126),
+BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_0,-256),
+BPF_LD_MAP_FD(BPF_REG_1,maps->d_v4.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_0,0,98),
+BPF_LD_ABS(BPF_B,-2097129),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,39),
+BPF_LD_ABS(BPF_B,-2097130),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-256),
+BPF_LD_ABS(BPF_B,-2097129),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-255),
+BPF_LD_ABS(BPF_B,-2097128),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-254),
+BPF_LD_ABS(BPF_B,-2097127),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-253),
+BPF_LD_ABS(BPF_B,-2097126),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-252),
+BPF_LD_ABS(BPF_B,-2097125),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-251),
+BPF_LD_ABS(BPF_B,-2097124),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-250),
+BPF_LD_ABS(BPF_B,-2097123),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-249),
+BPF_LD_ABS(BPF_B,-2097122),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-248),
+BPF_LD_ABS(BPF_B,-2097121),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-247),
+BPF_LD_ABS(BPF_B,-2097120),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-246),
+BPF_LD_ABS(BPF_B,-2097119),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-245),
+BPF_LD_ABS(BPF_B,-2097118),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-244),
+BPF_LD_ABS(BPF_B,-2097117),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-243),
+BPF_LD_ABS(BPF_B,-2097116),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-242),
+BPF_LD_ABS(BPF_B,-2097115),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-241),
+BPF_LD_MAP_FD(BPF_REG_1,maps->d_v6.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_0,0,58),
+BPF_LD_ABS(BPF_B,-2097132),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_0,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,6,58),
+BPF_MOV64_IMM(BPF_REG_1,0),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-2),
+BPF_STX_MEM(BPF_H,BPF_REG_10,BPF_REG_1,-4),
+BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_1,-8),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-16),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-24),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-32),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-40),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-48),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-56),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-64),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-72),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-80),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-88),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-96),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-104),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-112),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-120),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-128),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-136),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-144),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-152),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-160),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-168),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-176),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-184),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-192),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-200),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-208),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-216),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-224),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-232),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-240),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-248),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-256),
+BPF_MOV64_IMM(BPF_REG_1,20),
+BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_1,48),
+BPF_LD_ABS(BPF_B,20),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_MOV64_IMM(BPF_REG_7,0),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_8,63,17),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_8,0,18),
+BPF_LD_ABS(BPF_H,21),
+BPF_MOV64_REG(BPF_REG_6,BPF_REG_0),
+BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
+BPF_MOV64_IMM(BPF_REG_7,2147483647),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,0,7),
+BPF_LDX_MEM(BPF_H,BPF_REG_1,BPF_REG_0,8),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,255,2),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_6,65535),
+BPF_JMP_REG(BPF_JNE,BPF_REG_1,BPF_REG_6,3),
+BPF_MOV64_IMM(BPF_REG_1,1),
+BPF_RAW_INSN(BPF_STX|BPF_XADD|BPF_DW,BPF_REG_0,BPF_REG_1,0,0),
+BPF_MOV64_IMM(BPF_REG_7,0),
+BPF_MOV64_REG(BPF_REG_0,BPF_REG_7),
+BPF_EXIT_INSN(),
+BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_8,52),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_8,-256),
+BPF_LD_ABS(BPF_B,21),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-65),
+BPF_ALU64_IMM(BPF_LSH,BPF_REG_2,32),
+BPF_ALU64_IMM(BPF_RSH,BPF_REG_2,32),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,32),
+BPF_MOV64_IMM(BPF_REG_3,26),
+BPF_JMP_REG(BPF_JGT,BPF_REG_3,BPF_REG_2,1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_8,60),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_1,56),
+BPF_LD_MAP_FD(BPF_REG_2,maps->d_filters.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_6),
+BPF_MOV64_IMM(BPF_REG_3,0),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_tail_call),
+BPF_MOV64_IMM(BPF_REG_7,2147483647),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,-25),
+++ /dev/null
-../bpf-filter.qname.ebpf
\ No newline at end of file
--- /dev/null
+/* generated from the bpf_qname_filter() function in bpf-filter.ebpf.src */
+BPF_MOV64_REG(BPF_REG_6,BPF_REG_1),
+BPF_LDX_MEM(BPF_W,BPF_REG_8,BPF_REG_6,60),
+BPF_LDX_MEM(BPF_W,BPF_REG_7,BPF_REG_6,48),
+BPF_MOV64_IMM(BPF_REG_1,0),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-2),
+BPF_STX_MEM(BPF_H,BPF_REG_10,BPF_REG_1,-4),
+BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_1,-8),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-16),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-24),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-32),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-40),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-48),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-56),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-64),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-72),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-80),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-88),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-96),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-104),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-112),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-120),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-128),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-136),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-144),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-152),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-160),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-168),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-176),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-184),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-192),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-200),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-208),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-216),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-224),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-232),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-240),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-248),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-256),
+BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,52),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,1),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-256),
+BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,56),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,1),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-255),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,2),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_2,0,0),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,3),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,4024),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-254),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,3),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,4),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,4008),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-253),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,4),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,5),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3992),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-252),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,5),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,6),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3976),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-251),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,6),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,7),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3960),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-250),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,7),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,8),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3944),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-249),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,8),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,9),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3928),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-248),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,9),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,10),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3912),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-247),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,10),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,11),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3896),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-246),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,11),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,12),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3880),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-245),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,12),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,13),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3864),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-244),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,13),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,14),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3848),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-243),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,14),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,15),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3832),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-242),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,15),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,16),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3816),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-241),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,16),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,17),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3800),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-240),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,17),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,18),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3784),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-239),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,18),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,19),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3768),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-238),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,19),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,20),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3752),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-237),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,20),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,21),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3736),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-236),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,21),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,22),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3720),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-235),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,22),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,23),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3704),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-234),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,23),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,24),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3688),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-233),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,24),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,25),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3672),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-232),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,25),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,26),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3656),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-231),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,26),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,27),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3640),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-230),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,27),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,28),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3624),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-229),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,28),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,29),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3608),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-228),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,29),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,30),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3592),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-227),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,30),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,31),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3576),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-226),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,31),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,32),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3560),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-225),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,32),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,33),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3544),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-224),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,33),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,34),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3528),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-223),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,34),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,35),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3512),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-222),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,35),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,36),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3496),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-221),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,36),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,37),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3480),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-220),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,37),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,38),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3464),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-219),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,38),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,39),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3448),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-218),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,39),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,40),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3432),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-217),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,40),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,41),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3416),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-216),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,41),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,42),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3400),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-215),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,42),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,43),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3384),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-214),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,43),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,44),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3368),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-213),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,44),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,45),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3352),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-212),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,45),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,46),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3336),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-211),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,46),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,47),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3320),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-210),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,47),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,48),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3304),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-209),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,48),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,49),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3288),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-208),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,49),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,50),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3272),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-207),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,50),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,51),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3256),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-206),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,51),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,52),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3240),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-205),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,52),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,53),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3224),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-204),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,53),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,54),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3208),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-203),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,54),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,55),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3192),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-202),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,55),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,56),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3176),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-201),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,56),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,57),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3160),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-200),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,57),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,58),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3144),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-199),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,58),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,59),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3128),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-198),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,59),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,60),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3112),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-197),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,60),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,61),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3096),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-196),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,61),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,62),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3080),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-195),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,62),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,63),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3064),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-194),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,63),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,64),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3048),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-193),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,64),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,65),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3032),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-192),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,65),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,66),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3016),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-191),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,66),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,67),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3000),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-190),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,67),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,68),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2984),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-189),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,68),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,69),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2968),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-188),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,69),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,70),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2952),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-187),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,70),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,71),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2936),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-186),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,71),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,72),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2920),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-185),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,72),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,73),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2904),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-184),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,73),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,74),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2888),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-183),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,74),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,75),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2872),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-182),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,75),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,76),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2856),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-181),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,76),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,77),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2840),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-180),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,77),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,78),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2824),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-179),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,78),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,79),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2808),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-178),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,79),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,80),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2792),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-177),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,80),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,81),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2776),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-176),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,81),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,82),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2760),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-175),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,82),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,83),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2744),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-174),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,83),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,84),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2728),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-173),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,84),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,85),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2712),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-172),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,85),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,86),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2696),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-171),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,86),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,87),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2680),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-170),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,87),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,88),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2664),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-169),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,88),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,89),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2648),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-168),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,89),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,90),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2632),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-167),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,90),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,91),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2616),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-166),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,91),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,92),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2600),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-165),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,92),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,93),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2584),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-164),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,93),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,94),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2568),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-163),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,94),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,95),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2552),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-162),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,95),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,96),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2536),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-161),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,96),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,97),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2520),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-160),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,97),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,98),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2504),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-159),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,98),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,99),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2488),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-158),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,99),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,100),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2472),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-157),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,100),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,101),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2456),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-156),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,101),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,102),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2440),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-155),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,102),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,103),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2424),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-154),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,103),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,104),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2408),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-153),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,104),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,105),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2392),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-152),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,105),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,106),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2376),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-151),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,106),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,107),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2360),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-150),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,107),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,108),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2344),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-149),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,108),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,109),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2328),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-148),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,109),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,110),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2312),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-147),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,110),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,111),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2296),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-146),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,111),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,112),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2280),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-145),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,112),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,113),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2264),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-144),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,113),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,114),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2248),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-143),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,114),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,115),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2232),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-142),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,115),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,116),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2216),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-141),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,116),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,117),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2200),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-140),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,117),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,118),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2184),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-139),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,118),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,119),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2168),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-138),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,119),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,120),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2152),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-137),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,120),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,121),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2136),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-136),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,121),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,122),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2120),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-135),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,122),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,123),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2104),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-134),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,123),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,124),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2088),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-133),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,124),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,125),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2072),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-132),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,125),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,126),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2056),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-131),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,126),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,127),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2040),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-130),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,127),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,128),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2024),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-129),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,128),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,129),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2008),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-128),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,129),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,130),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1992),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-127),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,130),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,131),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1976),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-126),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,131),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,132),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1960),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-125),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,132),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,133),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1944),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-124),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,133),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,134),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1928),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-123),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,134),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,135),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1912),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-122),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,135),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,136),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1896),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-121),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,136),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,137),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1880),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-120),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,137),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,138),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1864),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-119),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,138),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,139),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1848),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-118),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,139),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,140),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1832),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-117),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,140),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,141),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1816),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-116),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,141),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,142),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1800),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-115),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,142),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,143),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1784),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-114),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,143),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,144),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1768),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-113),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,144),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,145),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1752),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-112),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,145),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,146),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1736),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-111),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,146),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,147),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1720),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-110),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,147),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,148),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1704),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-109),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,148),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,149),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1688),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-108),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,149),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,150),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1672),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-107),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,150),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,151),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1656),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-106),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,151),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,152),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1640),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-105),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,152),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,153),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1624),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-104),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,153),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,154),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1608),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-103),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,154),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,155),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1592),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-102),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,155),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,156),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1576),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-101),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,156),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,157),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1560),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-100),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,157),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,158),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1544),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-99),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,158),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,159),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1528),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-98),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,159),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,160),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1512),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-97),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,160),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,161),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1496),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-96),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,161),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,162),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1480),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-95),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,162),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,163),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1464),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-94),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,163),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,164),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1448),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-93),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,164),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,165),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1432),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-92),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,165),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,166),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1416),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-91),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,166),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,167),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1400),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-90),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,167),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,168),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1384),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-89),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,168),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,169),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1368),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-88),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,169),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,170),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1352),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-87),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,170),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,171),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1336),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-86),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,171),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,172),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1320),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-85),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,172),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,173),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1304),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-84),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,173),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,174),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1288),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-83),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,174),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,175),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1272),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-82),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,175),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,176),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1256),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-81),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,176),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,177),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1240),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-80),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,177),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,178),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1224),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-79),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,178),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,179),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1208),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-78),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,179),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,180),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1192),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-77),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,180),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,181),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1176),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-76),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,181),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,182),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1160),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-75),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,182),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,183),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1144),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-74),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,183),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,184),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1128),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-73),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,184),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,185),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1112),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-72),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,185),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,186),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1096),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-71),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,186),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,187),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1080),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-70),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,187),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,188),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1064),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-69),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,188),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,189),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1048),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-68),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,189),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,190),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1032),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-67),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,190),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,191),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1016),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-66),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,191),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,192),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1000),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-65),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,192),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,193),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,984),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-64),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,193),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,194),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,968),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-63),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,194),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,195),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,952),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-62),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,195),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,196),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,936),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-61),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,196),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,197),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,920),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-60),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,197),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,198),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,904),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-59),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,198),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,199),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,888),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-58),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,199),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,200),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,872),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-57),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,200),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,201),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,856),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-56),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,201),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,202),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,840),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-55),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,202),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,203),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,824),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-54),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,203),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,204),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,808),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-53),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,204),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,205),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,792),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-52),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,205),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,206),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,776),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-51),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,206),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,207),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,760),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-50),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,207),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,208),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,744),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-49),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,208),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,209),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,728),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-48),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,209),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,210),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,712),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-47),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,210),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,211),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,696),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-46),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,211),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,212),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,680),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-45),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,212),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,213),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,664),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-44),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,213),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,214),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,648),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-43),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,214),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,215),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,632),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-42),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,215),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,216),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,616),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-41),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,216),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,217),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,600),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-40),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,217),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,218),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,584),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-39),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,218),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,219),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,568),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-38),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,219),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,220),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,552),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-37),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,220),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,221),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,536),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-36),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,221),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,222),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,520),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-35),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,222),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,223),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,504),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-34),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,223),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,224),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,488),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-33),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,224),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,225),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,472),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-32),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,225),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,226),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,456),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-31),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,226),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,227),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,440),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-30),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,227),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,228),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,424),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-29),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,228),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,229),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,408),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-28),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,229),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,230),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,392),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-27),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,230),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,231),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,376),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-26),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,231),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,232),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,360),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-25),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,232),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,233),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,344),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-24),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,233),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,234),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,328),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-23),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,234),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,235),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,312),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-22),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,235),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,236),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,296),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-21),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,236),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,237),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,280),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-20),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,237),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,238),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,264),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-19),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,238),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,239),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,248),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-18),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,239),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,240),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,232),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-17),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,240),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,241),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,216),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-16),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,241),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,242),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,200),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-15),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,242),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,243),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,184),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-14),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,243),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,244),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,168),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-13),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,244),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,245),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,152),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-12),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,245),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,246),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,136),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-11),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,246),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,247),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,120),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-10),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,247),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,248),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,104),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-9),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,248),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,249),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,88),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-8),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,249),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,250),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,72),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-7),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,250),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,251),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,56),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-6),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,251),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,252),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,40),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-5),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,252),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,253),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,24),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-4),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,253),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,254),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,8),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,5),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-3),
+BPF_MOV64_IMM(BPF_REG_9,255),
+BPF_ALU64_REG(BPF_ADD,BPF_REG_9,BPF_REG_7),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_H,BPF_REG_0,BPF_REG_9,0,0),
+BPF_MOV64_REG(BPF_REG_6,BPF_REG_0),
+BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
+BPF_MOV64_IMM(BPF_REG_1,2147483647),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,0,7),
+BPF_LDX_MEM(BPF_H,BPF_REG_2,BPF_REG_0,8),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_2,255,2),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_6,65535),
+BPF_JMP_REG(BPF_JNE,BPF_REG_6,BPF_REG_2,3),
+BPF_MOV64_IMM(BPF_REG_1,1),
+BPF_RAW_INSN(BPF_STX|BPF_XADD|BPF_DW,BPF_REG_0,BPF_REG_1,0,0),
+BPF_MOV64_IMM(BPF_REG_1,0),
+BPF_MOV64_REG(BPF_REG_0,BPF_REG_1),
+BPF_EXIT_INSN(),
CFLAGS="-g -O3 -Wall -Wextra -Wshadow -Wno-unused-parameter -fvisibility=hidden $CFLAGS"
CXXFLAGS="-g -O3 -Wall -Wextra -Wshadow -Wno-unused-parameter -Wmissing-declarations -Wredundant-decls -fvisibility=hidden $CXXFLAGS"
+AC_SUBST([pdns_configure_args], ["$ac_configure_args"])
+AC_DEFINE_UNQUOTED([DNSDIST_CONFIG_ARGS],
+ ["$pdns_configure_args"],
+ [pdns configure arguments]
+)
+
PDNS_WITH_LIBSODIUM
PDNS_WITH_QUICHE
PDNS_CHECK_DNSTAP([auto])
PDNS_CHECK_SECURE_MEMSET
AC_FUNC_STRERROR_R
-BOOST_REQUIRE([1.42])
+BOOST_REQUIRE([1.54])
PDNS_ENABLE_UNIT_TESTS
PDNS_ENABLE_FUZZ_TARGETS
+++ /dev/null
-../delaypipe.cc
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "delaypipe.hh"
+#include "misc.hh"
+#include "gettime.hh"
+#include <thread>
+#include "threadname.hh"
+
+template <class T>
+ObjectPipe<T>::ObjectPipe()
+{
+ auto [sender, receiver] = pdns::channel::createObjectQueue<T>(pdns::channel::SenderBlockingMode::SenderBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, 0, false);
+ d_sender = std::move(sender);
+ d_receiver = std::move(receiver);
+}
+
+template <class T>
+void ObjectPipe<T>::close()
+{
+ d_sender.close();
+}
+
+template <class T>
+void ObjectPipe<T>::write(T& t)
+{
+ auto ptr = std::make_unique<T>(t);
+ if (!d_sender.send(std::move(ptr))) {
+ unixDie("writing to the DelayPipe");
+ }
+}
+
+template <class T>
+int ObjectPipe<T>::readTimeout(T* t, double msec)
+{
+ while (true) {
+ int ret = waitForData(d_receiver.getDescriptor(), 0, 1000 * msec);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ unixDie("waiting for data in object pipe");
+ }
+ else if (ret == 0) {
+ return -1;
+ }
+
+ try {
+ auto tmp = d_receiver.receive();
+ if (!tmp) {
+ if (d_receiver.isClosed()) {
+ return 0;
+ }
+ continue;
+ }
+
+ *t = **tmp;
+ return 1;
+ }
+ catch (const std::exception& e) {
+ throw std::runtime_error("reading from the delay pipe: " + std::string(e.what()));
+ }
+ }
+}
+
+template <class T>
+DelayPipe<T>::DelayPipe() :
+ d_thread(&DelayPipe<T>::worker, this)
+{
+}
+
+template <class T>
+void DelayPipe<T>::gettime(struct timespec* ts)
+{
+ ::gettime(ts);
+}
+
+template <class T>
+void DelayPipe<T>::submit(T& t, int msec)
+{
+ struct timespec now;
+ gettime(&now);
+ now.tv_nsec += msec * 1e6;
+ while (now.tv_nsec > 1e9) {
+ now.tv_sec++;
+ now.tv_nsec -= 1e9;
+ }
+ Combo c{t, now};
+ d_pipe.write(c);
+}
+
+template <class T>
+DelayPipe<T>::~DelayPipe()
+{
+ d_pipe.close();
+ d_thread.join();
+}
+
+template <class T>
+void DelayPipe<T>::worker()
+{
+ setThreadName("dnsdist/delayPi");
+ Combo c;
+ for (;;) {
+ /* this code is slightly too subtle, but I don't see how it could be any simpler.
+ So we have a set of work to do, and we need to wait until the time arrives to do it.
+ Simultaneously new work might come in. So we try to combine both of these things by
+ setting a timeout on listening to the pipe over which new work comes in. This timeout
+ is equal to the wait until the first thing that needs to be done.
+
+ Two additional cases exist: we have no work to wait for, so we can wait infinitely long.
+ The other special case is that the first we have to do.. is in the past, so we need to do it
+ immediately. */
+
+ double delay = -1; // infinite
+ struct timespec now;
+ if (!d_work.empty()) {
+ gettime(&now);
+ delay = 1000 * tsdelta(d_work.begin()->first, now);
+ if (delay < 0) {
+ delay = 0; // don't wait - we have work that is late already!
+ }
+ }
+ if (delay != 0) {
+ int ret = d_pipe.readTimeout(&c, delay);
+ if (ret > 0) { // we got an object
+ d_work.emplace(c.when, c.what);
+ }
+ else if (ret == 0) { // EOF
+ break;
+ }
+ else {
+ ;
+ }
+ gettime(&now);
+ }
+
+ tscomp cmp;
+
+ for (auto iter = d_work.begin(); iter != d_work.end();) { // do the needful
+ if (cmp(iter->first, now)) {
+ iter->second();
+ d_work.erase(iter++);
+ }
+ else {
+ break;
+ }
+ }
+ }
+}
+++ /dev/null
-../delaypipe.hh
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <time.h>
+#include <thread>
+
+#include "channel.hh"
+
+/**
+ General idea: many threads submit work to this class, but only one executes it. The work should therefore be entirely trivial.
+ The implementation is that submitter threads create an object that represents the work, and it gets sent over a pipe
+ to the worker thread.
+
+ The worker thread meanwhile listens on this pipe (non-blocking), with a delay set to the next object that needs to be executed.
+ If meanwhile new work comes in, all objects who's time has come are executed, a new sleep time is calculated.
+*/
+
+/* ObjectPipe facilitates the type-safe passing of types over a pipe */
+
+template <class T>
+class ObjectPipe
+{
+public:
+ ObjectPipe();
+ void write(T& t);
+ int readTimeout(T* t, double msec); //!< -1 is timeout, 0 is no data, 1 is data. msec<0 waits infinitely long. msec==0 = undefined
+ void close();
+
+private:
+ pdns::channel::Sender<T> d_sender;
+ pdns::channel::Receiver<T> d_receiver;
+};
+
+template <class T>
+class DelayPipe
+{
+public:
+ DelayPipe();
+ ~DelayPipe();
+ void submit(T& t, int msec); //!< don't try for more than 4294 msec
+
+private:
+ void worker();
+ struct Combo
+ {
+ T what;
+ struct timespec when;
+ };
+
+ double tsdelta(const struct timespec& a, const struct timespec& b) // read as a-b
+ {
+ return 1.0 * (a.tv_sec - b.tv_sec) + 1.0 * (a.tv_nsec - b.tv_nsec) / 1000000000.0;
+ }
+
+ ObjectPipe<Combo> d_pipe;
+ struct tscomp
+ {
+ bool operator()(const struct timespec& a, const struct timespec& b) const
+ {
+ return std::tie(a.tv_sec, a.tv_nsec) < std::tie(b.tv_sec, b.tv_nsec);
+ }
+ };
+ std::multimap<struct timespec, T, tscomp> d_work;
+ void gettime(struct timespec* ts);
+ std::thread d_thread;
+};
+
+#include "delaypipe.cc"
bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut)
{
bool success = false;
- DNSCryptCertSignedData::ResolverPrivateKeyType providerPrivateKey;
+ DNSCryptCertSignedData::ResolverPrivateKeyType providerPrivateKey{};
sodium_mlock(providerPrivateKey.data(), providerPrivateKey.size());
sodium_memzero(providerPrivateKey.data(), providerPrivateKey.size());
using ResolverPublicKeyType = std::array<unsigned char, DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE>;
using ResolverPrivateKeyType = std::array<unsigned char, DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE>;
using ClientMagicType = std::array<unsigned char, DNSCRYPT_CLIENT_MAGIC_SIZE>;
- ResolverPublicKeyType resolverPK;
- ClientMagicType clientMagic;
+ ResolverPublicKeyType resolverPK{};
+ ClientMagicType clientMagic{};
uint32_t serial{0};
uint32_t tsStart{0};
uint32_t tsEnd{0};
using ESVersionType = std::array<unsigned char, 2>;
using ProtocolMinorVersionType = std::array<unsigned char, 2>;
using CertMagicType = std::array<unsigned char, DNSCRYPT_CERT_MAGIC_SIZE>;
- CertMagicType magic;
- ESVersionType esVersion;
- ProtocolMinorVersionType protocolMinorVersion;
- std::array<unsigned char, DNSCRYPT_SIGNATURE_SIZE> signature;
+ CertMagicType magic{};
+ ESVersionType esVersion{};
+ ProtocolMinorVersionType protocolMinorVersion{};
+ std::array<unsigned char, DNSCRYPT_SIGNATURE_SIZE> signature{};
DNSCryptCertSignedData signedData;
};
void getCertificateResponse(time_t now, PacketBuffer& response) const;
int encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp);
- static const size_t s_minUDPLength = 256;
+ static constexpr size_t s_minUDPLength = 256;
private:
static void fillServerNonce(DNSCryptNonceType& nonce);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+/* so what could you do:
+ drop,
+ fake up nxdomain,
+ provide actual answer,
+ allow & and stop processing,
+ continue processing,
+ modify header: (servfail|refused|notimp), set TC=1,
+ send to pool */
+
+struct DNSQuestion;
+struct DNSResponse;
+
+class DNSAction
+{
+public:
+ enum class Action : uint8_t
+ {
+ Drop,
+ Nxdomain,
+ Refused,
+ Spoof,
+ Allow,
+ HeaderModify,
+ Pool,
+ Delay,
+ Truncate,
+ ServFail,
+ None,
+ NoOp,
+ NoRecurse,
+ SpoofRaw,
+ SpoofPacket,
+ SetTag,
+ };
+ static std::string typeToString(const Action& action)
+ {
+ switch (action) {
+ case Action::Drop:
+ return "Drop";
+ case Action::Nxdomain:
+ return "Send NXDomain";
+ case Action::Refused:
+ return "Send Refused";
+ case Action::Spoof:
+ return "Spoof an answer";
+ case Action::SpoofPacket:
+ return "Spoof a raw answer from bytes";
+ case Action::SpoofRaw:
+ return "Spoof an answer from raw bytes";
+ case Action::Allow:
+ return "Allow";
+ case Action::HeaderModify:
+ return "Modify the header";
+ case Action::Pool:
+ return "Route to a pool";
+ case Action::Delay:
+ return "Delay";
+ case Action::Truncate:
+ return "Truncate over UDP";
+ case Action::ServFail:
+ return "Send ServFail";
+ case Action::SetTag:
+ return "Set Tag";
+ case Action::None:
+ case Action::NoOp:
+ return "Do nothing";
+ case Action::NoRecurse:
+ return "Set rd=0";
+ }
+
+ return "Unknown";
+ }
+
+ virtual Action operator()(DNSQuestion*, std::string* ruleresult) const = 0;
+ virtual ~DNSAction() = default;
+ virtual std::string toString() const = 0;
+ virtual std::map<std::string, double> getStats() const
+ {
+ return {{}};
+ }
+ virtual void reload()
+ {
+ }
+};
+
+class DNSResponseAction
+{
+public:
+ enum class Action : uint8_t
+ {
+ Allow,
+ Delay,
+ Drop,
+ HeaderModify,
+ ServFail,
+ Truncate,
+ None
+ };
+ virtual Action operator()(DNSResponse*, std::string* ruleresult) const = 0;
+ virtual ~DNSResponseAction() = default;
+ virtual std::string toString() const = 0;
+ virtual void reload()
+ {
+ }
+};
#include "dnsdist-async.hh"
#include "dnsdist-internal-queries.hh"
#include "dolog.hh"
+#include "mplexer.hh"
#include "threadname.hh"
namespace dnsdist
auto& ids = response->query.d_idstate;
DNSResponse dnsResponse = response->getDR();
- LocalHolders holders;
- auto result = processResponseAfterRules(response->query.d_buffer, *holders.cacheInsertedRespRuleActions, dnsResponse, ids.cs->muted);
+ auto result = processResponseAfterRules(response->query.d_buffer, dnsResponse, ids.cs->muted);
if (!result) {
/* easy */
return true;
}
DNSQuestion dnsQuestion = query->getDQ();
- LocalHolders holders;
- auto result = processQueryAfterRules(dnsQuestion, holders, query->downstream);
+ auto result = processQueryAfterRules(dnsQuestion, query->downstream);
if (result == ProcessQueryResult::Drop) {
/* easy */
return true;
uint16_t d_queryID;
};
- typedef multi_index_container<
+ using content_t = multi_index_container<
Entry,
indexed_by<
ordered_unique<tag<IDTag>,
member<Entry, uint16_t, &Entry::d_queryID>,
member<Entry, uint16_t, &Entry::d_asyncID>>>,
ordered_non_unique<tag<TTDTag>,
- member<Entry, struct timeval, &Entry::d_ttd>>>>
- content_t;
+ member<Entry, struct timeval, &Entry::d_ttd>>>>;
static void pickupExpired(content_t&, const struct timeval& now, std::list<std::pair<uint16_t, std::unique_ptr<CrossProtocolQuery>>>& expiredEvents);
static struct timeval getNextTTD(const content_t&);
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <boost/format.hpp>
+
#include "config.h"
#include "dnsdist.hh"
+#include "dnsdist-backend.hh"
#include "dnsdist-backoff.hh"
#include "dnsdist-metrics.hh"
#include "dnsdist-nghttp2.hh"
#include "dnsdist-random.hh"
#include "dnsdist-rings.hh"
+#include "dnsdist-snmp.hh"
#include "dnsdist-tcp.hh"
#include "dnsdist-xsk.hh"
#include "dolog.hh"
connected = true;
}
catch (const std::runtime_error& error) {
- if (initialAttempt || g_verbose) {
+ if (initialAttempt || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
infolog("Error connecting to new server with address %s: %s", d_config.remote.toStringWithPort(), error.what());
}
connected = false;
void DownstreamState::hash()
{
vinfolog("Computing hashes for id=%s and weight=%d", *d_config.id, d_config.d_weight);
+ const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
auto w = d_config.d_weight;
auto idStr = boost::str(boost::format("%s") % *d_config.id);
auto lockedHashes = hashes.write_lock();
lockedHashes->reserve(w);
while (w > 0) {
std::string uuid = boost::str(boost::format("%s-%d") % idStr % w);
- unsigned int wshash = burtleCI(reinterpret_cast<const unsigned char*>(uuid.c_str()), uuid.size(), g_hashperturb);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): sorry, it's the burtle API
+ unsigned int wshash = burtleCI(reinterpret_cast<const unsigned char*>(uuid.c_str()), uuid.size(), hashPerturbation);
lockedHashes->push_back(wshash);
--w;
}
setName(d_config.name);
- if (d_tlsCtx) {
- if (!d_config.d_dohPath.empty()) {
+ if (d_tlsCtx && !d_config.d_dohPath.empty()) {
#ifdef HAVE_NGHTTP2
- setupDoHClientProtocolNegotiation(d_tlsCtx);
-
- if (g_configurationDone && g_outgoingDoHWorkerThreads && *g_outgoingDoHWorkerThreads == 0) {
- throw std::runtime_error("Error: setOutgoingDoHWorkerThreads() is set to 0 so no outgoing DoH worker thread is available to serve queries");
- }
-
- if (!g_outgoingDoHWorkerThreads || *g_outgoingDoHWorkerThreads == 0) {
- g_outgoingDoHWorkerThreads = 1;
- }
-#endif /* HAVE_NGHTTP2 */
+ auto outgoingDoHWorkerThreads = dnsdist::configuration::getImmutableConfiguration().d_outgoingDoHWorkers;
+ if (dnsdist::configuration::isImmutableConfigurationDone() && outgoingDoHWorkerThreads && *outgoingDoHWorkerThreads == 0) {
+ throw std::runtime_error("Error: setOutgoingDoHWorkerThreads() is set to 0 so no outgoing DoH worker thread is available to serve queries");
}
- else {
- setupDoTProtocolNegotiation(d_tlsCtx);
+
+ if (!dnsdist::configuration::isImmutableConfigurationDone() && (!outgoingDoHWorkerThreads || *outgoingDoHWorkerThreads == 0)) {
+ dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::ImmutableConfiguration& immutableConfig) {
+ immutableConfig.d_outgoingDoHWorkers = 1;
+ });
}
+#endif /* HAVE_NGHTTP2 */
}
if (connect && !isTCPOnly()) {
void DownstreamState::connectUDPSockets()
{
- if (s_randomizeIDs) {
+ const auto& config = dnsdist::configuration::getImmutableConfiguration();
+ if (config.d_randomizeIDsToBackend) {
idStates.clear();
}
else {
- idStates.resize(g_maxOutstanding);
+ idStates.resize(config.d_maxUDPOutstanding);
}
sockets.resize(d_config.d_numberOfSockets);
return sockets[0];
}
- size_t idx;
- if (s_randomizeSockets) {
+ size_t idx{0};
+ if (dnsdist::configuration::getImmutableConfiguration().d_randomizeUDPSocketsToBackend) {
idx = dnsdist::getRandomValue(numberOfSockets);
}
else {
(*mplexer.lock())->getAvailableFDs(ready, 1000);
}
-bool DownstreamState::s_randomizeSockets{false};
-bool DownstreamState::s_randomizeIDs{false};
-int DownstreamState::s_udpTimeout{2};
-
-static bool isIDSExpired(const IDState& ids)
+static bool isIDSExpired(const IDState& ids, uint8_t udpTimeout)
{
auto age = ids.age.load();
- return age > DownstreamState::s_udpTimeout;
+ return age > udpTimeout;
}
void DownstreamState::handleUDPTimeout(IDState& ids)
return;
}
- if (s_randomizeIDs) {
+ const auto& config = dnsdist::configuration::getImmutableConfiguration();
+ const auto udpTimeout = config.d_udpTimeout;
+ if (config.d_randomizeIDsToBackend) {
auto map = d_idStatesMap.lock();
for (auto it = map->begin(); it != map->end(); ) {
auto& ids = it->second;
- if (isIDSExpired(ids)) {
+ if (isIDSExpired(ids, udpTimeout)) {
handleUDPTimeout(ids);
it = map->erase(it);
continue;
if (!ids.isInUse()) {
continue;
}
- if (!isIDSExpired(ids)) {
+ if (!isIDSExpired(ids, udpTimeout)) {
++ids.age;
continue;
}
continue;
}
/* check again, now that we have locked this state */
- if (ids.isInUse() && isIDSExpired(ids)) {
+ if (ids.isInUse() && isIDSExpired(ids, udpTimeout)) {
handleUDPTimeout(ids);
}
}
uint16_t DownstreamState::saveState(InternalQueryState&& state)
{
- if (s_randomizeIDs) {
+ const auto& config = dnsdist::configuration::getImmutableConfiguration();
+ if (config.d_randomizeIDsToBackend) {
/* if the state is already in use we will retry,
up to 5 five times. The last selected one is used
even if it was already in use */
void DownstreamState::restoreState(uint16_t id, InternalQueryState&& state)
{
- if (s_randomizeIDs) {
+ const auto& config = dnsdist::configuration::getImmutableConfiguration();
+ if (config.d_randomizeIDsToBackend) {
auto map = d_idStatesMap.lock();
auto [it, inserted] = map->emplace(id, IDState());
std::optional<InternalQueryState> DownstreamState::getState(uint16_t id)
{
std::optional<InternalQueryState> result = std::nullopt;
-
- if (s_randomizeIDs) {
+ const auto& config = dnsdist::configuration::getImmutableConfiguration();
+ if (config.d_randomizeIDsToBackend) {
auto map = d_idStatesMap.lock();
auto it = map->find(id);
currentCheckFailures = 0;
consecutiveSuccessfulChecks++;
- if (!upStatus) {
+ if (!upStatus.load(std::memory_order_relaxed)) {
/* we were previously marked as "down" and had a successful health-check,
let's see if this is enough to move to the "up" state or if we need
more successful health-checks for that */
currentCheckFailures++;
- if (upStatus) {
+ if (upStatus.load(std::memory_order_relaxed)) {
/* we were previously marked as "up" and failed a health-check,
let's see if this is enough to move to the "down" state or if
need more failed checks for that */
}
}
- if (newState != upStatus) {
+ if (newState != upStatus.load(std::memory_order_relaxed)) {
/* we are actually moving to a new state */
if (!IsAnyAddress(d_config.remote)) {
infolog("Marking downstream %s as '%s'", getNameWithAddr(), newState ? "up" : "down");
}
setUpStatus(newState);
- if (g_snmpAgent && g_snmpTrapsEnabled) {
+ if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
g_snmpAgent->sendBackendStatusChangeTrap(*this);
}
}
d_config.sourceMACAddr = d_xskSockets.at(0)->getSourceMACAddress();
for (auto& xsk : d_xskSockets) {
- auto xskInfo = XskWorker::create();
+ auto xskInfo = XskWorker::create(XskWorker::Type::Bidirectional, xsk->sharedEmptyFrameOffset);
d_xskInfos.push_back(xskInfo);
xsk->addWorker(xskInfo);
- xskInfo->sharedEmptyFrameOffset = xsk->sharedEmptyFrameOffset;
}
reconnect(false);
}
}
*servers = std::move(newServers);
}
+
+namespace dnsdist::backend
+{
+void registerNewBackend(std::shared_ptr<DownstreamState>& backend)
+{
+ dnsdist::configuration::updateRuntimeConfiguration([&backend](dnsdist::configuration::RuntimeConfiguration& config) {
+ auto& backends = config.d_backends;
+ backends.push_back(backend);
+ std::stable_sort(backends.begin(), backends.end(), [](const std::shared_ptr<DownstreamState>& lhs, const std::shared_ptr<DownstreamState>& rhs) {
+ return lhs->d_config.order < rhs->d_config.order;
+ });
+ });
+}
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <memory>
+
+struct DownstreamState;
+
+namespace dnsdist::backend
+{
+void registerNewBackend(std::shared_ptr<DownstreamState>& backend);
+}
uint16_t optRDPosition = 0;
size_t remaining = 0;
- int res = getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
+ int res = dnsdist::getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
if (res == 0) {
size_t ecsOptionStartPosition = 0;
#endif
#include "dnsdist-carbon.hh"
+#include "dnsdist-cache.hh"
#include "dnsdist.hh"
#include "dnsdist-backoff.hh"
+#include "dnsdist-configuration.hh"
+#include "dnsdist-frontend.hh"
#include "dnsdist-metrics.hh"
#ifndef DISABLE_CARBON
namespace dnsdist
{
-LockGuarded<Carbon::Config> Carbon::s_config;
-
static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
{
const auto& server = endpoint.server;
if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
str << (*val)->load();
}
- else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&entry.d_value)) {
str << (*adval)->load();
}
- else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
- str << **dval;
- }
else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
str << (*func)(entry.d_name);
}
}
}
- auto states = g_dstates.getLocal();
- for (const auto& state : *states) {
+ for (const auto& state : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
string serverName = state->getName().empty() ? state->d_config.remote.toStringWithPort() : state->getName();
boost::replace_all(serverName, ".", "_");
string base = namespace_name;
}
std::map<std::string, uint64_t> frontendDuplicates;
- for (const auto& front : g_frontends) {
+ for (const auto& front : dnsdist::getFrontends()) {
if (front->udpFD == -1 && front->tcpFD == -1) {
continue;
}
}
}
- auto localPools = g_pools.getLocal();
- for (const auto& entry : *localPools) {
+ for (const auto& entry : dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools) {
string poolName = entry.first;
boost::replace_all(poolName, ".", "_");
if (poolName.empty()) {
{
std::map<std::string, uint64_t> dohFrontendDuplicates;
const string base = "dnsdist." + hostname + ".main.doh.";
- for (const auto& doh : g_dohlocals) {
+ for (const auto& doh : dnsdist::getDoHFrontends()) {
string name = doh->d_tlsContext.d_addr.toStringWithPort();
boost::replace_all(name, ".", "_");
boost::replace_all(name, ":", "_");
{
std::string qname;
- auto records = g_qcount.records.write_lock();
+ auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
for (const auto& record : *records) {
qname = record.first;
boost::replace_all(qname, ".", "_");
return true;
}
-static void carbonHandler(Carbon::Endpoint&& endpoint)
+static void carbonHandler(const Carbon::Endpoint& endpoint)
{
setThreadName("dnsdist/carbon");
const auto intervalUSec = endpoint.interval * 1000 * 1000;
}
}
-bool Carbon::addEndpoint(Carbon::Endpoint&& endpoint)
+Carbon::Endpoint Carbon::newEndpoint(const std::string& address, std::string ourName, uint64_t interval, const std::string& namespace_name, const std::string& instance_name)
{
- if (endpoint.ourname.empty()) {
+ if (ourName.empty()) {
try {
- endpoint.ourname = getCarbonHostName();
+ ourName = getCarbonHostName();
}
- catch (const std::exception& e) {
- throw std::runtime_error(std::string("The 'ourname' setting in 'carbonServer()' has not been set and we are unable to determine the system's hostname: ") + e.what());
+ catch (const std::exception& exp) {
+ throw std::runtime_error(std::string("The 'ourname' setting in 'carbonServer()' has not been set and we are unable to determine the system's hostname: ") + exp.what());
}
}
-
- auto config = s_config.lock();
- if (config->d_running) {
- // we already started the threads, let's just spawn a new one
- std::thread newHandler(carbonHandler, std::move(endpoint));
- newHandler.detach();
- }
- else {
- config->d_endpoints.push_back(std::move(endpoint));
- }
- return true;
+ return Carbon::Endpoint{ComboAddress(address, 2003),
+ !namespace_name.empty() ? namespace_name : "dnsdist",
+ std::move(ourName),
+ !instance_name.empty() ? instance_name : "main",
+ interval < std::numeric_limits<unsigned int>::max() ? static_cast<unsigned int>(interval) : 30};
}
-void Carbon::run()
+void Carbon::run(const std::vector<Carbon::Endpoint>& endpoints)
{
- auto config = s_config.lock();
- if (config->d_running) {
- throw std::runtime_error("The carbon threads are already running");
- }
- for (auto& endpoint : config->d_endpoints) {
- std::thread newHandler(carbonHandler, std::move(endpoint));
+ for (const auto& endpoint : endpoints) {
+ std::thread newHandler(carbonHandler, endpoint);
newHandler.detach();
}
- config->d_endpoints.clear();
- config->d_running = true;
}
}
#include "config.h"
#ifndef DISABLE_CARBON
-
-#include <thread>
+#include <string>
#include "iputils.hh"
-#include "lock.hh"
namespace dnsdist
{
unsigned int interval;
};
- static bool addEndpoint(Endpoint&& endpoint);
- static void run();
-
-private:
- struct Config
- {
- std::vector<Endpoint> d_endpoints;
- bool d_running{false};
- };
-
- static LockGuarded<Config> s_config;
+ static Endpoint newEndpoint(const std::string& address, std::string ourName, uint64_t interval, const std::string& namespace_name, const std::string& instance_name);
+ static void run(const std::vector<Endpoint>& endpoints);
};
}
#include <map>
#include "iputils.hh"
#include "lock.hh"
+#include "dnsdist-configuration.hh"
namespace dnsdist
{
public:
static bool accountNewTCPConnection(const ComboAddress& from)
{
- if (s_maxTCPConnectionsPerClient == 0) {
+ const auto maxConnsPerClient = dnsdist::configuration::getImmutableConfiguration().d_maxTCPConnectionsPerClient;
+ if (maxConnsPerClient == 0) {
return true;
}
auto db = s_tcpClientsConcurrentConnectionsCount.lock();
auto& count = (*db)[from];
- if (count >= s_maxTCPConnectionsPerClient) {
+ if (count >= maxConnsPerClient) {
return false;
}
++count;
static void accountClosedTCPConnection(const ComboAddress& from)
{
- if (s_maxTCPConnectionsPerClient == 0) {
+ const auto maxConnsPerClient = dnsdist::configuration::getImmutableConfiguration().d_maxTCPConnectionsPerClient;
+ if (maxConnsPerClient == 0) {
return;
}
auto db = s_tcpClientsConcurrentConnectionsCount.lock();
}
}
- static void setMaxTCPConnectionsPerClient(size_t max)
- {
- s_maxTCPConnectionsPerClient = max;
- }
-
private:
static LockGuarded<std::map<ComboAddress, size_t, ComboAddress::addressOnlyLessThan>> s_tcpClientsConcurrentConnectionsCount;
- static size_t s_maxTCPConnectionsPerClient;
};
}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-configuration.hh"
+#include "sholder.hh"
+
+namespace dnsdist::configuration
+{
+static GlobalStateHolder<RuntimeConfiguration> s_currentRuntimeConfiguration;
+static ImmutableConfiguration s_immutableConfiguration;
+static std::atomic<bool> s_immutableConfigurationDone{false};
+
+const RuntimeConfiguration& getCurrentRuntimeConfiguration()
+{
+ static thread_local auto t_threadLocalConfiguration = s_currentRuntimeConfiguration.getLocal();
+ return *t_threadLocalConfiguration;
+}
+
+void updateRuntimeConfiguration(const std::function<void(RuntimeConfiguration&)>& mutator)
+{
+ s_currentRuntimeConfiguration.modify(mutator);
+}
+
+void updateImmutableConfiguration(const std::function<void(ImmutableConfiguration&)>& mutator)
+{
+ if (isImmutableConfigurationDone()) {
+ throw std::runtime_error("Trying to update an immutable setting at runtime!");
+ }
+
+ mutator(s_immutableConfiguration);
+}
+
+const ImmutableConfiguration& getImmutableConfiguration()
+{
+ return s_immutableConfiguration;
+}
+
+bool isImmutableConfigurationDone()
+{
+ return s_immutableConfigurationDone.load();
+}
+
+void setImmutableConfigurationDone()
+{
+ if (s_immutableConfigurationDone.exchange(true)) {
+ throw std::runtime_error("Trying to seal the runtime-immutable configuration a second time");
+ }
+}
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+
+#include "config.h"
+#include "credentials.hh"
+#include "dnsdist-actions.hh"
+#include "dnsdist-carbon.hh"
+#include "dnsdist-query-count.hh"
+#include "dnsdist-rule-chains.hh"
+#include "iputils.hh"
+
+class ServerPolicy;
+struct ServerPool;
+struct DownstreamState;
+struct ClientState;
+
+using servers_t = std::vector<std::shared_ptr<DownstreamState>>;
+
+namespace dnsdist::configuration
+{
+/* This part of the configuration is compile-time only */
+/* when we add EDNS to a query, we don't want to advertise
+ a large buffer size */
+static constexpr size_t s_EdnsUDPPayloadSize{512};
+static constexpr uint16_t s_defaultPayloadSizeSelfGenAnswers = 1232;
+static constexpr uint16_t s_udpIncomingBufferSize{1500}; // don't accept UDP queries larger than this value
+static_assert(s_defaultPayloadSizeSelfGenAnswers < s_udpIncomingBufferSize, "The UDP responder's payload size should be smaller or equal to our incoming buffer size");
+
+/* this part of the configuration can only be updated at configuration
+ time, and is immutable once the configuration phase is over */
+struct ImmutableConfiguration
+{
+ std::set<std::string> d_capabilitiesToRetain;
+ std::vector<uint32_t> d_tcpFastOpenKey;
+ std::vector<std::shared_ptr<ClientState>> d_frontends;
+#ifdef __linux__
+ // On Linux this gives us 128k pending queries (default is 8192 queries),
+ // which should be enough to deal with huge spikes
+ uint64_t d_maxTCPQueuedConnections{10000};
+ size_t d_tcpInternalPipeBufferSize{1048576U};
+#else
+ uint64_t d_maxTCPQueuedConnections{1000};
+ size_t d_tcpInternalPipeBufferSize{0};
+#endif
+ double d_weightedBalancingFactor{0};
+ double d_consistentHashBalancingFactor{0};
+ std::optional<uint64_t> d_outgoingDoHWorkers{std::nullopt};
+ uint64_t d_consoleMaxConcurrentConnections{0};
+ uint64_t d_outgoingDoHMaxIdleTime{300};
+ uint64_t d_outgoingTCPMaxIdleTime{300};
+ uint64_t d_outgoingDoHCleanupInterval{60};
+ uint64_t d_outgoingTCPCleanupInterval{60};
+ uint64_t d_outgoingDoHMaxIdlePerBackend{10};
+ uint64_t d_outgoingTCPMaxIdlePerBackend{10};
+ uint64_t d_maxTCPClientThreads{0};
+ size_t d_maxTCPConnectionsPerClient{0};
+ size_t d_udpVectorSize{1};
+ size_t d_ringsCapacity{10000};
+ size_t d_ringsNumberOfShards{10};
+ size_t d_ringsNbLockTries{5};
+ uint32_t d_socketUDPSendBuffer{0};
+ uint32_t d_socketUDPRecvBuffer{0};
+ uint32_t d_hashPerturbation{0};
+ uint16_t d_maxUDPOutstanding{std::numeric_limits<uint16_t>::max()};
+ uint8_t d_udpTimeout{2};
+ bool d_randomizeUDPSocketsToBackend{false};
+ bool d_randomizeIDsToBackend{false};
+ bool d_ringsRecordQueries{true};
+ bool d_ringsRecordResponses{true};
+};
+
+/* this part of the configuration can be updated at runtime via
+ a RCU-like mechanism */
+struct RuntimeConfiguration
+{
+ rules::RuleChains d_ruleChains;
+ servers_t d_backends;
+#ifndef DISABLE_CARBON
+ std::vector<dnsdist::Carbon::Endpoint> d_carbonEndpoints;
+#endif /* DISABLE_CARBON */
+ std::map<std::string, std::shared_ptr<ServerPool>> d_pools;
+ std::shared_ptr<const CredentialsHolder> d_webPassword;
+ std::shared_ptr<const CredentialsHolder> d_webAPIKey;
+ std::optional<std::unordered_map<std::string, std::string>> d_webCustomHeaders;
+ std::shared_ptr<ServerPolicy> d_lbPolicy;
+ NetmaskGroup d_ACL;
+ NetmaskGroup d_proxyProtocolACL;
+ NetmaskGroup d_consoleACL;
+ NetmaskGroup d_webServerACL;
+ std::optional<ComboAddress> d_webServerAddress{std::nullopt};
+ dnsdist::QueryCount::Configuration d_queryCountConfig;
+ ComboAddress d_consoleServerAddress{"127.0.0.1:5199"};
+ std::string d_consoleKey;
+ std::string d_secPollSuffix{"secpoll.powerdns.com."};
+ std::string d_apiConfigDirectory;
+ uint64_t d_dynBlocksPurgeInterval{60};
+ size_t d_maxTCPQueriesPerConn{0};
+ size_t d_maxTCPConnectionDuration{0};
+ size_t d_proxyProtocolMaximumSize{512};
+ uint32_t d_staleCacheEntriesTTL{0};
+ uint32_t d_secPollInterval{3600};
+ uint32_t d_consoleOutputMsgMaxSize{10000000};
+ uint16_t d_payloadSizeSelfGenAnswers{s_defaultPayloadSizeSelfGenAnswers};
+ uint16_t d_tcpRecvTimeout{2};
+ uint16_t d_tcpSendTimeout{2};
+ /* rfc7871: "11.1. Privacy" */
+ uint16_t d_ECSSourcePrefixV4{24};
+ uint16_t d_ECSSourcePrefixV6{56};
+ uint16_t d_cacheCleaningDelay{60};
+ uint16_t d_cacheCleaningPercentage{100};
+ uint16_t d_tlsSessionCacheCleanupDelay{60};
+ uint16_t d_tlsSessionCacheSessionValidity{600};
+ uint16_t d_tlsSessionCacheMaxSessionsPerBackend{20};
+ DNSAction::Action d_dynBlockAction{DNSAction::Action::Drop};
+ bool d_apiRequiresAuthentication{true};
+ bool d_dashboardRequiresAuthentication{true};
+ bool d_statsRequireAuthentication{true};
+ bool d_truncateTC{false};
+ bool d_fixupCase{false};
+ bool d_queryCountEnabled{false};
+ bool d_ecsOverride{false};
+ bool d_verbose{false};
+ bool d_verboseHealthChecks{false};
+ bool d_apiReadWrite{false};
+ bool d_roundrobinFailOnNoServer{false};
+ bool d_servFailOnNoPolicy{false};
+ bool d_allowEmptyResponse{false};
+ bool d_dropEmptyQueries{false};
+ bool d_snmpEnabled{false};
+ bool d_snmpTrapsEnabled{false};
+ bool d_consoleEnabled{false};
+ bool d_logConsoleConnections{true};
+ bool d_addEDNSToSelfGeneratedResponses{true};
+ bool d_applyACLToProxiedClients{false};
+};
+
+/* Be careful not to hold on this for too long, it can be invalidated
+ by the next call to getCurrentRuntimeConfiguration() from the
+ same thread, so better be sure that any function you are not calling
+ while holding to this reference does not call getCurrentRuntimeConfiguration()
+ itself. When in doubt, better call getCurrentRuntimeConfiguration() twice.
+*/
+const RuntimeConfiguration& getCurrentRuntimeConfiguration();
+/* Get the runtime-immutable configuration */
+const ImmutableConfiguration& getImmutableConfiguration();
+/* Update the runtime-immutable part of the configuration. This function can only be called
+ during configuration time (isConfigurationDone() returns false), and will throw otherwise. */
+void updateImmutableConfiguration(const std::function<void(ImmutableConfiguration&)>& mutator);
+void updateRuntimeConfiguration(const std::function<void(RuntimeConfiguration&)>& mutator);
+/* Whether parsing the configuration is done, meaning the runtime-immutable part of the
+ configuration is now sealed */
+bool isImmutableConfigurationDone();
+void setImmutableConfigurationDone();
+}
#ifdef HAVE_LIBEDIT
#if defined(__OpenBSD__) || defined(__NetBSD__)
-// If this is not undeffed, __attribute__ wil be redefined by /usr/include/readline/rlstdc.h
+// If this is not undeffed, __attribute__ will be redefined by /usr/include/readline/rlstdc.h
#undef __STRICT_ANSI__
#include <readline/readline.h>
#include <readline/history.h>
#include "dnsdist.hh"
#include "dnsdist-console.hh"
#include "dnsdist-crypto.hh"
+#include "dnsdist-lua.hh"
#include "threadname.hh"
-GlobalStateHolder<NetmaskGroup> g_consoleACL;
-vector<pair<struct timeval, string>> g_confDelta;
-std::string g_consoleKey;
-bool g_logConsoleConnections{true};
-bool g_consoleEnabled{false};
-uint32_t g_consoleOutputMsgMaxSize{10000000};
+static LockGuarded<std::vector<pair<timeval, string>>> s_confDelta;
static ConcurrentConnectionManager s_connManager(100);
FDWrapper d_fileDesc;
};
-void setConsoleMaximumConcurrentConnections(size_t max)
-{
- s_connManager.setMaxConcurrentConnections(max);
-}
-
-// MUST BE CALLED UNDER A LOCK - right now the LuaLock
static void feedConfigDelta(const std::string& line)
{
if (line.empty()) {
}
timeval now{};
gettimeofday(&now, nullptr);
- g_confDelta.emplace_back(now, line);
+ s_confDelta.lock()->emplace_back(now, line);
+}
+
+namespace dnsdist::console
+{
+const std::vector<std::pair<timeval, std::string>>& getConfigurationDelta()
+{
+ return *(s_confDelta.lock());
+}
}
#ifdef HAVE_LIBEDIT
}
*len = ntohl(raw);
- if (*len > g_consoleOutputMsgMaxSize) {
+ if (*len > dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleOutputMsgMaxSize) {
return ConsoleCommandResult::TooLarge;
}
static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string& line, dnsdist::crypto::authenticated::Nonce& readingNonce, dnsdist::crypto::authenticated::Nonce& writingNonce, const bool outputEmptyLine)
{
- string msg = dnsdist::crypto::authenticated::encryptSym(line, g_consoleKey, writingNonce);
+ const auto& consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
+ string msg = dnsdist::crypto::authenticated::encryptSym(line, consoleKey, writingNonce);
const auto msgLen = msg.length();
if (msgLen > std::numeric_limits<uint32_t>::max()) {
cerr << "Encrypted message is too long to be sent to the server, " << std::to_string(msgLen) << " > " << std::numeric_limits<uint32_t>::max() << endl;
return commandResult;
}
if (commandResult == ConsoleCommandResult::TooLarge) {
- cerr << "Received a console message whose length (" << len << ") is exceeding the allowed one (" << g_consoleOutputMsgMaxSize << "), closing that connection" << endl;
+ cerr << "Received a console message whose length (" << len << ") is exceeding the allowed one (" << dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleOutputMsgMaxSize << "), closing that connection" << endl;
return commandResult;
}
msg.clear();
msg.resize(len);
readn2(fileDesc, msg.data(), len);
- msg = dnsdist::crypto::authenticated::decryptSym(msg, g_consoleKey, readingNonce);
+ msg = dnsdist::crypto::authenticated::decryptSym(msg, consoleKey, readingNonce);
cout << msg;
cout.flush();
return ConsoleCommandResult::Valid;
}
-void doClient(ComboAddress server, const std::string& command)
+namespace dnsdist::console
+{
+void doClient(const std::string& command)
{
- if (!dnsdist::crypto::authenticated::isValidKey(g_consoleKey)) {
+ //coverity[auto_causes_copy]
+ const auto consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
+ //coverity[auto_causes_copy]
+ const auto server = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleServerAddress;
+ if (!dnsdist::crypto::authenticated::isValidKey(consoleKey)) {
cerr << "The currently configured console key is not valid, please configure a valid key using the setKey() directive" << endl;
return;
}
- if (g_verbose) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
cout << "Connecting to " << server.toStringWithPort() << endl;
}
}
}
}
+}
#ifndef DISABLE_COMPLETION
/**** CARGO CULT CODE AHEAD ****/
-const std::vector<ConsoleKeyword> g_consoleKeywords
+static const std::vector<dnsdist::console::ConsoleKeyword> s_consoleKeywords
{
/* keyword, function, parameters, description */
{"addACL", true, "netmask", "add to the ACL set who can use this server"},
{"topResponseRules", true, "[top][, vars]", "show `top` response rules"},
{"topRules", true, "[top][, vars]", "show `top` rules"},
{"topSelfAnsweredResponseRules", true, "[top][, vars]", "show `top` self-answered response rules"},
- {"topSlow", true, "[top][, limit][, labels]", "show `top` queries slower than `limit` milliseconds, grouped by last `labels` labels"},
+ {"topSlow", true, "[top][, limit][, labels]", "show `top` queries slower than `limit` milliseconds (timeouts excepted), grouped by last `labels` labels"},
+ {"topTimeouts", true, "[top][, labels]", "show `top` queries that timed out, grouped by last `labels` labels"},
{"TrailingDataRule", true, "", "Matches if the query has trailing data"},
{"truncateTC", true, "bool", "if set (defaults to no starting with dnsdist 1.2.0) truncate TC=1 answers so they are actually empty. Fixes an issue for PowerDNS Authoritative Server 2.9.22. Note: turning this on breaks compatibility with RFC 6891."},
{"unregisterDynBPFFilter", true, "DynBPFFilter", "unregister this dynamic BPF filter"},
#if defined(HAVE_LIBEDIT)
extern "C"
{
- static char* my_generator(const char* text, int state)
+ static char* dnsdist_completion_generator(const char* text, int state)
{
string textStr(text);
/* to keep it readable, we try to keep only 4 keywords per line
s_counter = 0;
}
- for (const auto& keyword : g_consoleKeywords) {
+ for (const auto& keyword : s_consoleKeywords) {
if (boost::starts_with(keyword.name, textStr) && counter++ == s_counter) {
std::string value(keyword.name);
s_counter++;
return nullptr;
}
- char** my_completion(const char* text, int start, int end)
+ static char** dnsdist_completion_callback(const char* text, int start, int end)
{
char** matches = nullptr;
if (start == 0) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): readline
- matches = rl_completion_matches(const_cast<char*>(text), &my_generator);
+ matches = rl_completion_matches(const_cast<char*>(text), &dnsdist_completion_generator);
}
// skip default filename completion.
#endif /* HAVE_LIBEDIT */
#endif /* DISABLE_COMPLETION */
+namespace dnsdist::console
+{
+#ifndef DISABLE_COMPLETION
+const std::vector<ConsoleKeyword>& getConsoleKeywords()
+{
+ return s_consoleKeywords;
+}
+#endif /* DISABLE_COMPLETION */
+
+void setupCompletion()
+{
+#ifndef DISABLE_COMPLETION
+#ifdef HAVE_LIBEDIT
+ rl_attempted_completion_function = dnsdist_completion_callback;
+ rl_completion_append_character = 0;
+#endif /* DISABLE_COMPLETION */
+#endif /* HAVE_LIBEDIT */
+}
+
+void clearHistory()
+{
+#ifdef HAVE_LIBEDIT
+ clear_history();
+#endif /* HAVE_LIBEDIT */
+ s_confDelta.lock()->clear();
+}
+
static void controlClientThread(ConsoleConnection&& conn)
{
try {
setTCPNoDelay(conn.getFD());
+ //coverity[auto_causes_copy]
+ const auto consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
dnsdist::crypto::authenticated::Nonce theirs;
dnsdist::crypto::authenticated::Nonce ours;
dnsdist::crypto::authenticated::Nonce readingNonce;
}
std::string line;
+ //coverity[tainted_data]
line.resize(len);
readn2(conn.getFD(), line.data(), len);
- line = dnsdist::crypto::authenticated::decryptSym(line, g_consoleKey, readingNonce);
+ line = dnsdist::crypto::authenticated::decryptSym(line, consoleKey, readingNonce);
string response;
try {
catch (const LuaContext::SyntaxErrorException& e) {
response = "Error: " + string(e.what()) + ": ";
}
- response = dnsdist::crypto::authenticated::encryptSym(response, g_consoleKey, writingNonce);
+ response = dnsdist::crypto::authenticated::encryptSym(response, consoleKey, writingNonce);
putMsgLen32(conn.getFD(), response.length());
writen2(conn.getFD(), response.c_str(), response.length());
}
- if (g_logConsoleConnections) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_logConsoleConnections) {
infolog("Closed control connection from %s", conn.getClient().toStringWithPort());
}
}
}
}
-// NOLINTNEXTLINE(performance-unnecessary-value-param): this is thread
-void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local)
+void controlThread(Socket&& acceptFD)
{
try {
setThreadName("dnsdist/control");
+ const ComboAddress local = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleServerAddress;
+ s_connManager.setMaxConcurrentConnections(dnsdist::configuration::getImmutableConfiguration().d_consoleMaxConcurrentConnections);
+
ComboAddress client;
// make sure that the family matches the one from the listening IP,
// so that getSocklen() returns the correct size later, otherwise
client.sin4.sin_family = local.sin4.sin_family;
int sock{-1};
- auto localACL = g_consoleACL.getLocal();
infolog("Accepting control connections on %s", local.toStringWithPort());
- while ((sock = SAccept(acceptFD->getHandle(), client)) >= 0) {
-
+ while ((sock = SAccept(acceptFD.getHandle(), client)) >= 0) {
+ const auto& consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
FDWrapper socket(sock);
- if (!dnsdist::crypto::authenticated::isValidKey(g_consoleKey)) {
+ if (!dnsdist::crypto::authenticated::isValidKey(consoleKey)) {
vinfolog("Control connection from %s dropped because we don't have a valid key configured, please configure one using setKey()", client.toStringWithPort());
continue;
}
- if (!localACL->match(client)) {
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (!runtimeConfig.d_consoleACL.match(client)) {
vinfolog("Control connection from %s dropped because of ACL", client.toStringWithPort());
continue;
}
try {
ConsoleConnection conn(client, std::move(socket));
- if (g_logConsoleConnections) {
+ if (runtimeConfig.d_logConsoleConnections) {
warnlog("Got control connection from %s", client.toStringWithPort());
}
errlog("Control thread died: %s", e.what());
}
}
-
-void clearConsoleHistory()
-{
-#ifdef HAVE_LIBEDIT
- clear_history();
-#endif /* HAVE_LIBEDIT */
- g_confDelta.clear();
}
*/
#pragma once
+#include <vector>
+#include <string>
+
#include "config.h"
#include "sstuff.hh"
+namespace dnsdist::console
+{
+const std::vector<std::pair<timeval, std::string>>& getConfigurationDelta();
+void doClient(const std::string& command);
+void doConsole();
+void controlThread(Socket&& acceptFD);
+void clearHistory();
+
#ifndef DISABLE_COMPLETION
struct ConsoleKeyword
{
return res;
}
};
-extern const std::vector<ConsoleKeyword> g_consoleKeywords;
-extern "C"
-{
- char** my_completion(const char* text, int start, int end);
-}
+const std::vector<ConsoleKeyword>& getConsoleKeywords();
#endif /* DISABLE_COMPLETION */
-
-extern GlobalStateHolder<NetmaskGroup> g_consoleACL;
-extern std::string g_consoleKey; // in theory needs locking
-extern bool g_logConsoleConnections;
-extern bool g_consoleEnabled;
-extern uint32_t g_consoleOutputMsgMaxSize;
-
-void doClient(ComboAddress server, const std::string& command);
-void doConsole();
-void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local);
-void clearConsoleHistory();
-
-void setConsoleMaximumConcurrentConnections(size_t max);
+void setupCompletion();
+}
#include "config.h"
#include "dnsdist-discovery.hh"
+#include "dnsdist-backend.hh"
#include "dnsdist.hh"
#include "dnsdist-random.hh"
#include "dnsparser.hh"
bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeableBackend, ServiceDiscovery::DiscoveredResolverConfig& config)
{
+ const auto verbose = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
const auto& backend = upgradeableBackend.d_ds;
const auto& addr = backend->d_config.remote;
try {
uint16_t responseSize = 0;
auto got = readn2WithTimeout(sock.getHandle(), &responseSize, sizeof(responseSize), remainingTime);
if (got != sizeof(responseSize)) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Error while waiting for the ADD upgrade response size from backend %s: %d", addr.toStringWithPort(), got);
}
return false;
got = readn2WithTimeout(sock.getHandle(), packet.data(), packet.size(), remainingTime);
if (got != packet.size()) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Error while waiting for the ADD upgrade response from backend %s: %d", addr.toStringWithPort(), got);
}
return false;
}
if (packet.size() <= sizeof(struct dnsheader)) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Too short answer of size %d received from the backend %s", packet.size(), addr.toStringWithPort());
}
return false;
struct dnsheader d;
memcpy(&d, packet.data(), sizeof(d));
if (d.id != id) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Invalid ID (%d / %d) received from the backend %s", d.id, id, addr.toStringWithPort());
}
return false;
}
if (d.rcode != RCode::NoError) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Response code '%s' received from the backend %s for '%s'", RCode::to_s(d.rcode), addr.toStringWithPort(), s_discoveryDomain);
}
}
if (ntohs(d.qdcount) != 1) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Invalid answer (qdcount %d) received from the backend %s", ntohs(d.qdcount), addr.toStringWithPort());
}
return false;
DNSName receivedName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &receivedType, &receivedClass);
if (receivedName != s_discoveryDomain || receivedType != s_discoveryType || receivedClass != QClass::IN) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Invalid answer, either the qname (%s / %s), qtype (%s / %s) or qclass (%s / %s) does not match, received from the backend %s", receivedName, s_discoveryDomain, QType(receivedType).toString(), s_discoveryType.toString(), QClass(receivedClass).toString(), QClass::IN.toString(), addr.toStringWithPort());
}
return false;
infolog("Added automatically upgraded server %s", newServer->getNameWithAddr());
- auto localPools = g_pools.getCopy();
if (!newServer->d_config.pools.empty()) {
for (const auto& poolName : newServer->d_config.pools) {
- addServerToPool(localPools, poolName, newServer);
+ addServerToPool(poolName, newServer);
}
}
else {
- addServerToPool(localPools, "", newServer);
+ addServerToPool("", newServer);
}
newServer->start();
- auto states = g_dstates.getCopy();
- states.push_back(newServer);
/* remove the existing backend if needed */
if (!backend.keepAfterUpgrade) {
- for (auto it = states.begin(); it != states.end(); ++it) {
- if (*it == backend.d_ds) {
- states.erase(it);
- break;
+ dnsdist::configuration::updateRuntimeConfiguration([&backend](dnsdist::configuration::RuntimeConfiguration& runtimeConfig) {
+ auto& backends = runtimeConfig.d_backends;
+ for (auto backendIt = backends.begin(); backendIt != backends.end(); ++backendIt) {
+ if (*backendIt == backend.d_ds) {
+ backends.erase(backendIt);
+ break;
+ }
}
- }
+ });
for (const string& poolName : backend.d_ds->d_config.pools) {
- removeServerFromPool(localPools, poolName, backend.d_ds);
+ removeServerFromPool(poolName, backend.d_ds);
}
/* the server might also be in the default pool */
- removeServerFromPool(localPools, "", backend.d_ds);
+ removeServerFromPool("", backend.d_ds);
}
- std::stable_sort(states.begin(), states.end(), [](const decltype(newServer)& a, const decltype(newServer)& b) {
- return a->d_config.order < b->d_config.order;
- });
+ dnsdist::backend::registerNewBackend(newServer);
- g_pools.setState(localPools);
- g_dstates.setState(states);
if (!backend.keepAfterUpgrade) {
backend.d_ds->stop();
}
return true;
}
}
+
+void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config)
+{
+ if (config.setAA) {
+ dnsheader.aa = *config.setAA;
+ }
+ if (config.setAD) {
+ dnsheader.ad = *config.setAD;
+ }
+ else {
+ dnsheader.ad = false;
+ }
+ if (config.setRA) {
+ dnsheader.ra = *config.setRA;
+ }
+ else {
+ dnsheader.ra = dnsheader.rd; // for good measure
+ }
+}
}
bool editDNSHeaderFromPacket(PacketBuffer& packet, const std::function<bool(dnsheader& header)>& editFunction);
bool editDNSHeaderFromRawPacket(void* packet, const std::function<bool(dnsheader& header)>& editFunction);
}
+
+struct ResponseConfig
+{
+ boost::optional<bool> setAA{boost::none};
+ boost::optional<bool> setAD{boost::none};
+ boost::optional<bool> setRA{boost::none};
+ uint32_t ttl{60};
+};
+void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config);
}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dnsdist.hh"
+#include "dnsdist-configuration.hh"
+#include "dnsdist-dnsparser.hh"
+
+std::string DNSQuestion::getTrailingData() const
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const auto* message = reinterpret_cast<const char*>(this->getData().data());
+ const uint16_t messageLen = getDNSPacketLength(message, this->getData().size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ return {message + messageLen, this->getData().size() - messageLen};
+}
+
+bool DNSQuestion::setTrailingData(const std::string& tail)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const char* message = reinterpret_cast<const char*>(this->data.data());
+ const uint16_t messageLen = getDNSPacketLength(message, this->data.size());
+ this->data.resize(messageLen);
+ if (!tail.empty()) {
+ if (!hasRoomFor(tail.size())) {
+ return false;
+ }
+ this->data.insert(this->data.end(), tail.begin(), tail.end());
+ }
+ return true;
+}
+
+bool DNSQuestion::editHeader(const std::function<bool(dnsheader&)>& editFunction)
+{
+ if (data.size() < sizeof(dnsheader)) {
+ throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
+ }
+ return dnsdist::PacketMangling::editDNSHeaderFromPacket(data, editFunction);
+}
+
+DNSQuestion::DNSQuestion(InternalQueryState& ids_, PacketBuffer& data_) :
+ data(data_), ids(ids_), ecsPrefixLength(ids.origRemote.sin4.sin_family == AF_INET ? dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV4 : dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV6), ecsOverride(dnsdist::configuration::getCurrentRuntimeConfiguration().d_ecsOverride)
+{
+}
-
#include "dnsdist.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-metrics.hh"
-
-GlobalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> g_dynblockNMG;
-GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
-DNSAction::Action g_dynBlockAction = DNSAction::Action::Drop;
+#include "sholder.hh"
#ifndef DISABLE_DYNBLOCKS
+static GlobalStateHolder<ClientAddressDynamicRules> s_dynblockNMG;
+static GlobalStateHolder<SuffixDynamicRules> s_dynblockSMT;
+
void DynBlockRulesGroup::apply(const timespec& now)
{
counts_t counts;
return;
}
- boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>> blocks;
+ boost::optional<ClientAddressDynamicRules> blocks;
bool updated = false;
for (const auto& entry : counts) {
}
if (updated && blocks) {
- g_dynblockNMG.setState(std::move(*blocks));
+ s_dynblockNMG.setState(std::move(*blocks));
}
applySMT(now, statNodeRoot);
if (!namesToBlock.empty()) {
updated = false;
- SuffixMatchTree<DynBlock> smtBlocks = g_dynblockSMT.getCopy();
+ auto smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
for (auto& [name, parameters] : namesToBlock) {
if (parameters.d_reason || parameters.d_action) {
DynBlockRule rule(d_suffixMatchRule);
}
}
if (updated) {
- g_dynblockSMT.setState(std::move(smtBlocks));
+ s_dynblockSMT.setState(std::move(smtBlocks));
}
}
}
/* return the actual action that will be taken by that block:
- either the one set on that block, if any
- - or the one set with setDynBlocksAction in g_dynBlockAction
+ - or the one set with setDynBlocksAction
*/
static DNSAction::Action getActualAction(const DynBlock& block)
{
if (block.action != DNSAction::Action::None) {
return block.action;
}
- return g_dynBlockAction;
+ return dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
}
namespace dnsdist::DynamicBlocks
{
-bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet)
+bool addOrRefreshBlock(ClientAddressDynamicRules& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet)
{
unsigned int count = 0;
bool expired = false;
return true;
}
-bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet)
+bool addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet)
{
unsigned int count = 0;
/* be careful, if you try to insert a longer suffix
if (!beQuiet && (got == nullptr || expired)) {
warnlog("Inserting dynamic block for %s for %d seconds: %s", dblock.domain, dblock.until.tv_sec - now.tv_sec, dblock.reason);
}
- blocks.add(dblock.domain, std::move(dblock));
+ auto domain = dblock.domain;
+ blocks.add(domain, std::move(dblock));
return true;
}
}
-void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning)
+void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<ClientAddressDynamicRules>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning)
{
/* network exclusions are address-based only (no port) */
if (d_excludedSubnets.match(requestor.getNetwork())) {
dblock.tagSettings = rule.d_tagSettings;
}
if (!blocks) {
- blocks = g_dynblockNMG.getCopy();
+ blocks = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
}
updated = dnsdist::DynamicBlocks::addOrRefreshBlock(*blocks, now, requestor, std::move(dblock), d_beQuiet);
}
}
-void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated)
+void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated)
{
if (d_excludedDomains.check(name)) {
/* do not add a block for excluded domains */
// since the block happens in kernel space.
uint64_t bpfBlocked = 0;
{
- auto blocks = g_dynblockNMG.getLocal();
+ auto blocks = s_dynblockNMG.getLocal();
std::vector<AddressAndPortRange> toRemove;
for (const auto& entry : *blocks) {
if (!(now < entry.second.until)) {
}
}
if (!toRemove.empty()) {
- auto updated = g_dynblockNMG.getCopy();
+ auto updated = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
for (const auto& entry : toRemove) {
updated.erase(entry);
}
- g_dynblockNMG.setState(std::move(updated));
+ s_dynblockNMG.setState(std::move(updated));
dnsdist::metrics::g_stats.dynBlocked += bpfBlocked;
}
}
{
std::vector<DNSName> toRemove;
- auto blocks = g_dynblockSMT.getLocal();
- blocks->visit([&toRemove, now](const SuffixMatchTree<DynBlock>& node) {
+ auto blocks = s_dynblockSMT.getLocal();
+ blocks->visit([&toRemove, now](const SuffixDynamicRules& node) {
if (!(now < node.d_value.until)) {
toRemove.push_back(node.d_value.domain);
}
});
if (!toRemove.empty()) {
- auto updated = g_dynblockSMT.getCopy();
+ auto updated = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
for (const auto& entry : toRemove) {
updated.remove(entry);
}
- g_dynblockSMT.setState(std::move(updated));
+ s_dynblockSMT.setState(std::move(updated));
}
}
}
return results;
}
- auto blocks = g_dynblockNMG.getLocal();
+ auto blocks = s_dynblockNMG.getLocal();
for (const auto& entry : *blocks) {
auto& topsForReason = results[entry.second.reason];
uint64_t value = entry.second.blocks.load();
return results;
}
- auto blocks = g_dynblockSMT.getLocal();
- blocks->visit([&results, topN](const SuffixMatchTree<DynBlock>& node) {
+ auto blocks = s_dynblockSMT.getLocal();
+ blocks->visit([&results, topN](const SuffixDynamicRules& node) {
auto& topsForReason = results[node.d_value.reason];
if (topsForReason.size() < topN || topsForReason.front().second < node.d_value.blocks) {
auto newEntry = std::pair(node.d_value.domain, node.d_value.blocks.load());
std::list<DynBlockMaintenance::MetricsSnapshot> DynBlockMaintenance::s_metricsData;
LockGuarded<DynBlockMaintenance::Tops> DynBlockMaintenance::s_tops;
-size_t DynBlockMaintenance::s_topN{20};
-time_t DynBlockMaintenance::s_expiredDynBlocksPurgeInterval{60};
void DynBlockMaintenance::collectMetrics()
{
static const time_t metricsGenerationInterval = 60;
time_t now = time(nullptr);
- time_t nextExpiredPurge = now + s_expiredDynBlocksPurgeInterval;
- time_t nextMetricsCollect = now + metricsCollectionInterval;
+ auto purgeInterval = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlocksPurgeInterval;
+ time_t nextExpiredPurge = now + static_cast<time_t>(purgeInterval);
+ time_t nextMetricsCollect = now + static_cast<time_t>(metricsCollectionInterval);
time_t nextMetricsGeneration = now + metricsGenerationInterval;
while (true) {
time_t sleepDelay = std::numeric_limits<time_t>::max();
- if (s_expiredDynBlocksPurgeInterval > 0) {
+ if (purgeInterval > 0) {
sleepDelay = std::min(sleepDelay, (nextExpiredPurge - now));
}
sleepDelay = std::min(sleepDelay, (nextMetricsCollect - now));
nextMetricsGeneration = now + metricsGenerationInterval;
}
- if (s_expiredDynBlocksPurgeInterval > 0 && now >= nextExpiredPurge) {
- struct timespec tspec
- {
- };
+ purgeInterval = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlocksPurgeInterval;
+ if (purgeInterval > 0 && now >= nextExpiredPurge) {
+ timespec tspec{};
gettime(&tspec);
purgeExpired(tspec);
now = time(nullptr);
- nextExpiredPurge = now + s_expiredDynBlocksPurgeInterval;
+ nextExpiredPurge = now + static_cast<time_t>(purgeInterval);
}
}
catch (const std::exception& e) {
warnlog("Error in the dynamic block maintenance thread: %s", e.what());
}
catch (...) {
+ vinfolog("Unhandled error in the dynamic block maintenance thread");
}
}
}
return result.str();
}
+namespace dnsdist::DynamicBlocks
+{
+const ClientAddressDynamicRules& getClientAddressDynamicRules()
+{
+ static thread_local auto t_localRules = s_dynblockNMG.getLocal();
+ return *t_localRules;
+}
+
+ClientAddressDynamicRules getClientAddressDynamicRulesCopy()
+{
+ return s_dynblockNMG.getCopy();
+}
+
+const SuffixDynamicRules& getSuffixDynamicRules()
+{
+ static thread_local auto t_localRules = s_dynblockSMT.getLocal();
+ return *t_localRules;
+}
+
+SuffixDynamicRules getSuffixDynamicRulesCopy()
+{
+ return s_dynblockSMT.getCopy();
+}
+
+void setClientAddressDynamicRules(ClientAddressDynamicRules&& rules)
+{
+ s_dynblockNMG.setState(std::move(rules));
+}
+
+void setSuffixDynamicRules(SuffixDynamicRules&& rules)
+{
+ s_dynblockSMT.setState(std::move(rules));
+}
+
+void clearClientAddressDynamicRules()
+{
+ ClientAddressDynamicRules emptyNMG;
+ setClientAddressDynamicRules(std::move(emptyNMG));
+}
+
+void clearSuffixDynamicRules()
+{
+ SuffixDynamicRules emptySMT;
+ setSuffixDynamicRules(std::move(emptySMT));
+}
+
+}
+
#endif /* DISABLE_DYNBLOCKS */
#include "dnsdist-lua-inspection-ffi.h"
}
+#include "ext/luawrapper/include/LuaContext.hpp"
+
// dnsdist_ffi_stat_node_t is a lightuserdata
template <>
struct LuaContext::Pusher<dnsdist_ffi_stat_node_t*>
SMTBlockParameters& d_blockParameters;
};
+struct DynBlock
+{
+ DynBlock()
+ {
+ until.tv_sec = 0;
+ until.tv_nsec = 0;
+ }
+
+ DynBlock(const std::string& reason_, const struct timespec& until_, const DNSName& domain_, DNSAction::Action action_) :
+ reason(reason_), domain(domain_), until(until_), action(action_)
+ {
+ }
+
+ DynBlock(const DynBlock& rhs) :
+ reason(rhs.reason), domain(rhs.domain), until(rhs.until), tagSettings(rhs.tagSettings), action(rhs.action), warning(rhs.warning), bpf(rhs.bpf)
+ {
+ blocks.store(rhs.blocks);
+ }
+
+ DynBlock(DynBlock&& rhs) :
+ reason(std::move(rhs.reason)), domain(std::move(rhs.domain)), until(rhs.until), tagSettings(std::move(rhs.tagSettings)), action(rhs.action), warning(rhs.warning), bpf(rhs.bpf)
+ {
+ blocks.store(rhs.blocks);
+ }
+
+ DynBlock& operator=(const DynBlock& rhs)
+ {
+ reason = rhs.reason;
+ until = rhs.until;
+ domain = rhs.domain;
+ action = rhs.action;
+ blocks.store(rhs.blocks);
+ warning = rhs.warning;
+ bpf = rhs.bpf;
+ tagSettings = rhs.tagSettings;
+ return *this;
+ }
+
+ DynBlock& operator=(DynBlock&& rhs)
+ {
+ reason = std::move(rhs.reason);
+ until = rhs.until;
+ domain = std::move(rhs.domain);
+ action = rhs.action;
+ blocks.store(rhs.blocks);
+ warning = rhs.warning;
+ bpf = rhs.bpf;
+ tagSettings = std::move(rhs.tagSettings);
+ return *this;
+ }
+
+ struct TagSettings
+ {
+ std::string d_name;
+ std::string d_value;
+ };
+
+ string reason;
+ DNSName domain;
+ timespec until{};
+ std::shared_ptr<TagSettings> tagSettings{nullptr};
+ mutable std::atomic<uint32_t> blocks{0};
+ DNSAction::Action action{DNSAction::Action::None};
+ bool warning{false};
+ bool bpf{false};
+};
+
using dnsdist_ffi_dynamic_block_inserted_hook = std::function<void(uint8_t type, const char* key, const char* reason, uint8_t action, uint64_t duration, bool warning)>;
+using ClientAddressDynamicRules = NetmaskTree<DynBlock, AddressAndPortRange>;
+using SuffixDynamicRules = SuffixMatchTree<DynBlock>;
class DynBlockRulesGroup
{
void applySMT(const struct timespec& now, StatNode& statNodeRoot);
bool checkIfQueryTypeMatches(const Rings::Query& query);
bool checkIfResponseCodeMatches(const Rings::Response& response);
- void addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning);
- void addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated);
+ void addOrRefreshBlock(boost::optional<ClientAddressDynamicRules>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning);
+ void addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated);
- void addBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
+ void addBlock(boost::optional<ClientAddressDynamicRules>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
{
addOrRefreshBlock(blocks, now, requestor, rule, updated, false);
}
- void handleWarning(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
+ void handleWarning(boost::optional<ClientAddressDynamicRules>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
{
addOrRefreshBlock(blocks, now, requestor, rule, updated, true);
}
static std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> getTopSuffixes(size_t topN);
static void purgeExpired(const struct timespec& now);
- static time_t s_expiredDynBlocksPurgeInterval;
-
private:
static void collectMetrics();
static void generateMetrics();
/* s_metricsData should only be accessed by the dynamic blocks maintenance thread so it does not need a lock */
// need N+1 datapoints to be able to do the diff after a collection point has been reached
static std::list<MetricsSnapshot> s_metricsData;
- static size_t s_topN;
+ static constexpr size_t s_topN{20};
};
namespace dnsdist::DynamicBlocks
{
-bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet);
-bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet);
+bool addOrRefreshBlock(ClientAddressDynamicRules& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet);
+bool addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet);
+
+const ClientAddressDynamicRules& getClientAddressDynamicRules();
+const SuffixDynamicRules& getSuffixDynamicRules();
+ClientAddressDynamicRules getClientAddressDynamicRulesCopy();
+SuffixDynamicRules getSuffixDynamicRulesCopy();
+void setClientAddressDynamicRules(ClientAddressDynamicRules&& rules);
+void setSuffixDynamicRules(SuffixDynamicRules&& rules);
+void clearClientAddressDynamicRules();
+void clearSuffixDynamicRules();
}
#endif /* DISABLE_DYNBLOCKS */
*/
#include "dnsdist-dynbpf.hh"
+std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
+
bool DynBPFFilter::block(const ComboAddress& addr, const struct timespec& until)
{
bool inserted = false;
};
LockGuarded<Data> d_data;
};
+
+extern std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
#include "ednsoptions.hh"
#include "ednssubnet.hh"
-/* when we add EDNS to a query, we don't want to advertise
- a large buffer size */
-size_t g_EdnsUDPPayloadSize = 512;
-static const uint16_t defaultPayloadSizeSelfGenAnswers = 1232;
-static_assert(defaultPayloadSizeSelfGenAnswers < s_udpIncomingBufferSize, "The UDP responder's payload size should be smaller or equal to our incoming buffer size");
-uint16_t g_PayloadSizeSelfGenAnswers{defaultPayloadSizeSelfGenAnswers};
-
-/* draft-ietf-dnsop-edns-client-subnet-04 "11.1. Privacy" */
-uint16_t g_ECSSourcePrefixV4 = 24;
-uint16_t g_ECSSourcePrefixV6 = 56;
-
-bool g_ECSOverride{false};
-bool g_addEDNSToSelfGeneratedResponses{true};
-
int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent)
{
if (initialPacket.size() < sizeof(dnsheader)) {
/* addOrReplaceEDNSOption will set it to false if there is already an existing option */
optionAdded = true;
addOrReplaceEDNSOption(options, optionToReplace, optionAdded, overrideExisting, newOptionContent);
- packetWriter.addOpt(recordHeader.d_class, edns0.extRCode, edns0.extFlags, options, edns0.version);
+ packetWriter.addOpt(recordHeader.d_class, edns0.extRCode, ntohs(edns0.extFlags), options, edns0.version);
}
}
if (ednsAdded) {
- packetWriter.addOpt(g_EdnsUDPPayloadSize, 0, 0, {{optionToReplace, std::string(&newOptionContent.at(EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), newOptionContent.size() - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE))}}, 0);
+ packetWriter.addOpt(dnsdist::configuration::s_EdnsUDPPayloadSize, 0, 0, {{optionToReplace, std::string(&newOptionContent.at(EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), newOptionContent.size() - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE))}}, 0);
optionAdded = true;
}
return ENOENT;
}
+namespace dnsdist
+{
/* extract the start of the OPT RR in a QUERY packet if any */
-int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_t* optRDPosition, size_t* remaining)
+int getEDNSOptionsStart(const PacketBuffer& packet, const size_t qnameWireLength, uint16_t* optRDPosition, size_t* remaining)
{
if (optRDPosition == nullptr || remaining == nullptr) {
throw std::runtime_error("Invalid values passed to getEDNSOptionsStart");
const dnsheader_aligned dnsHeader(packet.data());
- if (offset >= packet.size()) {
+ if (qnameWireLength >= packet.size()) {
return ENOENT;
}
return ENOENT;
}
- size_t pos = sizeof(dnsheader) + offset;
+ size_t pos = sizeof(dnsheader) + qnameWireLength;
pos += DNS_TYPE_SIZE + DNS_CLASS_SIZE;
if (pos >= packet.size()) {
return 0;
}
+}
void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength)
{
size_t remaining = 0;
uint16_t optRDPosition{};
- int res = getEDNSOptionsStart(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
+ int res = dnsdist::getEDNSOptionsStart(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
if (res == 0) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
static bool addEDNSWithECS(PacketBuffer& packet, size_t maximumSize, const string& newECSOption, bool& ednsAdded, bool& ecsAdded)
{
- if (!generateOptRR(newECSOption, packet, maximumSize, g_EdnsUDPPayloadSize, 0, false)) {
+ if (!generateOptRR(newECSOption, packet, maximumSize, dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
return false;
}
uint16_t optRDPosition = 0;
size_t remaining = 0;
- int res = getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
+ int res = dnsdist::getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
if (res != 0) {
/* no EDNS but there might be another record in additional (TSIG?) */
bool hadEDNS = false;
bool dnssecOK = false;
- if (g_addEDNSToSelfGeneratedResponses) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses) {
uint16_t payloadSize = 0;
uint16_t zValue = 0;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
if (hadEDNS) {
/* now we need to add a new OPT record */
- return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
+ return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
}
return true;
size_t remaining = 0;
auto& packet = dnsQuestion.getMutableData();
- int res = getEDNSOptionsStart(packet, dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
+ int res = dnsdist::getEDNSOptionsStart(packet, dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
if (res != 0) {
/* if the initial query did not have EDNS0, we are done */
return true;
});
- if (g_addEDNSToSelfGeneratedResponses) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses) {
/* now we need to add a new OPT record */
- return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
+ return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
}
/* otherwise we are just fine */
return true;
}
+namespace dnsdist
+{
+static std::optional<size_t> getEDNSRecordPosition(const DNSQuestion& dnsQuestion)
+{
+ try {
+ const auto& packet = dnsQuestion.getData();
+ if (packet.size() <= sizeof(dnsheader)) {
+ return std::nullopt;
+ }
+
+ uint16_t optRDPosition = 0;
+ size_t remaining = 0;
+ auto res = getEDNSOptionsStart(packet, dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
+ if (res != 0) {
+ return std::nullopt;
+ }
+
+ if (optRDPosition < DNS_TTL_SIZE) {
+ return std::nullopt;
+ }
+
+ return optRDPosition - DNS_TTL_SIZE;
+ }
+ catch (...) {
+ return std::nullopt;
+ }
+}
+
// goal in life - if you send us a reasonably normal packet, we'll get Z for you, otherwise 0
int getEDNSZ(const DNSQuestion& dnsQuestion)
{
try {
- const auto& dnsHeader = dnsQuestion.getHeader();
- if (ntohs(dnsHeader->qdcount) != 1 || dnsHeader->ancount != 0 || ntohs(dnsHeader->arcount) != 1 || dnsHeader->nscount != 0) {
+ auto position = getEDNSRecordPosition(dnsQuestion);
+
+ if (!position) {
return 0;
}
- if (dnsQuestion.getData().size() <= sizeof(dnsheader)) {
+ const auto& packet = dnsQuestion.getData();
+ if ((*position + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1) >= packet.size()) {
return 0;
}
- size_t pos = sizeof(dnsheader) + dnsQuestion.ids.qname.wirelength() + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
+ return 0x100 * packet.at(*position + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE) + packet.at(*position + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1);
+ }
+ catch (...) {
+ return 0;
+ }
+}
- if (dnsQuestion.getData().size() <= (pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) {
- return 0;
+std::optional<uint8_t> getEDNSVersion(const DNSQuestion& dnsQuestion)
+{
+ try {
+ auto position = getEDNSRecordPosition(dnsQuestion);
+
+ if (!position) {
+ return std::nullopt;
}
const auto& packet = dnsQuestion.getData();
- if (packet.at(pos) != 0) {
- /* not root, so not a valid OPT record */
- return 0;
+ if ((*position + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE) >= packet.size()) {
+ return std::nullopt;
}
- pos++;
+ return packet.at(*position + EDNS_EXTENDED_RCODE_SIZE);
+ }
+ catch (...) {
+ return std::nullopt;
+ }
+}
- uint16_t qtype = packet.at(pos) * 256 + packet.at(pos + 1);
- pos += DNS_TYPE_SIZE;
- pos += DNS_CLASS_SIZE;
+std::optional<uint8_t> getEDNSExtendedRCode(const DNSQuestion& dnsQuestion)
+{
+ try {
+ auto position = getEDNSRecordPosition(dnsQuestion);
- if (qtype != QType::OPT || (pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1) >= packet.size()) {
- return 0;
+ if (!position) {
+ return std::nullopt;
}
- return 0x100 * packet.at(pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE) + packet.at(pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1);
+ const auto& packet = dnsQuestion.getData();
+ if ((*position + EDNS_EXTENDED_RCODE_SIZE) >= packet.size()) {
+ return std::nullopt;
+ }
+
+ return packet.at(*position);
}
catch (...) {
- return 0;
+ return std::nullopt;
}
}
+}
+
bool queryHasEDNS(const DNSQuestion& dnsQuestion)
{
uint16_t optRDPosition = 0;
size_t ecsRemaining = 0;
- int res = getEDNSOptionsStart(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), &optRDPosition, &ecsRemaining);
+ int res = dnsdist::getEDNSOptionsStart(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), &optRDPosition, &ecsRemaining);
return res == 0;
}
}
auto& data = dnsQuestion.getMutableData();
- if (generateOptRR(optRData, data, dnsQuestion.getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
+ if (generateOptRR(optRData, data, dnsQuestion.getMaximumSize(), dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [](dnsheader& header) {
header.arcount = htons(1);
return true;
buffer.resize(sizeof(dnsheader) + qnameLength + sizeof(uint16_t) + sizeof(uint16_t));
if (hadEDNS) {
DNSQuestion dnsQuestion(state, buffer);
- if (!addEDNS(buffer, dnsQuestion.getMaximumSize(), (edns0.extFlags & htons(EDNS_HEADER_FLAG_DO)) != 0, g_PayloadSizeSelfGenAnswers, 0)) {
+ if (!addEDNS(buffer, dnsQuestion.getMaximumSize(), (edns0.extFlags & htons(EDNS_HEADER_FLAG_DO)) != 0, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0)) {
return false;
}
}
// root label (1), type (2), class (2), ttl (4) + rdlen (2)
static const size_t optRecordMinimumSize = 11;
-extern size_t g_EdnsUDPPayloadSize;
-extern uint16_t g_PayloadSizeSelfGenAnswers;
-
int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent);
bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, const string& newOptionContent);
int locateEDNSOptRR(const PacketBuffer& packet, uint16_t* optStart, size_t* optLen, bool* last);
void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength);
int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove);
int rewriteResponseWithoutEDNSOption(const PacketBuffer& initialPacket, const uint16_t optionCodeToSkip, PacketBuffer& newContent);
-int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_t* optRDPosition, size_t* remaining);
bool isEDNSOptionInOpt(const PacketBuffer& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart = nullptr, uint16_t* optContentLen = nullptr);
bool addEDNS(PacketBuffer& packet, size_t maximumSize, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode);
bool addEDNSToQueryTurnedResponse(DNSQuestion& dnsQuestion);
bool parseEDNSOptions(const DNSQuestion& dnsQuestion);
-int getEDNSZ(const DNSQuestion& dnsQuestion);
bool queryHasEDNS(const DNSQuestion& dnsQuestion);
bool getEDNS0Record(const PacketBuffer& packet, EDNS0Record& edns0);
namespace dnsdist
{
bool setInternalQueryRCode(InternalQueryState& state, PacketBuffer& buffer, uint8_t rcode, bool clearAnswers);
+/* this method only works for queries (qdcount == 1, ancount == nscount == 0, arcount == 1) */
+int getEDNSOptionsStart(const PacketBuffer& packet, const size_t qnameWireLength, uint16_t* optRDPosition, size_t* remaining);
+/* this method only works for queries (qdcount == 1, ancount == nscount == 0, arcount == 1) */
+int getEDNSZ(const DNSQuestion& dnsQuestion);
+/* this method only works for queries (qdcount == 1, ancount == nscount == 0, arcount == 1) */
+std::optional<uint8_t> getEDNSVersion(const DNSQuestion& dnsQuestion);
+/* this method only works for queries (qdcount == 1, ancount == nscount == 0, arcount == 1) */
+std::optional<uint8_t> getEDNSExtendedRCode(const DNSQuestion& dnsQuestion);
}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-frontend.hh"
+#include "dnsdist.hh"
+#include "dnsdist-configuration.hh"
+
+namespace dnsdist
+{
+
+const std::vector<std::shared_ptr<ClientState>>& getFrontends()
+{
+ return dnsdist::configuration::getImmutableConfiguration().d_frontends;
+}
+
+std::vector<std::shared_ptr<DNSCryptContext>> getDNSCryptFrontends()
+{
+ std::vector<std::shared_ptr<DNSCryptContext>> results;
+ for (const auto& frontend : getFrontends()) {
+ if (frontend->getProtocol() == dnsdist::Protocol::DNSCryptUDP || frontend->getProtocol() == dnsdist::Protocol::DNSCryptTCP) {
+ results.push_back(frontend->dnscryptCtx);
+ }
+ }
+ return results;
+}
+
+std::vector<std::shared_ptr<TLSFrontend>> getDoTFrontends()
+{
+ std::vector<std::shared_ptr<TLSFrontend>> results;
+ for (const auto& frontend : getFrontends()) {
+ if (frontend->getProtocol() == dnsdist::Protocol::DoT) {
+ results.push_back(frontend->tlsFrontend);
+ }
+ }
+ return results;
+}
+
+std::vector<std::shared_ptr<DOHFrontend>> getDoHFrontends()
+{
+ std::vector<std::shared_ptr<DOHFrontend>> results;
+ for (const auto& frontend : getFrontends()) {
+ if (frontend->getProtocol() == dnsdist::Protocol::DoH) {
+ results.push_back(frontend->dohFrontend);
+ }
+ }
+ return results;
+}
+
+std::vector<std::shared_ptr<DOQFrontend>> getDoQFrontends()
+{
+ std::vector<std::shared_ptr<DOQFrontend>> results;
+ for (const auto& frontend : getFrontends()) {
+ if (frontend->getProtocol() == dnsdist::Protocol::DoQ) {
+ results.push_back(frontend->doqFrontend);
+ }
+ }
+ return results;
+}
+
+std::vector<std::shared_ptr<DOH3Frontend>> getDoH3Frontends()
+{
+ std::vector<std::shared_ptr<DOH3Frontend>> results;
+ for (const auto& frontend : getFrontends()) {
+ if (frontend->getProtocol() == dnsdist::Protocol::DoH3) {
+ results.push_back(frontend->doh3Frontend);
+ }
+ }
+ return results;
+}
+}
*/
#pragma once
-#include "config.h"
-
-#ifdef HAVE_DNS_OVER_HTTPS
-#ifdef HAVE_LIBH2OEVLOOP
-
-#include <ctime>
#include <memory>
-#include <string>
-
-struct CrossProtocolQuery;
-struct DNSQuestion;
-
-std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse);
+#include <vector>
-#include "dnsdist-doh-common.hh"
+struct ClientState;
+class DNSCryptContext;
+class TLSFrontend;
+struct DOHFrontend;
+struct DOQFrontend;
+struct DOH3Frontend;
-struct H2ODOHFrontend : public DOHFrontend
+namespace dnsdist
{
-public:
-
- void setup() override;
- void reloadCertificates() override;
-
- void rotateTicketsKey(time_t now) override;
- void loadTicketsKeys(const std::string& keyFile) override;
- void handleTicketsKeyRotation() override;
- std::string getNextTicketsKeyRotation() const override;
- size_t getTicketsKeysCount() override;
-};
-
-void dohThread(ClientState* clientState);
-
-#endif /* HAVE_LIBH2OEVLOOP */
-#endif /* HAVE_DNS_OVER_HTTPS */
+const std::vector<std::shared_ptr<ClientState>>& getFrontends();
+std::vector<std::shared_ptr<DNSCryptContext>> getDNSCryptFrontends();
+std::vector<std::shared_ptr<TLSFrontend>> getDoTFrontends();
+std::vector<std::shared_ptr<DOHFrontend>> getDoHFrontends();
+std::vector<std::shared_ptr<DOQFrontend>> getDoQFrontends();
+std::vector<std::shared_ptr<DOH3Frontend>> getDoH3Frontends();
+}
#include "tcpiohandler-mplexer.hh"
#include "dnswriter.hh"
#include "dolog.hh"
+#include "dnsdist-lua.hh"
#include "dnsdist-random.hh"
#include "dnsdist-tcp.hh"
#include "dnsdist-nghttp2.hh"
#include "dnsdist-session-cache.hh"
-bool g_verboseHealthChecks{false};
-
struct HealthCheckData
{
enum class TCPState : uint8_t
static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
{
+ const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
const auto& downstream = data->d_ds;
try {
if (data->d_buffer.size() < sizeof(dnsheader)) {
++data->d_ds->d_healthCheckMetrics.d_parseErrors;
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Invalid health check response of size %d from backend %s, expecting at least %d", data->d_buffer.size(), downstream->getNameWithAddr(), sizeof(dnsheader));
}
return false;
dnsheader_aligned responseHeader(data->d_buffer.data());
if (responseHeader.get()->id != data->d_queryID) {
++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Invalid health check response id %d from backend %s, expecting %d", responseHeader.get()->id, downstream->getNameWithAddr(), data->d_queryID);
}
return false;
if (!responseHeader.get()->qr) {
++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Invalid health check response from backend %s, expecting QR to be set", downstream->getNameWithAddr());
}
return false;
if (responseHeader.get()->rcode == RCode::ServFail) {
++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Backend %s responded to health check with ServFail", downstream->getNameWithAddr());
}
return false;
if (downstream->d_config.mustResolve && (responseHeader.get()->rcode == RCode::NXDomain || responseHeader.get()->rcode == RCode::Refused)) {
++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Backend %s responded to health check with %s while mustResolve is set", downstream->getNameWithAddr(), responseHeader.get()->rcode == RCode::NXDomain ? "NXDomain" : "Refused");
}
return false;
if (receivedName != data->d_checkName || receivedType != data->d_checkType || receivedClass != data->d_checkClass) {
++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Backend %s responded to health check with an invalid qname (%s vs %s), qtype (%s vs %s) or qclass (%d vs %d)", downstream->getNameWithAddr(), receivedName.toLogString(), data->d_checkName.toLogString(), QType(receivedType).toString(), QType(data->d_checkType).toString(), receivedClass, data->d_checkClass);
}
return false;
}
catch (const std::exception& e) {
++data->d_ds->d_healthCheckMetrics.d_parseErrors;
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
}
return false;
}
catch (...) {
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
}
return false;
static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& param)
{
auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(param);
+ const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
ssize_t got = 0;
ComboAddress from;
return;
}
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno));
}
++data->d_ds->d_healthCheckMetrics.d_networkErrors;
/* we are using a connected socket but hey.. */
if (from != data->d_ds->d_config.remote) {
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Invalid health check response received from %s, expecting one from %s", from.toStringWithPort(), data->d_ds->d_config.remote.toStringWithPort());
}
++data->d_ds->d_healthCheckMetrics.d_networkErrors;
catch (const std::exception& e) {
++data->d_ds->d_healthCheckMetrics.d_networkErrors;
data->d_ds->submitHealthCheckResult(data->d_initial, false);
- if (g_verboseHealthChecks) {
+ const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+ if (verboseHealthChecks) {
infolog("Error checking the health of backend %s: %s", data->d_ds->getNameWithAddr(), e.what());
}
}
catch (...) {
data->d_ds->submitHealthCheckResult(data->d_initial, false);
- if (g_verboseHealthChecks) {
+ const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+ if (verboseHealthChecks) {
infolog("Unknown exception while checking the health of backend %s", data->d_ds->getNameWithAddr());
}
}
bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initialCheck)
{
+ const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
try {
uint16_t queryID = dnsdist::getRandomDNSID();
DNSName checkName = downstream->d_config.checkName;
#ifdef SO_BINDTODEVICE
if (!downstream->d_config.sourceItfName.empty()) {
int res = setsockopt(sock.getHandle(), SOL_SOCKET, SO_BINDTODEVICE, downstream->d_config.sourceItfName.c_str(), downstream->d_config.sourceItfName.length());
- if (res != 0 && g_verboseHealthChecks) {
+ if (res != 0 && verboseHealthChecks) {
infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", downstream->getNameWithAddr(), stringerror());
}
}
ssize_t sent = udpClientSendRequestToBackend(downstream, data->d_udpSocket.getHandle(), packet, true);
if (sent < 0) {
int ret = errno;
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error while sending a health check query (ID %d) to backend %s: %d", queryID, downstream->getNameWithAddr(), ret);
}
return false;
return true;
}
catch (const std::exception& e) {
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
}
return false;
}
catch (...) {
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
}
return false;
void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
{
+ const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
while (mplexer.getWatchedFDCount(false) > 0 || mplexer.getWatchedFDCount(true) > 0) {
struct timeval now
{
};
int ret = mplexer.run(&now, 100);
if (ret == -1) {
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error while waiting for the health check response from backends: %d", ret);
}
break;
else {
mplexer.removeReadFD(timeout.first);
}
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
}
/* this is not supposed to happen as the file descriptor has to be
there for us to reach that code, and the submission code should not throw,
but let's provide a nice error message if it ever does. */
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
}
}
catch (...) {
/* this is even less likely to happen */
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
}
}
try {
/* UDP does not block while writing, H2 is handled separately */
data->d_ioState.reset();
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
}
catch (const std::exception& e) {
/* this is not supposed to happen as the submission code should not throw,
but let's provide a nice error message if it ever does. */
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
}
}
catch (...) {
/* this is even less likely to happen */
- if (g_verboseHealthChecks) {
+ if (verboseHealthChecks) {
infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
}
}
#include "mplexer.hh"
#include "sstuff.hh"
-extern bool g_verboseHealthChecks;
-
bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initial = false);
void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial = false);
#include "dolog.hh"
#include "dns_random.hh"
-GlobalStateHolder<ServerPolicy> g_policy;
-bool g_roundrobinFailOnNoServer{false};
-
static constexpr size_t s_staticArrayCutOff = 16;
template <typename T> using DynamicIndexArray = std::vector<std::pair<T, size_t>>;
template <typename T> using StaticIndexArray = std::array<std::pair<T, size_t>, s_staticArrayCutOff>;
return leastOutstanding(servers, dq);
}
-double g_weightedBalancingFactor = 0;
-
template <class T> static std::shared_ptr<DownstreamState> getValRandom(const ServerPolicy::NumberedServerVector& servers, T& poss, const unsigned int val, const double targetLoad)
{
constexpr int max = std::numeric_limits<int>::max();
int sum = 0;
size_t usableServers = 0;
+ const auto weightedBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
for (const auto& d : servers) { // w=1, w=10 -> 1, 11
- if (d.second->isUp() && (g_weightedBalancingFactor == 0 || (d.second->outstanding <= (targetLoad * d.second->d_config.d_weight)))) {
+ if (d.second->isUp() && (weightedBalancingFactor == 0 || (static_cast<double>(d.second->outstanding.load()) <= (targetLoad * d.second->d_config.d_weight)))) {
// Don't overflow sum when adding high weights
if (d.second->d_config.d_weight > max - sum) {
sum = max;
{
using ValRandomType = int;
double targetLoad = std::numeric_limits<double>::max();
-
- if (g_weightedBalancingFactor > 0) {
+ const auto weightedBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
+ if (weightedBalancingFactor > 0) {
/* we start with one, representing the query we are currently handling */
double currentLoad = 1;
size_t totalWeight = 0;
}
if (totalWeight > 0) {
- targetLoad = (currentLoad / totalWeight) * g_weightedBalancingFactor;
+ targetLoad = (currentLoad / static_cast<double>(totalWeight)) * weightedBalancingFactor;
}
}
return valrandom(dns_random_uint32(), servers);
}
-uint32_t g_hashperturb;
-double g_consistentHashBalancingFactor = 0;
-
shared_ptr<DownstreamState> whashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t hash)
{
return valrandom(hash, servers);
shared_ptr<DownstreamState> whashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
- return whashedFromHash(servers, dq->ids.qname.hash(g_hashperturb));
+ const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
+ return whashedFromHash(servers, dq->ids.qname.hash(hashPerturbation));
}
shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t qhash)
shared_ptr<DownstreamState> ret = nullptr, first = nullptr;
double targetLoad = std::numeric_limits<double>::max();
- if (g_consistentHashBalancingFactor > 0) {
+ const auto consistentHashBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
+ if (consistentHashBalancingFactor > 0) {
/* we start with one, representing the query we are currently handling */
double currentLoad = 1;
size_t totalWeight = 0;
}
if (totalWeight > 0) {
- targetLoad = (currentLoad / totalWeight) * g_consistentHashBalancingFactor;
+ targetLoad = (currentLoad / static_cast<double>(totalWeight)) * consistentHashBalancingFactor;
}
}
for (const auto& d: servers) {
- if (d.second->isUp() && (g_consistentHashBalancingFactor == 0 || d.second->outstanding <= (targetLoad * d.second->d_config.d_weight))) {
+ if (d.second->isUp() && (consistentHashBalancingFactor == 0 || static_cast<double>(d.second->outstanding.load()) <= (targetLoad * d.second->d_config.d_weight))) {
// make sure hashes have been computed
if (!d.second->hashesComputed) {
d.second->hash();
shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
- return chashedFromHash(servers, dq->ids.qname.hash(g_hashperturb));
+ const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
+ return chashedFromHash(servers, dq->ids.qname.hash(hashPerturbation));
}
shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
}
if (candidates.empty()) {
- if (g_roundrobinFailOnNoServer) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_roundrobinFailOnNoServer) {
return shared_ptr<DownstreamState>();
}
for (auto& d : servers) {
return servers.at(candidates.at((counter++) % candidates.size()) - 1).second;
}
-const std::shared_ptr<const ServerPolicy::NumberedServerVector> getDownstreamCandidates(const pools_t& pools, const std::string& poolName)
+std::shared_ptr<const ServerPolicy::NumberedServerVector> getDownstreamCandidates(const std::string& poolName)
{
- std::shared_ptr<ServerPool> pool = getPool(pools, poolName);
+ std::shared_ptr<ServerPool> pool = getPool(poolName);
return pool->getServers();
}
-std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName)
+std::shared_ptr<ServerPool> createPoolIfNotExists(const string& poolName)
{
- std::shared_ptr<ServerPool> pool;
- pools_t::iterator it = pools.find(poolName);
- if (it != pools.end()) {
- pool = it->second;
+ {
+ const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ const auto poolIt = pools.find(poolName);
+ if (poolIt != pools.end()) {
+ return poolIt->second;
+ }
}
- else {
- if (!poolName.empty())
- vinfolog("Creating pool %s", poolName);
- pool = std::make_shared<ServerPool>();
- pools.insert(std::pair<std::string, std::shared_ptr<ServerPool> >(poolName, pool));
+
+ if (!poolName.empty()) {
+ vinfolog("Creating pool %s", poolName);
}
+
+ auto pool = std::make_shared<ServerPool>();
+ dnsdist::configuration::updateRuntimeConfiguration([&poolName,&pool](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_pools.emplace(poolName, pool);
+ });
+
return pool;
}
-void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<ServerPolicy> policy)
+void setPoolPolicy(const string& poolName, std::shared_ptr<ServerPolicy> policy)
{
- std::shared_ptr<ServerPool> pool = createPoolIfNotExists(pools, poolName);
+ std::shared_ptr<ServerPool> pool = createPoolIfNotExists(poolName);
if (!poolName.empty()) {
vinfolog("Setting pool %s server selection policy to %s", poolName, policy->getName());
} else {
pool->policy = std::move(policy);
}
-void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server)
+void addServerToPool(const string& poolName, std::shared_ptr<DownstreamState> server)
{
- std::shared_ptr<ServerPool> pool = createPoolIfNotExists(pools, poolName);
+ std::shared_ptr<ServerPool> pool = createPoolIfNotExists(poolName);
if (!poolName.empty()) {
vinfolog("Adding server to pool %s", poolName);
} else {
pool->addServer(server);
}
-void removeServerFromPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server)
+void removeServerFromPool(const string& poolName, std::shared_ptr<DownstreamState> server)
{
- std::shared_ptr<ServerPool> pool = getPool(pools, poolName);
+ std::shared_ptr<ServerPool> pool = getPool(poolName);
if (!poolName.empty()) {
vinfolog("Removing server from pool %s", poolName);
pool->removeServer(server);
}
-std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName)
+std::shared_ptr<ServerPool> getPool(const std::string& poolName)
{
- pools_t::const_iterator it = pools.find(poolName);
-
- if (it == pools.end()) {
+ const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ auto poolIt = pools.find(poolName);
+ if (poolIt == pools.end()) {
throw std::out_of_range("No pool named " + poolName);
}
- return it->second;
+ return poolIt->second;
}
ServerPolicy::ServerPolicy(const std::string& name_, const std::string& code): d_name(name_), d_perThreadPolicyCode(code), d_isLua(true), d_isFFI(true), d_isPerThread(true)
auto ret = tmpContext.executeCode<ServerPolicy::ffipolicyfunc_t>(code);
}
-thread_local ServerPolicy::PerThreadState ServerPolicy::t_perThreadState;
+struct ServerPolicy::PerThreadState
+{
+ LuaContext d_luaContext;
+ std::unordered_map<std::string, ffipolicyfunc_t> d_policies;
+};
+
+thread_local std::unique_ptr<ServerPolicy::PerThreadState> ServerPolicy::t_perThreadState;
const ServerPolicy::ffipolicyfunc_t& ServerPolicy::getPerThreadPolicy() const
{
auto& state = t_perThreadState;
- if (!state.d_initialized) {
- setupLuaLoadBalancingContext(state.d_luaContext);
- state.d_initialized = true;
+ if (!state) {
+ state = std::make_unique<ServerPolicy::PerThreadState>();
+ setupLuaLoadBalancingContext(state->d_luaContext);
}
- const auto& it = state.d_policies.find(d_name);
- if (it != state.d_policies.end()) {
- return it->second;
+ const auto& policyIt = state->d_policies.find(d_name);
+ if (policyIt != state->d_policies.end()) {
+ return policyIt->second;
}
- auto newPolicy = state.d_luaContext.executeCode<ServerPolicy::ffipolicyfunc_t>(d_perThreadPolicyCode);
- state.d_policies[d_name] = std::move(newPolicy);
- return state.d_policies.at(d_name);
+ auto newPolicy = state->d_luaContext.executeCode<ServerPolicy::ffipolicyfunc_t>(d_perThreadPolicyCode);
+ state->d_policies[d_name] = std::move(newPolicy);
+ return state->d_policies.at(d_name);
}
std::shared_ptr<DownstreamState> ServerPolicy::getSelectedBackend(const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq) const
struct dnsdist_ffi_server_t;
struct dnsdist_ffi_dnsquestion_t;
+struct DNSQuestion;
struct DownstreamState;
struct PerThreadPoliciesState;
template <class T>
using NumberedVector = std::vector<std::pair<unsigned int, T>>;
using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
- typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
- typedef std::function<unsigned int(dnsdist_ffi_servers_list_t* servers, dnsdist_ffi_dnsquestion_t* dq)> ffipolicyfunc_t;
+ using policyfunc_t = std::function<std::shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)>;
+ using ffipolicyfunc_t = std::function<unsigned int(dnsdist_ffi_servers_list_t* servers, dnsdist_ffi_dnsquestion_t* dq)>;
ServerPolicy(const std::string& name_, policyfunc_t policy_, bool isLua_) :
d_name(name_), d_policy(std::move(policy_)), d_isLua(isLua_)
}
private:
- struct PerThreadState
- {
- LuaContext d_luaContext;
- std::unordered_map<std::string, ffipolicyfunc_t> d_policies;
- bool d_initialized{false};
- };
+ struct PerThreadState;
const ffipolicyfunc_t& getPerThreadPolicy() const;
- static thread_local PerThreadState t_perThreadState;
+ static thread_local std::unique_ptr<PerThreadState> t_perThreadState;
public:
std::string d_name;
struct ServerPool;
-using pools_t = map<std::string, std::shared_ptr<ServerPool>>;
-std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName);
-std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName);
-void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<ServerPolicy> policy);
-void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
-void removeServerFromPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
+using pools_t = std::map<std::string, std::shared_ptr<ServerPool>>;
+std::shared_ptr<ServerPool> getPool(const std::string& poolName);
+std::shared_ptr<ServerPool> createPoolIfNotExists(const string& poolName);
+void setPoolPolicy(const string& poolName, std::shared_ptr<ServerPolicy> policy);
+void addServerToPool(const string& poolName, std::shared_ptr<DownstreamState> server);
+void removeServerFromPool(const string& poolName, std::shared_ptr<DownstreamState> server);
-const std::shared_ptr<const ServerPolicy::NumberedServerVector> getDownstreamCandidates(const map<std::string, std::shared_ptr<ServerPool>>& pools, const std::string& poolName);
+std::shared_ptr<const ServerPolicy::NumberedServerVector> getDownstreamCandidates(const std::string& poolName);
std::shared_ptr<DownstreamState> firstAvailable(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
std::shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
std::shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t hash);
std::shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
-
-extern double g_consistentHashBalancingFactor;
-extern double g_weightedBalancingFactor;
-extern uint32_t g_hashperturb;
-extern bool g_roundrobinFailOnNoServer;
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-kvs.hh"
#include "dnsdist-rule-chains.hh"
+#include "dnsdist-snmp.hh"
#include "dnsdist-svc.hh"
#include "dnstap.hh"
void TeeAction::worker()
{
setThreadName("dnsdist/TeeWork");
- std::array<char, s_udpIncomingBufferSize> packet{};
+ std::array<char, dnsdist::configuration::s_udpIncomingBufferSize> packet{};
ssize_t res = 0;
const dnsheader_aligned dnsheader(packet.data());
for (;;) {
{
return "set rcode " + std::to_string(d_rcode);
}
- [[nodiscard]] ResponseConfig& getResponseConfig()
+ [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
{
return d_responseConfig;
}
private:
- ResponseConfig d_responseConfig;
+ dnsdist::ResponseConfig d_responseConfig;
uint8_t d_rcode;
};
{
return "set ercode " + ERCode::to_s(d_rcode);
}
- [[nodiscard]] ResponseConfig& getResponseConfig()
+ [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
{
return d_responseConfig;
}
private:
- ResponseConfig d_responseConfig;
+ dnsdist::ResponseConfig d_responseConfig;
uint8_t d_rcode;
};
throw std::runtime_error("Unable to generate a valid SVC record from the supplied parameters");
}
- d_totalPayloadsSize += payload.size();
d_payloads.push_back(std::move(payload));
for (const auto& hint : param.second.ipv4hints) {
DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- /* it will likely be a bit bigger than that because of additionals */
- auto numberOfRecords = d_payloads.size();
- const auto qnameWireLength = dnsquestion->ids.qname.wirelength();
- if (dnsquestion->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + d_totalPayloadsSize)) {
+ if (!dnsdist::svc::generateSVCResponse(*dnsquestion, d_payloads, d_additionals4, d_additionals6, d_responseConfig)) {
return Action::None;
}
- PacketBuffer newPacket;
- newPacket.reserve(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + d_totalPayloadsSize);
- GenericDNSPacketWriter<PacketBuffer> packetWriter(newPacket, dnsquestion->ids.qname, dnsquestion->ids.qtype);
- for (const auto& payload : d_payloads) {
- packetWriter.startRecord(dnsquestion->ids.qname, dnsquestion->ids.qtype, d_responseConfig.ttl);
- packetWriter.xfrBlob(payload);
- packetWriter.commit();
- }
-
- if (newPacket.size() < dnsquestion->getMaximumSize()) {
- for (const auto& additional : d_additionals4) {
- packetWriter.startRecord(additional.first.isRoot() ? dnsquestion->ids.qname : additional.first, QType::A, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
- packetWriter.xfrCAWithoutPort(4, additional.second);
- packetWriter.commit();
- }
- }
-
- if (newPacket.size() < dnsquestion->getMaximumSize()) {
- for (const auto& additional : d_additionals6) {
- packetWriter.startRecord(additional.first.isRoot() ? dnsquestion->ids.qname : additional.first, QType::AAAA, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
- packetWriter.xfrCAWithoutPort(6, additional.second);
- packetWriter.commit();
- }
- }
-
- if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
- bool dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
- packetWriter.addOpt(g_PayloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0);
- packetWriter.commit();
- }
-
- if (newPacket.size() >= dnsquestion->getMaximumSize()) {
- /* sorry! */
- return Action::None;
- }
-
- packetWriter.getHeader()->id = dnsquestion->getHeader()->id;
- packetWriter.getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*packetWriter.getHeader(), d_responseConfig);
- dnsquestion->getMutableData() = std::move(newPacket);
-
return Action::HeaderModify;
}
+
[[nodiscard]] std::string toString() const override
{
return "spoof SVC record ";
}
- [[nodiscard]] ResponseConfig& getResponseConfig()
+ [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
{
return d_responseConfig;
}
private:
- ResponseConfig d_responseConfig;
+ dnsdist::ResponseConfig d_responseConfig;
std::vector<std::vector<uint8_t>> d_payloads{};
std::set<std::pair<DNSName, ComboAddress>> d_additionals4{};
std::set<std::pair<DNSName, ComboAddress>> d_additionals6{};
- size_t d_totalPayloadsSize{0};
};
class TCAction : public DNSAction
bool dnssecOK = false;
bool hadEDNS = false;
- if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
hadEDNS = true;
- dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
+ dnssecOK = ((dnsdist::getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
}
auto& data = dnsquestion->getMutableData();
});
if (hadEDNS && !raw) {
- addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
+ addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0);
}
return Action::HeaderModify;
}
auto& data = dnsquestion->getMutableData();
- if (generateOptRR(optRData, data, dnsquestion->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
+ if (generateOptRR(optRData, data, dnsquestion->getMaximumSize(), dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
header.arcount = htons(1);
return true;
{
auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
if (!filepointer) {
- if (!d_verboseOnly || g_verbose) {
+ if (!d_verboseOnly || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
if (d_includeTimestamp) {
infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dnsquestion->getQueryRealTime().tv_sec), static_cast<unsigned long>(dnsquestion->getQueryRealTime().tv_nsec), dnsquestion->ids.origRemote.toStringWithPort(), dnsquestion->ids.qname.toString(), QType(dnsquestion->ids.qtype).toString(), dnsquestion->getHeader()->id);
}
{
auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
if (!filepointer) {
- if (!d_verboseOnly || g_verbose) {
+ if (!d_verboseOnly || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
if (d_includeTimestamp) {
infolog("[%u.%u] Answer to %s for %s %s (%s) with id %u", static_cast<unsigned long long>(response->getQueryRealTime().tv_sec), static_cast<unsigned long>(response->getQueryRealTime().tv_nsec), response->ids.origRemote.toStringWithPort(), response->ids.qname.toString(), QType(response->ids.qtype).toString(), RCode::to_s(response->getHeader()->rcode), response->getHeader()->id);
}
}
DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+ if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
g_snmpAgent->sendDNSTrap(*dnsquestion, d_reason);
}
}
DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
- if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+ if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
g_snmpAgent->sendDNSTrap(*response, d_reason);
}
return "return an HTTP status of " + std::to_string(d_code);
}
- [[nodiscard]] ResponseConfig& getResponseConfig()
+ [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
{
return d_responseConfig;
}
private:
- ResponseConfig d_responseConfig;
+ dnsdist::ResponseConfig d_responseConfig;
PacketBuffer d_body;
std::string d_contentType;
int d_code;
[[nodiscard]] std::string toString() const override
{
- return std::string(d_nxd ? "NXD " : "NODATA") + " with SOA";
+ return std::string(d_nxd ? "NXD" : "NODATA") + " with SOA";
}
- [[nodiscard]] ResponseConfig& getResponseConfig()
+ [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
{
return d_responseConfig;
}
private:
- ResponseConfig d_responseConfig;
+ dnsdist::ResponseConfig d_responseConfig;
DNSName d_zone;
DNSName d_mname;
EDNSExtendedError d_ede;
};
-template <typename T, typename ActionT>
-static void addAction(GlobalStateHolder<vector<T>>* someRuleActions, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params)
+template <typename ActionT, typename IdentifierT>
+static void addAction(IdentifierT identifier, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params)
{
setLuaSideEffect();
checkAllParametersConsumed("addAction", params);
auto rule = makeRule(var, "addAction");
- someRuleActions->modify([&rule, &action, &uuid, creationOrder, &name](vector<T>& ruleactions) {
- ruleactions.push_back({std::move(rule), std::move(action), std::move(name), uuid, creationOrder});
+ dnsdist::configuration::updateRuntimeConfiguration([identifier, &rule, &action, &name, &uuid, creationOrder](dnsdist::configuration::RuntimeConfiguration& config) {
+ dnsdist::rules::add(config.d_ruleChains, identifier, std::move(rule), action, std::move(name), uuid, creationOrder);
});
}
using responseParams_t = std::unordered_map<std::string, boost::variant<bool, uint32_t>>;
-static void parseResponseConfig(boost::optional<responseParams_t>& vars, ResponseConfig& config)
+static void parseResponseConfig(boost::optional<responseParams_t>& vars, dnsdist::ResponseConfig& config)
{
getOptionalValue<uint32_t>(vars, "ttl", config.ttl);
getOptionalValue<bool>(vars, "aa", config.setAA);
getOptionalValue<bool>(vars, "ra", config.setRA);
}
-void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config)
-{
- if (config.setAA) {
- dnsheader.aa = *config.setAA;
- }
- if (config.setAD) {
- dnsheader.ad = *config.setAD;
- }
- else {
- dnsheader.ad = false;
- }
- if (config.setRA) {
- dnsheader.ra = *config.setRA;
- }
- else {
- dnsheader.ra = dnsheader.rd; // for good measure
- }
-}
-
// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
void setupLuaActions(LuaContext& luaCtx)
{
return std::make_shared<dnsdist::rules::RuleAction>(ruleaction);
});
- for (const auto& chain : dnsdist::rules::getRuleChains()) {
+ for (const auto& chain : dnsdist::rules::getRuleChainDescriptions()) {
auto fullName = std::string("add") + chain.prefix + std::string("Action");
luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
throw std::runtime_error(fullName + "() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
}
- addAction(&chain.holder, var, boost::get<std::shared_ptr<DNSAction>>(era), params);
+ addAction(chain.identifier, var, boost::get<std::shared_ptr<DNSAction>>(era), params);
});
fullName = std::string("get") + chain.prefix + std::string("Action");
luaCtx.writeFunction(fullName, [&chain](unsigned int num) {
setLuaNoSideEffect();
boost::optional<std::shared_ptr<DNSAction>> ret;
- auto ruleactions = chain.holder.getCopy();
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& ruleactions = dnsdist::rules::getRuleChain(chains, chain.identifier);
if (num < ruleactions.size()) {
ret = ruleactions[num].d_action;
}
});
}
- for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
+ for (const auto& chain : dnsdist::rules::getResponseRuleChainDescriptions()) {
const auto fullName = std::string("add") + chain.prefix + std::string("ResponseAction");
luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
throw std::runtime_error(fullName + "() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
}
- addAction(&chain.holder, var, boost::get<std::shared_ptr<DNSResponseAction>>(era), params);
+ addAction(chain.identifier, var, boost::get<std::shared_ptr<DNSResponseAction>>(era), params);
});
}
#include "dnsdist-ecs.hh"
#include "dnsdist-internal-queries.hh"
#include "dnsdist-lua.hh"
+#include "dnsdist-snmp.hh"
#include "dnsparser.hh"
// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
}
dnsQuestion.ids.d_protoBufData->d_requestorID = newValue; });
luaCtx.registerFunction<bool (DNSQuestion::*)() const>("getDO", [](const DNSQuestion& dnsQuestion) {
- return getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO;
+ return dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO;
});
luaCtx.registerFunction<std::string (DNSQuestion::*)() const>("getContent", [](const DNSQuestion& dnsQuestion) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
luaCtx.registerFunction<void (DNSQuestion::*)(std::string)>("sendTrap", [](const DNSQuestion& dnsQuestion, boost::optional<std::string> reason) {
#ifdef HAVE_NET_SNMP
- if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+ if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
g_snmpAgent->sendDNSTrap(dnsQuestion, reason ? *reason : "");
}
#endif /* HAVE_NET_SNMP */
editDNSPacketTTL(reinterpret_cast<char*>(dnsResponse.getMutableData().data()), dnsResponse.getData().size(), editFunc);
});
luaCtx.registerFunction<bool (DNSResponse::*)() const>("getDO", [](const DNSResponse& dnsQuestion) {
- return getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO;
+ return dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO;
});
luaCtx.registerFunction<std::string (DNSResponse::*)() const>("getContent", [](const DNSResponse& dnsQuestion) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
luaCtx.registerFunction<void (DNSResponse::*)(std::string)>("sendTrap", [](const DNSResponse& dnsResponse, boost::optional<std::string> reason) {
#ifdef HAVE_NET_SNMP
- if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+ if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
g_snmpAgent->sendDNSTrap(dnsResponse, reason ? *reason : "");
}
#endif /* HAVE_NET_SNMP */
#include "config.h"
#include "dnsdist.hh"
+#include "dnsdist-cache.hh"
#include "dnsdist-lua.hh"
#include <boost/lexical_cast.hpp>
#include "config.h"
#include "dnsdist.hh"
#include "dnsdist-async.hh"
+#include "dnsdist-dynblocks.hh"
+#include "dnsdist-dynbpf.hh"
+#include "dnsdist-frontend.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-resolver.hh"
#include "dnsdist-svc.hh"
#include "dolog.hh"
#include "xsk.hh"
-// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
-void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
+void setupLuaBindingsLogging(LuaContext& luaCtx)
{
luaCtx.writeFunction("vinfolog", [](const string& arg) {
vinfolog("%s", arg);
g_outputBuffer += arg;
g_outputBuffer += "\n";
});
+}
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
+void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
+{
/* Exceptions */
luaCtx.registerFunction<string (std::exception_ptr::*)() const>("__tostring", [](const std::exception_ptr& eptr) -> std::string {
try {
/* DownstreamState */
luaCtx.registerFunction<void (DownstreamState::*)(int)>("setQPS", [](DownstreamState& state, int lim) { state.qps = lim > 0 ? QPSLimiter(lim, lim) : QPSLimiter(); });
luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](const std::shared_ptr<DownstreamState>& state, const string& pool) {
- auto localPools = g_pools.getCopy();
- addServerToPool(localPools, pool, state);
- g_pools.setState(localPools);
+ addServerToPool(pool, state);
state->d_config.pools.insert(pool);
});
luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](const std::shared_ptr<DownstreamState>& state, const string& pool) {
- auto localPools = g_pools.getCopy();
- removeServerFromPool(localPools, pool, state);
- g_pools.setState(localPools);
+ removeServerFromPool(pool, state);
state->d_config.pools.erase(pool);
});
luaCtx.registerFunction<uint64_t (DownstreamState::*)() const>("getOutstanding", [](const DownstreamState& state) { return state.outstanding.load(); });
});
luaCtx.registerFunction<std::string (DownstreamState::*)() const>("getName", [](const DownstreamState& state) -> const std::string& { return state.getName(); });
luaCtx.registerFunction<std::string (DownstreamState::*)() const>("getNameWithAddr", [](const DownstreamState& state) -> const std::string& { return state.getNameWithAddr(); });
- luaCtx.registerMember("upStatus", &DownstreamState::upStatus);
+ luaCtx.registerMember<bool(DownstreamState::*)>(
+ "upStatus",
+ [](const DownstreamState& state) -> bool { return state.upStatus.load(std::memory_order_relaxed); },
+ [](DownstreamState& state, bool newStatus) { state.upStatus.store(newStatus); });
luaCtx.registerMember<int(DownstreamState::*)>(
"weight",
[](const DownstreamState& state) -> int { return state.d_config.d_weight; },
luaCtx.registerFunction<bool (ComboAddress::*)() const>("isIPv6", [](const ComboAddress& addr) { return addr.sin4.sin_family == AF_INET6; });
luaCtx.registerFunction<bool (ComboAddress::*)() const>("isMappedIPv4", [](const ComboAddress& addr) { return addr.isMappedIPv4(); });
luaCtx.registerFunction<ComboAddress (ComboAddress::*)() const>("mapToIPv4", [](const ComboAddress& addr) { return addr.mapToIPv4(); });
- luaCtx.registerFunction<bool (nmts_t::*)(const ComboAddress&)>("match", [](nmts_t& set, const ComboAddress& addr) { return set.match(addr); });
+#ifndef DISABLE_DYNBLOCKS
+ luaCtx.registerFunction<bool (ClientAddressDynamicRules::*)(const ComboAddress&) const>("match", [](const ClientAddressDynamicRules& set, const ComboAddress& addr) { return set.match(addr); });
+#endif /* DISABLE_DYNBLOCKS */
#endif /* DISABLE_COMBO_ADDR_BINDINGS */
#ifndef DISABLE_DNSNAME_BINDINGS
luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter>& bpf) {
std::string res;
- if (!g_configurationDone) {
+ if (!dnsdist::configuration::isImmutableConfigurationDone()) {
throw std::runtime_error("attachToAllBinds() cannot be used at configuration time!");
return;
}
if (bpf) {
- for (const auto& frontend : g_frontends) {
+ for (const auto& frontend : dnsdist::getFrontends()) {
frontend->attachFilter(bpf, frontend->getSocket());
}
}
#ifdef HAVE_XSK
using xskopt_t = LuaAssociativeTable<boost::variant<uint32_t, std::string>>;
luaCtx.writeFunction("newXsk", [client](xskopt_t opts) {
- if (g_configurationDone) {
+ if (dnsdist::configuration::isImmutableConfigurationDone()) {
throw std::runtime_error("newXsk() only can be used at configuration time!");
}
if (client) {
uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
uint32_t dnsdist_ffi_dnsquestion_get_temp_failure_ttl(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
+uint8_t dnsdist_ffi_dnsquestion_get_edns_version(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
+uint8_t dnsdist_ffi_dnsquestion_get_edns_extended_rcode(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t* dq, const char** sni, size_t* sniSize) __attribute__ ((visibility ("default")));
const char* dnsdist_ffi_dnsquestion_get_tag(const dnsdist_ffi_dnsquestion_t* dq, const char* label) __attribute__ ((visibility ("default")));
size_t dnsdist_ffi_dnsquestion_get_tag_raw(const dnsdist_ffi_dnsquestion_t* dq, const char* label, char* buffer, size_t bufferSize) __attribute__ ((visibility ("default")));
size_t dnsdist_ffi_generate_proxy_protocol_payload(size_t addrSize, const void* srcAddr, const void* dstAddr, uint16_t srcPort, uint16_t dstPort, bool tcp, size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values, void* out, size_t outSize) __attribute__ ((visibility ("default")));
size_t dnsdist_ffi_dnsquestion_generate_proxy_protocol_payload(const dnsdist_ffi_dnsquestion_t* dq, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values, void* out, const size_t outSize) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dnsquestion_add_proxy_protocol_values(dnsdist_ffi_dnsquestion_t* dnsQuestion, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values) __attribute__ ((visibility ("default")));
typedef struct dnsdist_ffi_domain_list_t dnsdist_ffi_domain_list_t;
typedef struct dnsdist_ffi_address_list_t dnsdist_ffi_address_list_t;
void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t*) __attribute__ ((visibility ("default")));
uint32_t dnsdist_ffi_hash(uint32_t seed, const unsigned char* data, size_t dataSize, bool caseInsensitive) __attribute__ ((visibility ("default")));
+
+typedef struct dnsdist_ffi_svc_record_parameters dnsdist_ffi_svc_record_parameters;
+bool dnsdist_ffi_svc_record_parameters_new(const char* targetName, uint16_t priority, bool noDefaultALPN, dnsdist_ffi_svc_record_parameters** out) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_set_port(dnsdist_ffi_svc_record_parameters* parameters, uint16_t port) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_set_ech(dnsdist_ffi_svc_record_parameters* parameters, const char* ech, size_t echLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_set_additional_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key, const char* value, size_t valueLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_add_mandatory_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_add_alpn(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_add_ipv4_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_add_ipv6_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_free(dnsdist_ffi_svc_record_parameters* parameters) __attribute__ ((visibility ("default")));
+
+bool dnsdist_ffi_dnsquestion_generate_svc_response(dnsdist_ffi_dnsquestion_t* dnsQuestion, const dnsdist_ffi_svc_record_parameters** parametersList, size_t parametersListSize, uint32_t ttl) __attribute__ ((visibility ("default")));
*/
#include "dnsdist-async.hh"
+#include "dnsdist-cache.hh"
#include "dnsdist-dnsparser.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-rings.hh"
+#include "dnsdist-svc.hh"
+#include "dnsdist-snmp.hh"
#include "dolog.hh"
uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq)
return 0;
}
-bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dq)
+bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
{
- return getEDNSZ(*dq->dq) & EDNS_HEADER_FLAG_DO;
+ return (dnsdist::getEDNSZ(*dnsQuestion->dq) & EDNS_HEADER_FLAG_DO) != 0;
+}
+
+uint8_t dnsdist_ffi_dnsquestion_get_edns_version(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
+{
+ auto version = dnsdist::getEDNSVersion(*dnsQuestion->dq);
+ return version ? *version : 0U;
+}
+
+uint8_t dnsdist_ffi_dnsquestion_get_edns_extended_rcode(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
+{
+ auto rcode = dnsdist::getEDNSExtendedRCode(*dnsQuestion->dq);
+ return rcode ? *rcode : 0U;
}
void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t* dq, const char** sni, size_t* sniSize)
void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char* reason, size_t reasonLen)
{
- if (g_snmpAgent && g_snmpTrapsEnabled) {
+ if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
g_snmpAgent->sendDNSTrap(*dq->dq, std::string(reason, reasonLen));
}
}
{
setupLuaBindings(luaCtx, true, false);
setupLuaBindingsDNSQuestion(luaCtx);
+ setupLuaBindingsLogging(luaCtx);
setupLuaBindingsKVS(luaCtx, true);
setupLuaVars(luaCtx);
void setupLuaFFIPerThreadContext(LuaContext& luaCtx)
{
setupLuaVars(luaCtx);
+ setupLuaBindingsLogging(luaCtx);
#ifdef LUAJIT_VERSION
luaCtx.executeCode(getLuaFFIWrappers());
return payload.size();
}
+bool dnsdist_ffi_dnsquestion_add_proxy_protocol_values(dnsdist_ffi_dnsquestion_t* dnsQuestion, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values)
+{
+ if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || values == nullptr || valuesCount == 0) {
+ return false;
+ }
+
+ if (!dnsQuestion->dq->proxyProtocolValues) {
+ dnsQuestion->dq->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
+ }
+
+ dnsQuestion->dq->proxyProtocolValues->reserve(dnsQuestion->dq->proxyProtocolValues->size() + valuesCount);
+ for (size_t idx = 0; idx < valuesCount; idx++) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): the Lua FFI API is a C API..
+ dnsQuestion->dq->proxyProtocolValues->push_back({ std::string(values[idx].value, values[idx].size), values[idx].type });
+ }
+
+ return true;
+}
+
struct dnsdist_ffi_domain_list_t
{
std::vector<std::string> d_domains;
return 0;
}
- const auto localPools = g_pools.getCopy();
- auto it = localPools.find(poolName);
- if (it == localPools.end()) {
+ const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ auto poolIt = pools.find(poolName);
+ if (poolIt == pools.end()) {
return 0;
}
- auto pool = it->second;
+ auto pool = poolIt->second;
if (!pool->packetCache) {
return 0;
}
return 0;
}
- const auto localPools = g_pools.getCopy();
- auto it = localPools.find(poolName);
- if (it == localPools.end()) {
+ const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ auto poolIt = pools.find(poolName);
+ if (poolIt == pools.end()) {
return 0;
}
- auto pool = it->second;
+ auto pool = poolIt->second;
if (!pool->packetCache) {
return 0;
}
timespec until{now};
until.tv_sec += duration;
DynBlock dblock{message, until, DNSName(), static_cast<DNSAction::Action>(action)};
- auto slow = g_dynblockNMG.getCopy();
+
+ auto dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
if (dblock.action == DNSAction::Action::SetTag && tagKey != nullptr) {
dblock.tagSettings = std::make_shared<DynBlock::TagSettings>();
dblock.tagSettings->d_name = tagKey;
dblock.tagSettings->d_value = tagValue;
}
}
- if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, std::move(dblock), false)) {
- g_dynblockNMG.setState(slow);
+ if (dnsdist::DynamicBlocks::addOrRefreshBlock(dynamicRules, now, target, std::move(dblock), false)) {
+ dnsdist::DynamicBlocks::setClientAddressDynamicRules(std::move(dynamicRules));
return true;
}
}
timespec until{now};
until.tv_sec += duration;
DynBlock dblock{message, until, domain, static_cast<DNSAction::Action>(action)};
- auto slow = g_dynblockSMT.getCopy();
+ auto smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
if (dblock.action == DNSAction::Action::SetTag && tagKey != nullptr) {
dblock.tagSettings = std::make_shared<DynBlock::TagSettings>();
dblock.tagSettings->d_name = tagKey;
dblock.tagSettings->d_value = tagValue;
}
}
- if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, std::move(dblock), false)) {
- g_dynblockSMT.setState(slow);
+ if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(smtBlocks, now, std::move(dblock), false)) {
+ dnsdist::DynamicBlocks::setSuffixDynamicRules(std::move(smtBlocks));
return true;
}
}
auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
- struct timespec now
- {
- };
+ timespec now{};
gettime(&now);
- auto fullCopy = g_dynblockNMG.getCopy();
- for (const auto& entry : fullCopy) {
+ const auto& dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
+ for (const auto& entry : dynamicRules) {
const auto& client = entry.first;
const auto& details = entry.second;
if (!(now < details.until)) {
if (g_defaultBPFFilter && details.bpf) {
counter += g_defaultBPFFilter->getHits(client.getNetwork());
}
- list->d_entries.push_back({strdup(client.toString().c_str()), strdup(details.reason.c_str()), counter, static_cast<uint64_t>(details.until.tv_sec - now.tv_sec), static_cast<uint8_t>(details.action != DNSAction::Action::None ? details.action : g_dynBlockAction), g_defaultBPFFilter && details.bpf, details.warning});
+ list->d_entries.push_back({strdup(client.toString().c_str()), strdup(details.reason.c_str()), counter, static_cast<uint64_t>(details.until.tv_sec - now.tv_sec), static_cast<uint8_t>(details.action != DNSAction::Action::None ? details.action : dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction), g_defaultBPFFilter && details.bpf, details.warning});
}
auto count = list->d_entries.size();
auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
- struct timespec now
- {
- };
+ timespec now{};
gettime(&now);
- auto fullCopy = g_dynblockSMT.getCopy();
- fullCopy.visit([&now, &list](const SuffixMatchTree<DynBlock>& node) {
+ const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
+ const auto& smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRules();
+ smtBlocks.visit([&now, &list, defaultAction](const SuffixMatchTree<DynBlock>& node) {
if (!(now < node.d_value.until)) {
return;
}
key = entry.domain.toString();
}
if (entry.action == DNSAction::Action::None) {
- entry.action = g_dynBlockAction;
+ entry.action = defaultAction;
}
list->d_entries.push_back({strdup(key.c_str()), strdup(entry.reason.c_str()), entry.blocks, static_cast<uint64_t>(entry.until.tv_sec - now.tv_sec), static_cast<uint8_t>(entry.action), entry.bpf, entry.warning});
});
return burtle(data, dataSize, seed);
}
+
+struct dnsdist_ffi_svc_record_parameters
+{
+ SVCRecordParameters parameters;
+};
+
+bool dnsdist_ffi_svc_record_parameters_new(const char* targetName, uint16_t priority, bool noDefaultALPN, dnsdist_ffi_svc_record_parameters** out)
+{
+ if (targetName == nullptr || out == nullptr) {
+ return false;
+ }
+ try {
+ auto parameters = std::make_unique<dnsdist_ffi_svc_record_parameters>();
+ parameters->parameters.target = DNSName(targetName);
+ parameters->parameters.priority = priority;
+ parameters->parameters.noDefaultAlpn = noDefaultALPN;
+ *out = parameters.release();
+ return true;
+ }
+ catch (const std::exception& exp) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_new: %s", exp.what());
+ }
+ catch (const PDNSException& exp) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_new: %s", exp.reason);
+ }
+ catch (...) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_new");
+ }
+
+ return false;
+}
+
+void dnsdist_ffi_svc_record_parameters_set_port(dnsdist_ffi_svc_record_parameters* parameters, uint16_t port)
+{
+ if (parameters == nullptr) {
+ return;
+ }
+ parameters->parameters.port = port;
+}
+
+void dnsdist_ffi_svc_record_parameters_set_ech(dnsdist_ffi_svc_record_parameters* parameters, const char* ech, size_t echLen)
+{
+ if (parameters == nullptr || ech == nullptr || echLen == 0) {
+ return;
+ }
+ parameters->parameters.ech = std::string(ech, echLen);
+}
+
+void dnsdist_ffi_svc_record_parameters_set_additional_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key, const char* value, size_t valueLen)
+{
+ if (parameters == nullptr || (value == nullptr && valueLen != 0)) {
+ return;
+ }
+ parameters->parameters.additionalParams.emplace_back(key, std::string(value, valueLen));
+}
+
+void dnsdist_ffi_svc_record_parameters_add_mandatory_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key)
+{
+ if (parameters == nullptr) {
+ return;
+ }
+ parameters->parameters.mandatoryParams.insert(key);
+}
+
+void dnsdist_ffi_svc_record_parameters_add_alpn(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
+{
+ if (parameters == nullptr || value == nullptr || valueLen == 0) {
+ return;
+ }
+ parameters->parameters.alpns.emplace_back(value, valueLen);
+}
+
+void dnsdist_ffi_svc_record_parameters_add_ipv4_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
+{
+ if (parameters == nullptr || value == nullptr || valueLen == 0) {
+ return;
+ }
+ try {
+ parameters->parameters.ipv4hints.emplace_back(ComboAddress(std::string(value, valueLen)));
+ }
+ catch (const std::exception& exp) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.what());
+ }
+ catch (const PDNSException& exp) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.reason);
+ }
+ catch (...) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint");
+ }
+}
+
+void dnsdist_ffi_svc_record_parameters_add_ipv6_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
+{
+ if (parameters == nullptr || value == nullptr || valueLen == 0) {
+ return;
+ }
+ try {
+ parameters->parameters.ipv6hints.emplace_back(ComboAddress(std::string(value, valueLen)));
+ }
+ catch (const std::exception& exp) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.what());
+ }
+ catch (const PDNSException& exp) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.reason);
+ }
+ catch (...) {
+ errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint");
+ }
+}
+
+bool dnsdist_ffi_dnsquestion_generate_svc_response(dnsdist_ffi_dnsquestion_t* dnsQuestion, const dnsdist_ffi_svc_record_parameters** parametersList, size_t parametersListSize, uint32_t ttl)
+{
+ if (dnsQuestion == nullptr || parametersList == nullptr || parametersListSize == 0) {
+ return false;
+ }
+ std::vector<SVCRecordParameters> parameters;
+ parameters.reserve(parametersListSize);
+ for (size_t idx = 0; idx < parametersListSize; idx++) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): this is a C API
+ const auto* parameter = parametersList[idx];
+ if (parameter == nullptr) {
+ return false;
+ }
+ parameters.push_back(parameter->parameters);
+ }
+ return dnsdist::svc::generateSVCResponse(*dnsQuestion->dq, ttl, parameters);
+}
+
+void dnsdist_ffi_svc_record_parameters_free(dnsdist_ffi_svc_record_parameters* parameters)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): this is a C API, RAII is not an option
+ delete parameters;
+}
#include "dnsdist-lua-ffi-interface.h"
}
+#include "ext/luawrapper/include/LuaContext.hpp"
+
// dnsdist_ffi_dnsquestion_t is a lightuserdata
template<>
struct LuaContext::Pusher<dnsdist_ffi_dnsquestion_t*> {
#include "dnsdist-lua-hooks.hh"
#include "dnsdist-lua.hh"
#include "lock.hh"
+#include "tcpiohandler.hh"
namespace dnsdist::lua::hooks
{
+using MaintenanceCallback = std::function<void()>;
+using TicketsKeyAddedHook = std::function<void(const char*, size_t)>;
+
static LockGuarded<std::vector<MaintenanceCallback>> s_maintenanceHooks;
void runMaintenanceHooks(const LuaContext& context)
}
}
-void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback)
+static void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback)
{
(void)context;
s_maintenanceHooks.lock()->push_back(std::move(callback));
s_maintenanceHooks.lock()->clear();
}
+static void setTicketsKeyAddedHook(const LuaContext& context, const TicketsKeyAddedHook& hook)
+{
+ TLSCtx::setTicketsKeyAddedHook([hook](const std::string& key) {
+ try {
+ auto lua = g_lua.lock();
+ hook(key.c_str(), key.size());
+ }
+ catch (const std::exception& exp) {
+ warnlog("Error calling the Lua hook after new tickets key has been added: %s", exp.what());
+ }
+ });
+}
+
void setupLuaHooks(LuaContext& luaCtx)
{
luaCtx.writeFunction("addMaintenanceCallback", [&luaCtx](const MaintenanceCallback& callback) {
setLuaSideEffect();
addMaintenanceCallback(luaCtx, callback);
});
+ luaCtx.writeFunction("setTicketsKeyAddedHook", [&luaCtx](const TicketsKeyAddedHook& hook) {
+ setLuaSideEffect();
+ setTicketsKeyAddedHook(luaCtx, hook);
+ });
}
}
namespace dnsdist::lua::hooks
{
-using MaintenanceCallback = std::function<void()>;
void runMaintenanceHooks(const LuaContext& context);
-void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback);
void clearMaintenanceHooks();
void setupLuaHooks(LuaContext& luaCtx);
}
#include <fcntl.h>
#include "dnsdist.hh"
-#include "dnsdist-lua.hh"
+#include "dnsdist-console.hh"
#include "dnsdist-dynblocks.hh"
+#include "dnsdist-frontend.hh"
+#include "dnsdist-lua.hh"
#include "dnsdist-nghttp2.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-tcp.hh"
// NOLINTNEXTLINE(bugprone-exception-escape)
struct GrepQParams
{
- boost::optional<Netmask> netmask;
- boost::optional<DNSName> name;
+ std::optional<Netmask> netmask;
+ std::optional<DNSName> name;
+ std::optional<unsigned int> msec;
pdns::UniqueFilePtr outputFile{nullptr};
- int msec = -1;
};
static std::optional<GrepQParams> parseGrepQParams(const LuaTypeOrArrayOf<std::string>& inp, boost::optional<LuaAssociativeTable<std::string>>& options)
for (const auto& filter : filters) {
try {
result.netmask = Netmask(filter);
+ continue;
}
catch (...) {
- if (boost::ends_with(filter, "ms") && sscanf(filter.c_str(), "%ums", &result.msec) != 0) {
- ;
+ /* that's OK, let's try something else */
+ }
+
+ if (boost::ends_with(filter, "ms")) {
+ /* skip the ms at the end */
+ const auto msecStr = filter.substr(0, filter.size() - 2);
+ try {
+ result.msec = pdns::checked_stoi<unsigned int>(msecStr);
+ continue;
}
- else {
- try {
- result.name = DNSName(filter);
- }
- catch (...) {
- g_outputBuffer = "Could not parse '" + filter + "' as domain name or netmask";
- return std::nullopt;
- }
+ catch (...) {
+ /* that's OK, let's try to parse as a DNS name */
}
}
+
+ try {
+ result.name = DNSName(filter);
+ }
+ catch (...) {
+ g_outputBuffer = "Could not parse '" + filter + "' as domain name or netmask";
+ return std::nullopt;
+ }
}
return result;
}
constexpr bool response = std::is_same_v<C, Rings::Response>;
if constexpr (response) {
- if (params.msec != -1) {
- msecmatch = (entry.usec / 1000 > static_cast<unsigned int>(params.msec));
+ if (params.msec) {
+ msecmatch = (entry.usec / 1000 > *params.msec);
}
}
}
totalEntries += rings.back().size();
}
- vector<std::unordered_map<string, boost::variant<string, unsigned int>>> ret;
+ vector<std::unordered_map<string, boost::variant<unsigned int, string>>> ret;
ret.reserve(totalEntries);
for (const auto& ring : rings) {
for (const auto& entry : ring) {
luaCtx.executeCode(R"(function topResponses(top, kind, labels) top = top or 10; kind = kind or 0; for k,v in ipairs(getTopResponses(top, kind, labels)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
- luaCtx.writeFunction("getSlowResponses", [](uint64_t top, uint64_t msec, boost::optional<int> labels) {
- return getGenResponses(top, labels, [msec](const Rings::Response& resp) { return resp.usec > msec * 1000; });
+ luaCtx.writeFunction("getSlowResponses", [](uint64_t top, uint64_t msec, boost::optional<int> labels, boost::optional<bool> timeouts) {
+ return getGenResponses(top, labels, [msec, timeouts](const Rings::Response& resp) {
+ if (timeouts && *timeouts) {
+ return resp.usec == std::numeric_limits<unsigned int>::max();
+ }
+ return resp.usec > msec * 1000 && resp.usec != std::numeric_limits<unsigned int>::max();
+ });
});
- luaCtx.executeCode(R"(function topSlow(top, msec, labels) top = top or 10; msec = msec or 500; for k,v in ipairs(getSlowResponses(top, msec, labels)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
+ luaCtx.executeCode(R"(function topSlow(top, msec, labels) top = top or 10; msec = msec or 500; for k,v in ipairs(getSlowResponses(top, msec, labels, false)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
+
+ luaCtx.executeCode(R"(function topTimeouts(top, labels) top = top or 10; for k,v in ipairs(getSlowResponses(top, 0, labels, true)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
luaCtx.writeFunction("getTopBandwidth", [](uint64_t top) {
setLuaNoSideEffect();
luaCtx.writeFunction("delta", []() {
setLuaNoSideEffect();
// we hold the lua lock already!
- for (const auto& entry : g_confDelta) {
+ for (const auto& entry : dnsdist::console::getConfigurationDelta()) {
tm entryTime{};
localtime_r(&entry.first.tv_sec, &entryTime);
std::array<char, 80> date{};
fprintf(params.outputFile.get(), "%s", headLine.c_str());
}
- if (params.msec == -1) {
+ if (!params.msec) {
for (const auto& entry : queries) {
if (!ringEntryMatches(params, entry)) {
continue;
luaCtx.writeFunction("showTCPStats", [] {
setLuaNoSideEffect();
+ const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
ostringstream ret;
boost::format fmt("%-12d %-12d %-12d %-12d");
ret << (fmt % "Workers" % "Max Workers" % "Queued" % "Max Queued") << endl;
- ret << (fmt % g_tcpclientthreads->getThreadsCount() % (g_maxTCPClientThreads ? *g_maxTCPClientThreads : 0) % g_tcpclientthreads->getQueuedCount() % g_maxTCPQueuedConnections) << endl;
+ ret << (fmt % g_tcpclientthreads->getThreadsCount() % immutableConfig.d_maxTCPClientThreads % g_tcpclientthreads->getQueuedCount() % immutableConfig.d_maxTCPQueuedConnections) << endl;
ret << endl;
ret << "Frontends:" << endl;
ret << (fmt % "#" % "Address" % "Connections" % "Max concurrent conn" % "Died reading query" % "Died sending response" % "Gave up" % "Client timeouts" % "Downstream timeouts" % "Avg queries/conn" % "Avg duration" % "TLS new sessions" % "TLS Resumptions" % "TLS unknown ticket keys" % "TLS inactive ticket keys" % "TLS 1.0" % "TLS 1.1" % "TLS 1.2" % "TLS 1.3" % "TLS other") << endl;
size_t counter = 0;
- for (const auto& frontend : g_frontends) {
+ for (const auto& frontend : dnsdist::getFrontends()) {
ret << (fmt % counter % frontend->local.toStringWithPort() % frontend->tcpCurrentConnections % frontend->tcpMaxConcurrentConnections % frontend->tcpDiedReadingQuery % frontend->tcpDiedSendingResponse % frontend->tcpGaveUp % frontend->tcpClientTimeouts % frontend->tcpDownstreamTimeouts % frontend->tcpAvgQueriesPerConnection % frontend->tcpAvgConnectionDuration % frontend->tlsNewSessions % frontend->tlsResumptions % frontend->tlsUnknownTicketKey % frontend->tlsInactiveTicketKey % frontend->tls10queries % frontend->tls11queries % frontend->tls12queries % frontend->tls13queries % frontend->tlsUnknownqueries) << endl;
++counter;
}
fmt = boost::format("%-3d %-20.20s %-20.20s %-20d %-20d %-25d %-25d %-20d %-20d %-20d %-20d %-20d %-20d %-20d %-20d %-20f %-20f");
ret << (fmt % "#" % "Name" % "Address" % "Connections" % "Max concurrent conn" % "Died sending query" % "Died reading response" % "Gave up" % "Read timeouts" % "Write timeouts" % "Connect timeouts" % "Too many conn" % "Total connections" % "Reused connections" % "TLS resumptions" % "Avg queries/conn" % "Avg duration") << endl;
- auto states = g_dstates.getLocal();
counter = 0;
- for (const auto& backend : *states) {
+ for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
ret << (fmt % counter % backend->getName() % backend->d_config.remote.toStringWithPort() % backend->tcpCurrentConnections % backend->tcpMaxConcurrentConnections % backend->tcpDiedSendingQuery % backend->tcpDiedReadingResponse % backend->tcpGaveUp % backend->tcpReadTimeouts % backend->tcpWriteTimeouts % backend->tcpConnectTimeouts % backend->tcpTooManyConcurrentConnections % backend->tcpNewConnections % backend->tcpReusedConnections % backend->tlsResumptions % backend->tcpAvgQueriesPerConnection % backend->tcpAvgConnectionDuration) << endl;
++counter;
}
ret << (fmt % "#" % "Address" % "DH key too small" % "Inappropriate fallback" % "No shared cipher" % "Unknown cipher type" % "Unknown exchange type" % "Unknown protocol" % "Unsupported EC" % "Unsupported protocol") << endl;
size_t counter = 0;
- for (const auto& frontend : g_frontends) {
+ for (const auto& frontend : dnsdist::getFrontends()) {
if (!frontend->hasTLS()) {
continue;
}
if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
second = std::to_string((*val)->load());
}
- else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&entry.d_value)) {
second = (flt % (*adval)->load()).str();
}
- else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
- second = (flt % (**dval)).str();
- }
else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
second = std::to_string((*func)(entry.d_name));
}
/* DynBlock object accessors */
luaCtx.registerMember("reason", &DynBlock::reason);
luaCtx.registerMember("domain", &DynBlock::domain);
- luaCtx.registerMember("until", &DynBlock::until);
+ luaCtx.registerMember<DynBlock, timespec>(
+ "until", [](const DynBlock& block) {
+ timespec nowMonotonic{};
+ gettime(&nowMonotonic);
+ timespec nowRealTime{};
+ gettime(&nowRealTime, true);
+
+ auto seconds = block.until.tv_sec - nowMonotonic.tv_sec;
+ auto nseconds = block.until.tv_nsec - nowMonotonic.tv_nsec;
+ if (nseconds < 0) {
+ seconds -= 1;
+ nseconds += 1000000000;
+ }
+
+ nowRealTime.tv_sec += seconds;
+ nowRealTime.tv_nsec += nseconds;
+ if (nowRealTime.tv_nsec > 1000000000) {
+ nowRealTime.tv_sec += 1;
+ nowRealTime.tv_nsec -= 1000000000;
+ }
+
+ return nowRealTime; }, [](DynBlock& block, [[maybe_unused]] timespec until) {});
luaCtx.registerMember<DynBlock, unsigned int>(
"blocks", [](const DynBlock& block) { return block.blocks.load(); }, [](DynBlock& block, [[maybe_unused]] unsigned int blocks) {});
luaCtx.registerMember("action", &DynBlock::action);
parseDynamicActionOptionalParameters("addDynBlockSMT", rule, action, optionalParameters);
bool needUpdate = false;
- auto slow = g_dynblockSMT.getCopy();
+ auto smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
for (const auto& capair : names) {
DNSName domain(capair.second);
domain.makeUsLowerCase();
until.tv_sec += actualSeconds;
DynBlock dblock{msg, until, domain, action ? *action : DNSAction::Action::None};
dblock.tagSettings = rule.d_tagSettings;
- if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, std::move(dblock), false)) {
+ if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(smtBlocks, now, std::move(dblock), false)) {
needUpdate = true;
}
}
if (needUpdate) {
- g_dynblockSMT.setState(slow);
+ dnsdist::DynamicBlocks::setSuffixDynamicRules(std::move(smtBlocks));
}
});
DynBlock dblock{msg, until, DNSName(), action ? *action : DNSAction::Action::None};
dblock.tagSettings = rule.d_tagSettings;
- auto slow = g_dynblockNMG.getCopy();
- if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, std::move(dblock), false)) {
- g_dynblockNMG.setState(slow);
+ auto dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
+ if (dnsdist::DynamicBlocks::addOrRefreshBlock(dynamicRules, now, target, std::move(dblock), false)) {
+ dnsdist::DynamicBlocks::setClientAddressDynamicRules(std::move(dynamicRules));
}
});
#endif /* DISABLE_DYNBLOCKS */
return result;
}
-template <typename T>
-static void showRules(GlobalStateHolder<vector<T>>* someRuleActions, boost::optional<ruleparams_t>& vars)
+template <typename IdentifierT>
+static void showRules(IdentifierT identifier, boost::optional<ruleparams_t>& vars)
{
setLuaNoSideEffect();
- auto rules = someRuleActions->getLocal();
- g_outputBuffer += rulesToString(*rules, vars);
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& rules = dnsdist::rules::getRuleChain(chains, identifier);
+ g_outputBuffer += rulesToString(rules, vars);
}
-template <typename T>
-static void rmRule(GlobalStateHolder<vector<T>>* someRuleActions, const boost::variant<unsigned int, std::string>& ruleID)
+template <typename ChainTypeT, typename RuleTypeT>
+static bool removeRuleFromChain(ChainTypeT& rules, const std::function<bool(const RuleTypeT& rule)>& matchFunction)
+{
+ auto removeIt = std::remove_if(rules.begin(),
+ rules.end(),
+ matchFunction);
+ if (removeIt == rules.end()) {
+ g_outputBuffer = "Error: no rule matched\n";
+ return false;
+ }
+ rules.erase(removeIt,
+ rules.end());
+ return true;
+}
+
+template <typename ChainIdentifierT>
+static void rmRule(ChainIdentifierT chainIdentifier, const boost::variant<unsigned int, std::string>& ruleID)
{
- setLuaSideEffect();
- auto rules = someRuleActions->getCopy();
if (const auto* str = boost::get<std::string>(&ruleID)) {
try {
const auto uuid = getUniqueID(*str);
- auto removeIt = std::remove_if(rules.begin(),
- rules.end(),
- [&uuid](const T& rule) { return rule.d_id == uuid; });
- if (removeIt == rules.end()) {
- g_outputBuffer = "Error: no rule matched\n";
- return;
- }
- rules.erase(removeIt,
- rules.end());
+ dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier, &uuid](dnsdist::configuration::RuntimeConfiguration& config) {
+ constexpr bool isResponseChain = std::is_same_v<ChainIdentifierT, dnsdist::rules::ResponseRuleChain>;
+ if constexpr (isResponseChain) {
+ auto& rules = dnsdist::rules::getResponseRuleChain(config.d_ruleChains, chainIdentifier);
+ std::function<bool(const dnsdist::rules::ResponseRuleAction&)> matchFunction = [&uuid](const dnsdist::rules::ResponseRuleAction& rule) -> bool { return rule.d_id == uuid; };
+ removeRuleFromChain(rules, matchFunction);
+ }
+ else {
+ auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+ std::function<bool(const dnsdist::rules::RuleAction&)> matchFunction = [&uuid](const dnsdist::rules::RuleAction& rule) -> bool { return rule.d_id == uuid; };
+ removeRuleFromChain(rules, matchFunction);
+ }
+ });
}
catch (const std::runtime_error& e) {
- /* it was not an UUID, let's see if it was a name instead */
- auto removeIt = std::remove_if(rules.begin(),
- rules.end(),
- [&str](const T& rule) { return rule.d_name == *str; });
- if (removeIt == rules.end()) {
- g_outputBuffer = "Error: no rule matched\n";
- return;
- }
- rules.erase(removeIt,
- rules.end());
+ dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier, &str](dnsdist::configuration::RuntimeConfiguration& config) {
+ constexpr bool isResponseChain = std::is_same_v<ChainIdentifierT, dnsdist::rules::ResponseRuleChain>;
+ if constexpr (isResponseChain) {
+ auto& rules = dnsdist::rules::getResponseRuleChain(config.d_ruleChains, chainIdentifier);
+ std::function<bool(const dnsdist::rules::ResponseRuleAction&)> matchFunction = [&str](const dnsdist::rules::ResponseRuleAction& rule) -> bool { return rule.d_name == *str; };
+ removeRuleFromChain(rules, matchFunction);
+ }
+ else {
+ auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+ std::function<bool(const dnsdist::rules::RuleAction&)> matchFunction = [&str](const dnsdist::rules::RuleAction& rule) -> bool { return rule.d_name == *str; };
+ removeRuleFromChain(rules, matchFunction);
+ }
+ });
}
}
else if (const auto* pos = boost::get<unsigned int>(&ruleID)) {
- if (*pos >= rules.size()) {
- g_outputBuffer = "Error: attempt to delete non-existing rule\n";
- return;
- }
- rules.erase(rules.begin() + *pos);
+ dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier, pos](dnsdist::configuration::RuntimeConfiguration& config) {
+ auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+ if (*pos >= rules.size()) {
+ g_outputBuffer = "Error: attempt to delete non-existing rule\n";
+ return;
+ }
+ rules.erase(rules.begin() + *pos);
+ });
}
- someRuleActions->setState(std::move(rules));
+ setLuaSideEffect();
}
-template <typename T>
-static void moveRuleToTop(GlobalStateHolder<vector<T>>* someRuleActions)
+template <typename IdentifierTypeT>
+static void moveRuleToTop(IdentifierTypeT chainIdentifier)
{
setLuaSideEffect();
- auto rules = someRuleActions->getCopy();
- if (rules.empty()) {
- return;
- }
- auto subject = *rules.rbegin();
- rules.erase(std::prev(rules.end()));
- rules.insert(rules.begin(), subject);
- someRuleActions->setState(std::move(rules));
+ dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier](dnsdist::configuration::RuntimeConfiguration& config) {
+ auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+ if (rules.empty()) {
+ return;
+ }
+ //coverity[auto_causes_copy]
+ auto subject = *rules.rbegin();
+ rules.erase(std::prev(rules.end()));
+ rules.insert(rules.begin(), subject);
+ });
+ setLuaSideEffect();
}
-template <typename T>
-static void mvRule(GlobalStateHolder<vector<T>>* someRespRuleActions, unsigned int from, unsigned int destination)
+template <typename IdentifierTypeT>
+static void mvRule(IdentifierTypeT chainIdentifier, unsigned int from, unsigned int destination)
{
- setLuaSideEffect();
- auto rules = someRespRuleActions->getCopy();
- if (from >= rules.size() || destination > rules.size()) {
- g_outputBuffer = "Error: attempt to move rules from/to invalid index\n";
- return;
- }
- auto subject = rules[from];
- rules.erase(rules.begin() + from);
- if (destination > rules.size()) {
- rules.push_back(subject);
- }
- else {
- if (from < destination) {
- --destination;
+ dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier, from, &destination](dnsdist::configuration::RuntimeConfiguration& config) {
+ auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+ if (from >= rules.size() || destination > rules.size()) {
+ g_outputBuffer = "Error: attempt to move rules from/to invalid index\n";
+ return;
}
- rules.insert(rules.begin() + destination, subject);
- }
- someRespRuleActions->setState(std::move(rules));
+ //coverity[auto_causes_copy]
+ auto subject = rules[from];
+ rules.erase(rules.begin() + from);
+ if (destination > rules.size()) {
+ rules.push_back(subject);
+ }
+ else {
+ if (from < destination) {
+ --destination;
+ }
+ rules.insert(rules.begin() + destination, subject);
+ }
+ });
+ setLuaSideEffect();
}
template <typename T>
}
template <typename T>
-static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const boost::variant<int, std::string>& selector)
+static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const boost::variant<unsigned int, std::string>& selector)
{
if (const auto* str = boost::get<std::string>(&selector)) {
/* let's see if this a UUID */
}
}
}
- else if (const auto* pos = boost::get<int>(&selector)) {
+ else if (const auto* pos = boost::get<unsigned int>(&selector)) {
/* this will throw a std::out_of_range exception if the
supplied position is out of bounds, this is fine */
return rules.at(*pos);
luaCtx.registerFunction<std::shared_ptr<DNSResponseAction> (dnsdist::rules::ResponseRuleAction::*)() const>("getAction", [](const dnsdist::rules::ResponseRuleAction& rule) { return rule.d_action; });
- for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
+ for (const auto& chain : dnsdist::rules::getResponseRuleChainDescriptions()) {
luaCtx.writeFunction("show" + chain.prefix + "ResponseRules", [&chain](boost::optional<ruleparams_t> vars) {
- showRules(&chain.holder, vars);
+ showRules(chain.identifier, vars);
});
luaCtx.writeFunction("rm" + chain.prefix + "ResponseRule", [&chain](const boost::variant<unsigned int, std::string>& identifier) {
- rmRule(&chain.holder, identifier);
+ rmRule(chain.identifier, identifier);
});
luaCtx.writeFunction("mv" + chain.prefix + "ResponseRuleToTop", [&chain]() {
- moveRuleToTop(&chain.holder);
+ moveRuleToTop(chain.identifier);
});
luaCtx.writeFunction("mv" + chain.prefix + "ResponseRule", [&chain](unsigned int from, unsigned int dest) {
- mvRule(&chain.holder, from, dest);
+ mvRule(chain.identifier, from, dest);
});
- luaCtx.writeFunction("get" + chain.prefix + "ResponseRule", [&chain](const boost::variant<int, std::string>& selector) -> boost::optional<dnsdist::rules::ResponseRuleAction> {
- auto rules = chain.holder.getLocal();
- return getRuleFromSelector(*rules, selector);
+ luaCtx.writeFunction("get" + chain.prefix + "ResponseRule", [&chain](const boost::variant<unsigned int, std::string>& selector) -> boost::optional<dnsdist::rules::ResponseRuleAction> {
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& rules = dnsdist::rules::getResponseRuleChain(chains, chain.identifier);
+ return getRuleFromSelector(rules, selector);
});
luaCtx.writeFunction("getTop" + chain.prefix + "ResponseRules", [&chain](boost::optional<unsigned int> top) {
setLuaNoSideEffect();
- auto rules = chain.holder.getLocal();
- return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& rules = dnsdist::rules::getResponseRuleChain(chains, chain.identifier);
+ return toLuaArray(getTopRules(rules, (top ? *top : 10)));
});
luaCtx.writeFunction("top" + chain.prefix + "ResponseRules", [&chain](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
setLuaNoSideEffect();
- auto rules = chain.holder.getLocal();
- return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& rules = dnsdist::rules::getResponseRuleChain(chains, chain.identifier);
+ return rulesToString(getTopRules(rules, (top ? *top : 10)), vars);
});
luaCtx.writeFunction("clear" + chain.prefix + "ResponseRules", [&chain]() {
setLuaSideEffect();
- chain.holder.modify([](std::remove_reference_t<decltype(chain.holder)>::value_type& ruleactions) {
- ruleactions.clear();
+ dnsdist::configuration::updateRuntimeConfiguration([&chain](dnsdist::configuration::RuntimeConfiguration& config) {
+ auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chain.identifier);
+ rules.clear();
});
});
}
- for (const auto& chain : dnsdist::rules::getRuleChains()) {
+ for (const auto& chain : dnsdist::rules::getRuleChainDescriptions()) {
luaCtx.writeFunction("show" + chain.prefix + "Rules", [&chain](boost::optional<ruleparams_t> vars) {
- showRules(&chain.holder, vars);
+ showRules(chain.identifier, vars);
});
luaCtx.writeFunction("rm" + chain.prefix + "Rule", [&chain](const boost::variant<unsigned int, std::string>& identifier) {
- rmRule(&chain.holder, identifier);
+ rmRule(chain.identifier, identifier);
});
luaCtx.writeFunction("mv" + chain.prefix + "RuleToTop", [&chain]() {
- moveRuleToTop(&chain.holder);
+ moveRuleToTop(chain.identifier);
});
luaCtx.writeFunction("mv" + chain.prefix + "Rule", [&chain](unsigned int from, unsigned int dest) {
- mvRule(&chain.holder, from, dest);
+ mvRule(chain.identifier, from, dest);
});
luaCtx.writeFunction("get" + chain.prefix + "Rule", [&chain](const boost::variant<int, std::string>& selector) -> boost::optional<dnsdist::rules::RuleAction> {
- auto rules = chain.holder.getLocal();
- return getRuleFromSelector(*rules, selector);
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& rules = dnsdist::rules::getRuleChain(chains, chain.identifier);
+ return getRuleFromSelector(rules, selector);
});
luaCtx.writeFunction("getTop" + chain.prefix + "Rules", [&chain](boost::optional<unsigned int> top) {
setLuaNoSideEffect();
- auto rules = chain.holder.getLocal();
- return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& rules = dnsdist::rules::getRuleChain(chains, chain.identifier);
+ return toLuaArray(getTopRules(rules, (top ? *top : 10)));
});
luaCtx.writeFunction("top" + chain.prefix + "Rules", [&chain](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
setLuaNoSideEffect();
- auto rules = chain.holder.getLocal();
- return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& rules = dnsdist::rules::getRuleChain(chains, chain.identifier);
+
+ return rulesToString(getTopRules(rules, (top ? *top : 10)), vars);
});
luaCtx.writeFunction("clear" + chain.prefix + "Rules", [&chain]() {
setLuaSideEffect();
- chain.holder.modify([](std::remove_reference_t<decltype(chain.holder)>::value_type& ruleactions) {
- ruleactions.clear();
+ dnsdist::configuration::updateRuntimeConfiguration([&chain](dnsdist::configuration::RuntimeConfiguration& config) {
+ auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chain.identifier);
+ rules.clear();
});
});
luaCtx.writeFunction("set" + chain.prefix + "Rules", [&chain](const LuaArray<std::shared_ptr<dnsdist::rules::RuleAction>>& newruleactions) {
setLuaSideEffect();
- chain.holder.modify([newruleactions](std::remove_reference_t<decltype(chain.holder)>::value_type& gruleactions) {
- gruleactions.clear();
+ dnsdist::configuration::updateRuntimeConfiguration([&chain, &newruleactions](dnsdist::configuration::RuntimeConfiguration& config) {
+ auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chain.identifier);
+ rules.clear();
for (const auto& pair : newruleactions) {
const auto& newruleaction = pair.second;
if (newruleaction->d_action) {
auto rule = newruleaction->d_rule;
- gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder});
+ rules.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder});
}
}
});
#include "dnsdist-lua.hh"
#include "dnsdist-web.hh"
-void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler);
+namespace dnsdist::webserver
+{
+void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler, bool isLua);
+}
void setupLuaWeb(LuaContext& luaCtx)
{
#ifndef DISABLE_LUA_WEB_HANDLERS
luaCtx.writeFunction("registerWebHandler", [](const std::string& path, std::function<void(const YaHTTP::Request*, YaHTTP::Response*)> handler) {
/* LuaWrapper does a copy for objects passed by reference, so we pass a pointer */
- registerWebHandler(path, [handler](const YaHTTP::Request& req, YaHTTP::Response& resp) { handler(&req, &resp); });
+ dnsdist::webserver::registerWebHandler(path, [handler](const YaHTTP::Request& req, YaHTTP::Response& resp) { handler(&req, &resp); }, true);
});
luaCtx.registerMember<std::string(YaHTTP::Request::*)>("path", [](const YaHTTP::Request& req) -> std::string { return req.url.path; }, [](YaHTTP::Request& req, const std::string& path) { (void) path; });
});
#endif /* DISABLE_LUA_WEB_HANDLERS */
}
-
#include <vector>
#include "dnsdist.hh"
+#include "dnsdist-backend.hh"
+#include "dnsdist-cache.hh"
#include "dnsdist-carbon.hh"
#include "dnsdist-concurrent-connections.hh"
+#include "dnsdist-configuration.hh"
#include "dnsdist-console.hh"
#include "dnsdist-crypto.hh"
#include "dnsdist-dynblocks.hh"
+#include "dnsdist-dynbpf.hh"
#include "dnsdist-discovery.hh"
#include "dnsdist-ecs.hh"
+#include "dnsdist-frontend.hh"
#include "dnsdist-healthchecks.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-lua-hooks.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-secpoll.hh"
#include "dnsdist-session-cache.hh"
-#include "dnsdist-tcp-downstream.hh"
+#include "dnsdist-snmp.hh"
#include "dnsdist-web.hh"
#include "base64.hh"
using std::thread;
-static boost::optional<std::vector<std::function<void(void)>>> g_launchWork = boost::none;
-
-boost::tribool g_noLuaSideEffect;
-static bool g_included{false};
+static boost::tribool s_noLuaSideEffect;
/* this is a best effort way to prevent logging calls with no side-effects in the output of delta()
Functions can declare setLuaNoSideEffect() and if nothing else does declare a side effect, or nothing
has done so before on this invocation, this call won't be part of delta() output */
void setLuaNoSideEffect()
{
- if (g_noLuaSideEffect == false) {
+ if (s_noLuaSideEffect == false) {
// there has been a side effect already
return;
}
- g_noLuaSideEffect = true;
+ s_noLuaSideEffect = true;
}
void setLuaSideEffect()
{
- g_noLuaSideEffect = false;
+ s_noLuaSideEffect = false;
}
bool getLuaNoSideEffect()
{
- if (g_noLuaSideEffect) {
+ if (s_noLuaSideEffect) {
// NOLINTNEXTLINE(readability-simplify-boolean-expr): it's a tribool, not a boolean
return true;
}
void resetLuaSideEffect()
{
- g_noLuaSideEffect = boost::logic::indeterminate;
+ s_noLuaSideEffect = boost::logic::indeterminate;
}
using localbind_t = LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int>, LuaArray<std::string>, LuaAssociativeTable<std::string>, std::shared_ptr<XskSocket>>>;
static bool checkConfigurationTime(const std::string& name)
{
- if (!g_configurationDone) {
+ if (!dnsdist::configuration::isImmutableConfigurationDone()) {
return true;
}
g_outputBuffer = name + " cannot be used at runtime!\n";
}
#ifdef SO_BINDTODEVICE
/* we need to retain CAP_NET_RAW to be able to set SO_BINDTODEVICE in the health checks */
- g_capabilitiesToRetain.insert("CAP_NET_RAW");
+ dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::ImmutableConfiguration& currentConfig) {
+ currentConfig.d_capabilitiesToRetain.insert("CAP_NET_RAW");
+ });
#endif
}
else {
static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
{
luaCtx.writeFunction("inClientStartup", [client]() {
- return client && !g_configurationDone;
+ return client && !dnsdist::configuration::isImmutableConfigurationDone();
});
luaCtx.writeFunction("inConfigCheck", [configCheck]() {
if (getOptionalValue<std::string>(vars, "tls", valueStr) > 0) {
serverPort = 853;
config.d_tlsParams.d_provider = valueStr;
- tlsCtx = getTLSContext(config.d_tlsParams);
if (getOptionalValue<std::string>(vars, "dohPath", valueStr) > 0) {
#if !defined(HAVE_DNS_OVER_HTTPS) || !defined(HAVE_NGHTTP2)
serverPort = 443;
config.d_dohPath = valueStr;
+ config.d_tlsParams.d_alpn = TLSFrontend::ALPN::DoH;
getOptionalValue<bool>(vars, "addXForwardedHeaders", config.d_addXForwardedHeaders);
}
+ else {
+ config.d_tlsParams.d_alpn = TLSFrontend::ALPN::DoT;
+ }
+
+ tlsCtx = getTLSContext(config.d_tlsParams);
}
try {
#ifdef HAVE_XSK
LuaArray<std::shared_ptr<XskSocket>> luaXskSockets;
if (getOptionalValue<LuaArray<std::shared_ptr<XskSocket>>>(vars, "xskSockets", luaXskSockets) > 0 && !luaXskSockets.empty()) {
- if (g_configurationDone) {
+ if (dnsdist::configuration::isImmutableConfigurationDone()) {
throw std::runtime_error("Adding a server with xsk at runtime is not supported");
}
std::vector<std::shared_ptr<XskSocket>> xskSockets;
/* this needs to be done _AFTER_ the order has been set,
since the server are kept ordered inside the pool */
- auto localPools = g_pools.getCopy();
if (!ret->d_config.pools.empty()) {
for (const auto& poolName : ret->d_config.pools) {
- addServerToPool(localPools, poolName, ret);
+ addServerToPool(poolName, ret);
}
}
else {
- addServerToPool(localPools, "", ret);
+ addServerToPool("", ret);
}
- g_pools.setState(localPools);
if (ret->connected) {
- if (g_launchWork) {
- g_launchWork->push_back([ret]() {
- ret->start();
- });
- }
- else {
+ if (!dnsdist::configuration::isImmutableConfigurationDone()) {
ret->start();
}
}
- auto states = g_dstates.getCopy();
- states.push_back(ret);
- std::stable_sort(states.begin(), states.end(), [](const decltype(ret)& lhs, const decltype(ret)& rhs) {
- return lhs->d_config.order < rhs->d_config.order;
- });
- g_dstates.setState(states);
+ dnsdist::backend::registerNewBackend(ret);
+
checkAllParametersConsumed("newServer", vars);
return ret;
});
[](boost::variant<std::shared_ptr<DownstreamState>, int, std::string> var) {
setLuaSideEffect();
shared_ptr<DownstreamState> server = nullptr;
- auto states = g_dstates.getCopy();
if (auto* rem = boost::get<shared_ptr<DownstreamState>>(&var)) {
server = *rem;
}
else if (auto* str = boost::get<std::string>(&var)) {
const auto uuid = getUniqueID(*str);
- for (auto& state : states) {
+ for (const auto& state : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
if (*state->d_config.id == uuid) {
server = state;
}
}
else {
int idx = boost::get<int>(var);
- server = states.at(idx);
+ server = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends.at(idx);
}
if (!server) {
throw std::runtime_error("unable to locate the requested server");
}
- auto localPools = g_pools.getCopy();
for (const string& poolName : server->d_config.pools) {
- removeServerFromPool(localPools, poolName, server);
+ removeServerFromPool(poolName, server);
}
- /* the server might also be in the default pool */
- removeServerFromPool(localPools, "", server);
- g_pools.setState(localPools);
- states.erase(remove(states.begin(), states.end(), server), states.end());
- g_dstates.setState(states);
+
+ try {
+ /* the server might also be in the default pool */
+ removeServerFromPool("", server);
+ }
+ catch (const std::out_of_range& exp) {
+ /* but the default pool might not exist yet, this is fine */
+ }
+
+ dnsdist::configuration::updateRuntimeConfiguration([&server](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_backends.erase(std::remove(config.d_backends.begin(), config.d_backends.end(), server), config.d_backends.end());
+ });
+
server->stop();
});
- luaCtx.writeFunction("truncateTC", [](bool value) { setLuaSideEffect(); g_truncateTC = value; });
- luaCtx.writeFunction("fixupCase", [](bool value) { setLuaSideEffect(); g_fixupCase = value; });
+ struct BooleanConfigurationItems
+ {
+ const std::string name;
+ const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, bool newValue)> mutator;
+ };
+ static const std::vector<BooleanConfigurationItems> booleanConfigItems{
+ {"truncateTC", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_truncateTC = newValue; }},
+ {"fixupCase", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_fixupCase = newValue; }},
+ {"setECSOverride", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_ecsOverride = newValue; }},
+ {"setQueryCount", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_queryCountConfig.d_enabled = newValue; }},
+ {"setVerbose", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_verbose = newValue; }},
+ {"setVerboseHealthChecks", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_verboseHealthChecks = newValue; }},
+ {"setServFailWhenNoServer", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_servFailOnNoPolicy = newValue; }},
+ {"setRoundRobinFailOnNoServer", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_roundrobinFailOnNoServer = newValue; }},
+ {"setDropEmptyQueries", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_dropEmptyQueries = newValue; }},
+ {"setAllowEmptyResponse", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_allowEmptyResponse = newValue; }},
+ {"setConsoleConnectionsLogging", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_logConsoleConnections = newValue; }},
+ {"setProxyProtocolApplyACLToProxiedClients", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_applyACLToProxiedClients = newValue; }},
+ {"setAddEDNSToSelfGeneratedResponses", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_addEDNSToSelfGeneratedResponses = newValue; }},
+ };
+ struct UnsignedIntegerConfigurationItems
+ {
+ const std::string name;
+ const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, uint64_t value)> mutator;
+ const size_t maximumValue{std::numeric_limits<uint64_t>::max()};
+ };
+ static const std::vector<UnsignedIntegerConfigurationItems> unsignedIntegerConfigItems{
+ {"setCacheCleaningDelay", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_cacheCleaningDelay = newValue; }, std::numeric_limits<uint32_t>::max()},
+ {"setCacheCleaningPercentage", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_cacheCleaningPercentage = newValue; }, 100U},
+ {"setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheMaxSessionsPerBackend = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setOutgoingTLSSessionsCacheCleanupDelay", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheCleanupDelay = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setOutgoingTLSSessionsCacheMaxTicketValidity", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheSessionValidity = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setECSSourcePrefixV4", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_ECSSourcePrefixV4 = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setECSSourcePrefixV6", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_ECSSourcePrefixV6 = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setTCPRecvTimeout", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tcpRecvTimeout = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setTCPSendTimeout", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tcpSendTimeout = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setMaxTCPQueriesPerConnection", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_maxTCPQueriesPerConn = newValue; }, std::numeric_limits<uint64_t>::max()},
+ {"setMaxTCPConnectionDuration", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_maxTCPConnectionDuration = newValue; }, std::numeric_limits<uint32_t>::max()},
+ {"setStaleCacheEntriesTTL", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_staleCacheEntriesTTL = newValue; }, std::numeric_limits<uint32_t>::max()},
+ {"setConsoleOutputMaxMsgSize", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_consoleOutputMsgMaxSize = newValue; }, std::numeric_limits<uint32_t>::max()},
+#ifndef DISABLE_SECPOLL
+ {"setSecurityPollInterval", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_secPollInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+#endif /* DISABLE_SECPOLL */
+ {"setProxyProtocolMaximumPayloadSize", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_proxyProtocolMaximumSize = std::max(static_cast<uint64_t>(16), newValue); }, std::numeric_limits<uint32_t>::max()},
+ {"setPayloadSizeOnSelfGeneratedAnswers", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) {
+ if (newValue < 512) {
+ warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!");
+ g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!";
+ newValue = 512;
+ }
+ if (newValue > dnsdist::configuration::s_udpIncomingBufferSize) {
+ warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to %d instead!", dnsdist::configuration::s_udpIncomingBufferSize);
+ g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to " + std::to_string(dnsdist::configuration::s_udpIncomingBufferSize) + " instead";
+ newValue = dnsdist::configuration::s_udpIncomingBufferSize;
+ }
+ config.d_payloadSizeSelfGenAnswers = newValue;
+ },
+ std::numeric_limits<uint64_t>::max()},
+#ifndef DISABLE_DYNBLOCKS
+ {"setDynBlocksPurgeInterval", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_dynBlocksPurgeInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+#endif /* DISABLE_DYNBLOCKS */
+ };
+
+ struct StringConfigurationItems
+ {
+ const std::string name;
+ const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, const std::string& value)> mutator;
+ };
+ static const std::vector<StringConfigurationItems> stringConfigItems{
+#ifndef DISABLE_SECPOLL
+ {"setSecurityPollSuffix", [](dnsdist::configuration::RuntimeConfiguration& config, const std::string& newValue) { config.d_secPollSuffix = newValue; }},
+#endif /* DISABLE_SECPOLL */
+ };
+
+ for (const auto& item : booleanConfigItems) {
+ luaCtx.writeFunction(item.name, [&item](bool value) {
+ setLuaSideEffect();
+ dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+ item.mutator(config, value);
+ });
+ });
+ }
+
+ for (const auto& item : unsignedIntegerConfigItems) {
+ luaCtx.writeFunction(item.name, [&item](uint64_t value) {
+ setLuaSideEffect();
+ checkParameterBound(item.name, value, item.maximumValue);
+ dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+ item.mutator(config, value);
+ });
+ });
+ }
+
+ for (const auto& item : stringConfigItems) {
+ luaCtx.writeFunction(item.name, [&item](const std::string& value) {
+ setLuaSideEffect();
+ dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+ item.mutator(config, value);
+ });
+ });
+ }
+
+ struct BooleanImmutableConfigurationItems
+ {
+ const std::string name;
+ const std::function<void(dnsdist::configuration::ImmutableConfiguration& config, bool newValue)> mutator;
+ };
+ static const std::vector<BooleanImmutableConfigurationItems> booleanImmutableConfigItems{
+ {"setRandomizedOutgoingSockets", [](dnsdist::configuration::ImmutableConfiguration& config, bool newValue) { config.d_randomizeUDPSocketsToBackend = newValue; }},
+ {"setRandomizedIdsOverUDP", [](dnsdist::configuration::ImmutableConfiguration& config, bool newValue) { config.d_randomizeIDsToBackend = newValue; }},
+ };
+ struct UnsignedIntegerImmutableConfigurationItems
+ {
+ const std::string name;
+ const std::function<void(dnsdist::configuration::ImmutableConfiguration& config, uint64_t value)> mutator;
+ const size_t maximumValue{std::numeric_limits<uint64_t>::max()};
+ };
+ static const std::vector<UnsignedIntegerImmutableConfigurationItems> unsignedIntegerImmutableConfigItems
+ {
+ {"setMaxTCPQueuedConnections", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_maxTCPQueuedConnections = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setMaxTCPClientThreads", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_maxTCPClientThreads = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setMaxTCPConnectionsPerClient", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_maxTCPConnectionsPerClient = newValue; }, std::numeric_limits<uint64_t>::max()},
+ {"setTCPInternalPipeBufferSize", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_tcpInternalPipeBufferSize = newValue; }, std::numeric_limits<uint64_t>::max()},
+ {"setMaxCachedTCPConnectionsPerDownstream", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingTCPMaxIdlePerBackend = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setTCPDownstreamCleanupInterval", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingTCPCleanupInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+ {"setTCPDownstreamMaxIdleTime", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingTCPMaxIdleTime = newValue; }, std::numeric_limits<uint16_t>::max()},
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ {"setOutgoingDoHWorkerThreads", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingDoHWorkers = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setMaxIdleDoHConnectionsPerDownstream", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingDoHMaxIdlePerBackend = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setDoHDownstreamCleanupInterval", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingDoHCleanupInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+ {"setDoHDownstreamMaxIdleTime", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingDoHMaxIdleTime = newValue; }, std::numeric_limits<uint16_t>::max()},
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
+ {"setMaxUDPOutstanding", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_maxUDPOutstanding = newValue; }, std::numeric_limits<uint16_t>::max()},
+ {"setWHashedPertubation", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_hashPerturbation = newValue; }, std::numeric_limits<uint32_t>::max()},
+#ifndef DISABLE_RECVMMSG
+ {"setUDPMultipleMessagesVectorSize", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_udpVectorSize = newValue; }, std::numeric_limits<uint32_t>::max()},
+#endif /* DISABLE_RECVMMSG */
+ {"setUDPTimeout", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_udpTimeout = newValue; }, std::numeric_limits<uint8_t>::max()},
+ {"setConsoleMaximumConcurrentConnections", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_consoleMaxConcurrentConnections = newValue; }, std::numeric_limits<uint32_t>::max()},
+ {"setRingBuffersLockRetries", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_ringsNbLockTries = newValue; }, std::numeric_limits<uint64_t>::max()},
+ };
+
+ struct DoubleImmutableConfigurationItems
+ {
+ const std::string name;
+ const std::function<void(dnsdist::configuration::ImmutableConfiguration& config, double value)> mutator;
+ const double maximumValue{1.0};
+ };
+ static const std::vector<DoubleImmutableConfigurationItems> doubleImmutableConfigItems{
+ {"setConsistentHashingBalancingFactor", [](dnsdist::configuration::ImmutableConfiguration& config, double newValue) { config.d_consistentHashBalancingFactor = newValue; }, 1.0},
+ {"setWeightedBalancingFactor", [](dnsdist::configuration::ImmutableConfiguration& config, double newValue) { config.d_weightedBalancingFactor = newValue; }, 1.0},
+ };
+
+ for (const auto& item : booleanConfigItems) {
+ luaCtx.writeFunction(item.name, [&item](bool value) {
+ try {
+ dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+ item.mutator(config, value);
+ });
+ }
+ catch (const std::exception& exp) {
+ g_outputBuffer = item.name + " cannot be used at runtime!\n";
+ errlog("%s cannot be used at runtime!", item.name);
+ }
+ });
+ }
+
+ for (const auto& item : unsignedIntegerImmutableConfigItems) {
+ luaCtx.writeFunction(item.name, [&item](uint64_t value) {
+ checkParameterBound(item.name, value, item.maximumValue);
+ try {
+ dnsdist::configuration::updateImmutableConfiguration([value, &item](dnsdist::configuration::ImmutableConfiguration& config) {
+ item.mutator(config, value);
+ });
+ }
+ catch (const std::exception& exp) {
+ g_outputBuffer = item.name + " cannot be used at runtime!\n";
+ errlog("%s cannot be used at runtime!", item.name);
+ }
+ });
+ }
+ for (const auto& item : doubleImmutableConfigItems) {
+ luaCtx.writeFunction(item.name, [&item](double value) {
+ if (value > item.maximumValue) {
+ g_outputBuffer = "Invalid value passed to " + item.name + "()!\n";
+ errlog("Invalid value passed to %s()!", item.name);
+ return;
+ }
+
+ try {
+ dnsdist::configuration::updateImmutableConfiguration([value, &item](dnsdist::configuration::ImmutableConfiguration& config) {
+ item.mutator(config, value);
+ });
+ }
+ catch (const std::exception& exp) {
+ g_outputBuffer = item.name + " cannot be used at runtime!\n";
+ errlog("%s cannot be used at runtime!", item.name);
+ }
+ setLuaSideEffect();
+ });
+ }
- luaCtx.writeFunction("addACL", [](const std::string& domain) {
+ luaCtx.writeFunction("getVerbose", []() { return dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose; });
+
+ luaCtx.writeFunction("addACL", [](const std::string& mask) {
setLuaSideEffect();
- g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); });
+ dnsdist::configuration::updateRuntimeConfiguration([&mask](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_ACL.addMask(mask);
+ });
});
luaCtx.writeFunction("rmACL", [](const std::string& netmask) {
setLuaSideEffect();
- g_ACL.modify([netmask](NetmaskGroup& nmg) { nmg.deleteMask(netmask); });
+ dnsdist::configuration::updateRuntimeConfiguration([&netmask](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_ACL.deleteMask(netmask);
+ });
});
luaCtx.writeFunction("setLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) {
parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
+ auto frontends = dnsdist::configuration::getImmutableConfiguration().d_frontends;
try {
ComboAddress loc(addr, 53);
- for (auto it = g_frontends.begin(); it != g_frontends.end();) {
+ for (auto it = frontends.begin(); it != frontends.end();) {
/* DoH, DoT and DNSCrypt frontends are separate */
if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr && (*it)->dohFrontend == nullptr) {
- it = g_frontends.erase(it);
+ it = frontends.erase(it);
}
else {
++it;
}
// only works pre-startup, so no sync necessary
- auto udpCS = std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
- auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto udpCS = std::make_shared<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto tcpCS = std::make_shared<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
std::shared_ptr<XskSocket> socket;
parseXskVars(vars, socket);
if (socket) {
- udpCS->xskInfo = XskWorker::create();
- udpCS->xskInfo->sharedEmptyFrameOffset = socket->sharedEmptyFrameOffset;
+ udpCS->xskInfo = XskWorker::create(XskWorker::Type::Bidirectional, socket->sharedEmptyFrameOffset);
socket->addWorker(udpCS->xskInfo);
socket->addWorkerRoute(udpCS->xskInfo, loc);
+ udpCS->xskInfoResponder = XskWorker::create(XskWorker::Type::OutgoingOnly, socket->sharedEmptyFrameOffset);
+ socket->addWorker(udpCS->xskInfoResponder);
vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", socket->getXDPMode(), loc.toStringWithPort());
}
#endif /* HAVE_XSK */
- g_frontends.push_back(std::move(udpCS));
- g_frontends.push_back(std::move(tcpCS));
+ frontends.push_back(std::move(udpCS));
+ frontends.push_back(std::move(tcpCS));
checkAllParametersConsumed("setLocal", vars);
+ dnsdist::configuration::updateImmutableConfiguration([&frontends](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends = std::move(frontends);
+ });
}
catch (const std::exception& e) {
g_outputBuffer = "Error: " + string(e.what()) + "\n";
try {
ComboAddress loc(addr, 53);
// only works pre-startup, so no sync necessary
- auto udpCS = std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
- auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto udpCS = std::make_shared<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto tcpCS = std::make_shared<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
std::shared_ptr<XskSocket> socket;
parseXskVars(vars, socket);
if (socket) {
- udpCS->xskInfo = XskWorker::create();
- udpCS->xskInfo->sharedEmptyFrameOffset = socket->sharedEmptyFrameOffset;
+ udpCS->xskInfo = XskWorker::create(XskWorker::Type::Bidirectional, socket->sharedEmptyFrameOffset);
socket->addWorker(udpCS->xskInfo);
socket->addWorkerRoute(udpCS->xskInfo, loc);
+ udpCS->xskInfoResponder = XskWorker::create(XskWorker::Type::OutgoingOnly, socket->sharedEmptyFrameOffset);
+ socket->addWorker(udpCS->xskInfoResponder);
vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", socket->getXDPMode(), loc.toStringWithPort());
}
#endif /* HAVE_XSK */
- g_frontends.push_back(std::move(udpCS));
- g_frontends.push_back(std::move(tcpCS));
+ dnsdist::configuration::updateImmutableConfiguration([&udpCS, &tcpCS](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends.push_back(std::move(udpCS));
+ config.d_frontends.push_back(std::move(tcpCS));
+ });
checkAllParametersConsumed("addLocal", vars);
}
nmg.addMask(entry.second);
}
}
- g_ACL.setState(nmg);
+ dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_ACL = std::move(nmg);
+ });
});
luaCtx.writeFunction("setACLFromFile", [](const std::string& file) {
nmg.addMask(line);
}
- g_ACL.setState(nmg);
+ dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_ACL = std::move(nmg);
+ });
});
luaCtx.writeFunction("showACL", []() {
setLuaNoSideEffect();
- auto aclEntries = g_ACL.getLocal()->toStringVector();
+ auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.toStringVector();
for (const auto& entry : aclEntries) {
g_outputBuffer += entry + "\n";
#if 0
// Useful for debugging leaks, but might lead to race under load
// since other threads are still running.
- for (auto& frontend : g_tlslocals) {
+ for (auto& frontend : getDoTFrontends()) {
frontend->cleanup();
}
- g_tlslocals.clear();
g_rings.clear();
#endif /* 0 */
pdns::coverage::dumpCoverageData();
uint64_t totQueries{0};
uint64_t totDrops{0};
int counter = 0;
- auto states = g_dstates.getLocal();
- for (const auto& backend : *states) {
+ for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
string status = backend->getStatus();
string pools;
for (const auto& pool : backend->d_config.pools) {
setLuaNoSideEffect();
LuaArray<std::shared_ptr<DownstreamState>> ret;
int count = 1;
- for (const auto& backend : g_dstates.getCopy()) {
+ for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
ret.emplace_back(count++, backend);
}
return ret;
});
luaCtx.writeFunction("getPoolServers", [](const string& pool) {
- const auto poolServers = getDownstreamCandidates(g_pools.getCopy(), pool);
+ //coverity[auto_causes_copy]
+ const auto poolServers = getDownstreamCandidates(pool);
return *poolServers;
});
- luaCtx.writeFunction("getServer", [client](boost::variant<int, std::string> identifier) {
+ luaCtx.writeFunction("getServer", [client](boost::variant<unsigned int, std::string> identifier) {
if (client) {
return std::make_shared<DownstreamState>(ComboAddress());
}
- auto states = g_dstates.getCopy();
+ const auto& states = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
if (auto* str = boost::get<std::string>(&identifier)) {
const auto uuid = getUniqueID(*str);
for (auto& state : states) {
}
}
}
- else if (auto* pos = boost::get<int>(&identifier)) {
+ else if (auto* pos = boost::get<unsigned int>(&identifier)) {
return states.at(*pos);
}
#ifndef DISABLE_CARBON
luaCtx.writeFunction("carbonServer", [](const std::string& address, boost::optional<string> ourName, boost::optional<uint64_t> interval, boost::optional<string> namespace_name, boost::optional<string> instance_name) {
setLuaSideEffect();
- dnsdist::Carbon::Endpoint endpoint{ComboAddress(address, 2003),
- (namespace_name && !namespace_name->empty()) ? *namespace_name : "dnsdist",
- ourName ? *ourName : "",
- (instance_name && !instance_name->empty()) ? *instance_name : "main",
- (interval && *interval < std::numeric_limits<unsigned int>::max()) ? static_cast<unsigned int>(*interval) : 30};
- dnsdist::Carbon::addEndpoint(std::move(endpoint));
+ auto newEndpoint = dnsdist::Carbon::newEndpoint(address,
+ (ourName ? *ourName : ""),
+ (interval ? *interval : 30),
+ (namespace_name ? *namespace_name : "dnsdist"),
+ (instance_name ? *instance_name : "main"));
+ if (dnsdist::configuration::isImmutableConfigurationDone()) {
+ dnsdist::Carbon::run({newEndpoint});
+ }
+ dnsdist::configuration::updateRuntimeConfiguration([&newEndpoint](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_carbonEndpoints.push_back(std::move(newEndpoint));
+ });
});
#endif /* DISABLE_CARBON */
return;
}
- try {
- int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0);
- SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
- SBind(sock, local);
- SListen(sock, 5);
- auto launch = [sock, local]() {
- thread thr(dnsdistWebserverThread, sock, local);
+ dnsdist::configuration::updateRuntimeConfiguration([local](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_webServerAddress = local;
+ });
+
+ if (dnsdist::configuration::isImmutableConfigurationDone()) {
+ try {
+ auto sock = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+ sock.bind(local, true);
+ sock.listen(5);
+ thread thr(dnsdist::webserver::WebserverThread, std::move(sock));
thr.detach();
- };
- if (g_launchWork) {
- g_launchWork->push_back(launch);
}
- else {
- launch();
+ catch (const std::exception& e) {
+ g_outputBuffer = "Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what();
+ errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what());
}
}
- catch (const std::exception& e) {
- g_outputBuffer = "Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what();
- errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what());
- }
});
- typedef LuaAssociativeTable<boost::variant<bool, std::string, LuaAssociativeTable<std::string>>> webserveropts_t;
+ using webserveropts_t = LuaAssociativeTable<boost::variant<bool, std::string, LuaAssociativeTable<std::string>>>;
luaCtx.writeFunction("setWebserverConfig", [](boost::optional<webserveropts_t> vars) {
setLuaSideEffect();
return;
}
- bool hashPlaintextCredentials = false;
- getOptionalValue<bool>(vars, "hashPlaintextCredentials", hashPlaintextCredentials);
-
- std::string password;
- std::string apiKey;
- std::string acl;
- LuaAssociativeTable<std::string> headers;
- bool statsRequireAuthentication{true};
- bool apiRequiresAuthentication{true};
- bool dashboardRequiresAuthentication{true};
- int maxConcurrentConnections = 0;
+ dnsdist::configuration::updateRuntimeConfiguration([&vars](dnsdist::configuration::RuntimeConfiguration& config) {
+ std::string password;
+ std::string apiKey;
+ std::string acl;
+ LuaAssociativeTable<std::string> headers;
+ bool statsRequireAuthentication{true};
+ bool apiRequiresAuthentication{true};
+ bool dashboardRequiresAuthentication{true};
+ bool hashPlaintextCredentials = false;
+ getOptionalValue<bool>(vars, "hashPlaintextCredentials", hashPlaintextCredentials);
- if (getOptionalValue<std::string>(vars, "password", password) > 0) {
- auto holder = make_unique<CredentialsHolder>(std::move(password), hashPlaintextCredentials);
- if (!holder->wasHashed() && holder->isHashingAvailable()) {
- infolog("Passing a plain-text password via the 'password' parameter to 'setWebserverConfig()' is not advised, please consider generating a hashed one using 'hashPassword()' instead.");
+ if (getOptionalValue<std::string>(vars, "password", password) > 0) {
+ auto holder = std::make_shared<CredentialsHolder>(std::move(password), hashPlaintextCredentials);
+ if (!holder->wasHashed() && holder->isHashingAvailable()) {
+ infolog("Passing a plain-text password via the 'password' parameter to 'setWebserverConfig()' is not advised, please consider generating a hashed one using 'hashPassword()' instead.");
+ }
+ config.d_webPassword = std::move(holder);
}
- setWebserverPassword(std::move(holder));
- }
-
- if (getOptionalValue<std::string>(vars, "apiKey", apiKey) > 0) {
- auto holder = make_unique<CredentialsHolder>(std::move(apiKey), hashPlaintextCredentials);
- if (!holder->wasHashed() && holder->isHashingAvailable()) {
- infolog("Passing a plain-text API key via the 'apiKey' parameter to 'setWebserverConfig()' is not advised, please consider generating a hashed one using 'hashPassword()' instead.");
+ if (getOptionalValue<std::string>(vars, "apiKey", apiKey) > 0) {
+ auto holder = std::make_shared<CredentialsHolder>(std::move(apiKey), hashPlaintextCredentials);
+ if (!holder->wasHashed() && holder->isHashingAvailable()) {
+ infolog("Passing a plain-text API key via the 'apiKey' parameter to 'setWebserverConfig()' is not advised, please consider generating a hashed one using 'hashPassword()' instead.");
+ }
+ config.d_webAPIKey = std::move(holder);
}
- setWebserverAPIKey(std::move(holder));
- }
-
- if (getOptionalValue<std::string>(vars, "acl", acl) > 0) {
- setWebserverACL(acl);
- }
+ if (getOptionalValue<std::string>(vars, "acl", acl) > 0) {
+ NetmaskGroup ACLnmg;
+ ACLnmg.toMasks(acl);
+ config.d_webServerACL = std::move(ACLnmg);
+ }
- if (getOptionalValue<decltype(headers)>(vars, "customHeaders", headers) > 0) {
- setWebserverCustomHeaders(headers);
- }
+ if (getOptionalValue<decltype(headers)>(vars, "customHeaders", headers) > 0) {
+ config.d_webCustomHeaders = std::move(headers);
+ }
- if (getOptionalValue<bool>(vars, "statsRequireAuthentication", statsRequireAuthentication) > 0) {
- setWebserverStatsRequireAuthentication(statsRequireAuthentication);
- }
+ if (getOptionalValue<bool>(vars, "statsRequireAuthentication", statsRequireAuthentication) > 0) {
+ config.d_statsRequireAuthentication = statsRequireAuthentication;
+ }
- if (getOptionalValue<bool>(vars, "apiRequiresAuthentication", apiRequiresAuthentication) > 0) {
- setWebserverAPIRequiresAuthentication(apiRequiresAuthentication);
- }
+ if (getOptionalValue<bool>(vars, "apiRequiresAuthentication", apiRequiresAuthentication) > 0) {
+ config.d_apiRequiresAuthentication = apiRequiresAuthentication;
+ }
- if (getOptionalValue<bool>(vars, "dashboardRequiresAuthentication", dashboardRequiresAuthentication) > 0) {
- setWebserverDashboardRequiresAuthentication(dashboardRequiresAuthentication);
- }
+ if (getOptionalValue<bool>(vars, "dashboardRequiresAuthentication", dashboardRequiresAuthentication) > 0) {
+ config.d_dashboardRequiresAuthentication = dashboardRequiresAuthentication;
+ }
+ });
+ int maxConcurrentConnections = 0;
if (getOptionalIntegerValue("setWebserverConfig", vars, "maxConcurrentConnections", maxConcurrentConnections) > 0) {
- setWebserverMaxConcurrentConnections(maxConcurrentConnections);
+ dnsdist::webserver::setMaxConcurrentConnections(maxConcurrentConnections);
}
});
luaCtx.writeFunction("showWebserverConfig", []() {
setLuaNoSideEffect();
- return getWebserverConfig();
+ return dnsdist::webserver::getConfig();
});
luaCtx.writeFunction("hashPassword", [](const std::string& password, boost::optional<uint64_t> workFactor) {
ComboAddress local(str, 5199);
if (client || configCheck) {
- g_serverControl = local;
return;
}
- g_consoleEnabled = true;
+ dnsdist::configuration::updateRuntimeConfiguration([local](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_consoleServerAddress = local;
+ config.d_consoleEnabled = true;
+ });
#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
- if (g_configurationDone && g_consoleKey.empty()) {
+ if (dnsdist::configuration::isImmutableConfigurationDone() && dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey.empty()) {
warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
}
#endif
- try {
- auto sock = std::make_shared<Socket>(local.sin4.sin_family, SOCK_STREAM, 0);
- sock->bind(local, true);
- sock->listen(5);
- auto launch = [sock = std::move(sock), local]() {
- std::thread consoleControlThread(controlThread, sock, local);
+ if (dnsdist::configuration::isImmutableConfigurationDone()) {
+ try {
+ auto sock = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+ sock.bind(local, true);
+ sock.listen(5);
+ std::thread consoleControlThread(dnsdist::console::controlThread, std::move(sock));
consoleControlThread.detach();
- };
- if (g_launchWork) {
- g_launchWork->emplace_back(std::move(launch));
}
- else {
- launch();
+ catch (const std::exception& exp) {
+ g_outputBuffer = "Unable to bind to control socket on " + local.toStringWithPort() + ": " + exp.what();
+ errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), exp.what());
}
}
- catch (std::exception& e) {
- g_outputBuffer = "Unable to bind to control socket on " + local.toStringWithPort() + ": " + e.what();
- errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), e.what());
- }
});
luaCtx.writeFunction("addConsoleACL", [](const std::string& netmask) {
warnlog("Allowing remote access to the console while neither libsodium not libcrypto support has been enabled is not secure, and will result in cleartext communications");
#endif
- g_consoleACL.modify([netmask](NetmaskGroup& nmg) { nmg.addMask(netmask); });
+ dnsdist::configuration::updateRuntimeConfiguration([&netmask](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_consoleACL.addMask(netmask);
+ });
});
luaCtx.writeFunction("setConsoleACL", [](LuaTypeOrArrayOf<std::string> inp) {
nmg.addMask(entry.second);
}
}
- g_consoleACL.setState(nmg);
+ dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_consoleACL = std::move(nmg);
+ });
});
luaCtx.writeFunction("showConsoleACL", []() {
warnlog("Allowing remote access to the console while neither libsodium nor libcrypto support has not been enabled is not secure, and will result in cleartext communications");
#endif
- auto aclEntries = g_consoleACL.getLocal()->toStringVector();
+ auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleACL.toStringVector();
for (const auto& entry : aclEntries) {
g_outputBuffer += entry + "\n";
}
});
- luaCtx.writeFunction("setConsoleMaximumConcurrentConnections", [](uint64_t max) {
- setLuaSideEffect();
- setConsoleMaximumConcurrentConnections(max);
- });
-
luaCtx.writeFunction("clearQueryCounters", []() {
unsigned int size{0};
{
- auto records = g_qcount.records.write_lock();
+ auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
size = records->size();
records->clear();
}
luaCtx.writeFunction("getQueryCounters", [](boost::optional<uint64_t> optMax) {
setLuaNoSideEffect();
- auto records = g_qcount.records.read_lock();
+ auto records = dnsdist::QueryCount::g_queryCountRecords.read_lock();
g_outputBuffer = "query counting is currently: ";
- g_outputBuffer += g_qcount.enabled ? "enabled" : "disabled";
+ g_outputBuffer += dnsdist::configuration::getCurrentRuntimeConfiguration().d_queryCountConfig.d_enabled ? "enabled" : "disabled";
g_outputBuffer += (boost::format(" (%d records in buffer)\n") % records->size()).str();
boost::format fmt("%-3d %s: %d request(s)\n");
}
});
- luaCtx.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled = enabled; });
-
- luaCtx.writeFunction("setQueryCountFilter", [](QueryCountFilter func) {
- g_qcount.filter = std::move(func);
+ luaCtx.writeFunction("setQueryCountFilter", [](dnsdist::QueryCount::Configuration::Filter func) {
+ dnsdist::configuration::updateRuntimeConfiguration([&func](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_queryCountConfig.d_filter = std::move(func);
+ });
});
luaCtx.writeFunction("makeKey", []() {
});
luaCtx.writeFunction("setKey", [](const std::string& key) {
- if (!g_configurationDone && !g_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
+ if (!dnsdist::configuration::isImmutableConfigurationDone() && !dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
return; // but later setKeys() trump the -k value again
}
#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
#endif
setLuaSideEffect();
- string newkey;
- if (B64Decode(key, newkey) < 0) {
+ string newKey;
+ if (B64Decode(key, newKey) < 0) {
g_outputBuffer = string("Unable to decode ") + key + " as Base64";
errlog("%s", g_outputBuffer);
+ return;
}
- else {
- g_consoleKey = std::move(newkey);
- }
+
+ dnsdist::configuration::updateRuntimeConfiguration([&newKey](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_consoleKey = std::move(newKey);
+ });
});
luaCtx.writeFunction("clearConsoleHistory", []() {
- clearConsoleHistory();
+ dnsdist::console::clearHistory();
});
luaCtx.writeFunction("testCrypto", [](boost::optional<string> optTestMsg) {
setLuaNoSideEffect();
#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
try {
+ const auto& consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
string testmsg;
if (optTestMsg) {
dnsdist::crypto::authenticated::Nonce nonce2;
nonce1.init();
nonce2 = nonce1;
- string encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
- string decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
+ string encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, consoleKey, nonce1);
+ string decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, consoleKey, nonce2);
nonce1.increment();
nonce2.increment();
- encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
- decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
+ encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, consoleKey, nonce1);
+ decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, consoleKey, nonce2);
if (testmsg == decrypted) {
g_outputBuffer = "Everything is ok!\n";
#endif
});
- luaCtx.writeFunction("setTCPRecvTimeout", [](int timeout) { g_tcpRecvTimeout = timeout; });
-
- luaCtx.writeFunction("setTCPSendTimeout", [](int timeout) { g_tcpSendTimeout = timeout; });
-
- luaCtx.writeFunction("setUDPTimeout", [](int timeout) { DownstreamState::s_udpTimeout = timeout; });
-
- luaCtx.writeFunction("setMaxUDPOutstanding", [](uint64_t max) {
- if (!checkConfigurationTime("setMaxUDPOutstanding")) {
- return;
- }
-
- checkParameterBound("setMaxUDPOutstanding", max);
- g_maxOutstanding = max;
- });
-
- luaCtx.writeFunction("setMaxTCPClientThreads", [](uint64_t max) {
- if (!checkConfigurationTime("setMaxTCPClientThreads")) {
- return;
- }
- g_maxTCPClientThreads = max;
- });
-
- luaCtx.writeFunction("setMaxTCPQueuedConnections", [](uint64_t max) {
- if (!checkConfigurationTime("setMaxTCPQueuedConnections")) {
- return;
- }
- g_maxTCPQueuedConnections = max;
- });
-
- luaCtx.writeFunction("setMaxTCPQueriesPerConnection", [](uint64_t max) {
- if (!checkConfigurationTime("setMaxTCPQueriesPerConnection")) {
- return;
- }
- g_maxTCPQueriesPerConn = max;
- });
-
- luaCtx.writeFunction("setMaxTCPConnectionsPerClient", [](uint64_t max) {
- if (!checkConfigurationTime("setMaxTCPConnectionsPerClient")) {
- return;
- }
- dnsdist::IncomingConcurrentTCPConnectionsManager::setMaxTCPConnectionsPerClient(max);
- });
-
- luaCtx.writeFunction("setMaxTCPConnectionDuration", [](uint64_t max) {
- if (!checkConfigurationTime("setMaxTCPConnectionDuration")) {
- return;
- }
- g_maxTCPConnectionDuration = max;
- });
-
- luaCtx.writeFunction("setMaxCachedTCPConnectionsPerDownstream", [](uint64_t max) {
- setTCPDownstreamMaxIdleConnectionsPerBackend(max);
- });
-
-#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
- luaCtx.writeFunction("setMaxIdleDoHConnectionsPerDownstream", [](uint64_t max) {
- setDoHDownstreamMaxIdleConnectionsPerBackend(max);
- });
-
- luaCtx.writeFunction("setOutgoingDoHWorkerThreads", [](uint64_t workers) {
- if (!checkConfigurationTime("setOutgoingDoHWorkerThreads")) {
- return;
- }
- g_outgoingDoHWorkerThreads = workers;
- });
-#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-
- luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](uint64_t max) {
- if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketsPerBackend")) {
- return;
- }
- TLSSessionCache::setMaxTicketsPerBackend(max);
- });
-
- luaCtx.writeFunction("setOutgoingTLSSessionsCacheCleanupDelay", [](time_t delay) {
- if (!checkConfigurationTime("setOutgoingTLSSessionsCacheCleanupDelay")) {
- return;
- }
- TLSSessionCache::setCleanupDelay(delay);
- });
-
- luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketValidity", [](time_t validity) {
- if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketValidity")) {
- return;
- }
- TLSSessionCache::setSessionValidity(validity);
- });
-
luaCtx.writeFunction("getOutgoingTLSSessionCacheSize", []() {
setLuaNoSideEffect();
return g_sessionCache.getSize();
});
- luaCtx.writeFunction("setCacheCleaningDelay", [](uint64_t delay) {
- checkParameterBound("setCacheCleaningDelay", delay, std::numeric_limits<uint32_t>::max());
- g_cacheCleaningDelay = delay;
- });
-
- luaCtx.writeFunction("setCacheCleaningPercentage", [](uint64_t percentage) {
- if (percentage < 100) {
- g_cacheCleaningPercentage = percentage;
- }
- else {
- g_cacheCleaningPercentage = 100;
- }
- });
-
- luaCtx.writeFunction("setECSSourcePrefixV4", [](uint64_t prefix) {
- checkParameterBound("setECSSourcePrefixV4", prefix, std::numeric_limits<uint16_t>::max());
- g_ECSSourcePrefixV4 = prefix;
- });
-
- luaCtx.writeFunction("setECSSourcePrefixV6", [](uint64_t prefix) {
- checkParameterBound("setECSSourcePrefixV6", prefix, std::numeric_limits<uint16_t>::max());
- g_ECSSourcePrefixV6 = prefix;
- });
-
- luaCtx.writeFunction("setECSOverride", [](bool override) { g_ECSOverride = override; });
-
#ifndef DISABLE_DYNBLOCKS
luaCtx.writeFunction("showDynBlocks", []() {
setLuaNoSideEffect();
- auto slow = g_dynblockNMG.getCopy();
+ const auto dynBlockDefaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
+ const auto& clientAddressDynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
timespec now{};
gettime(&now);
boost::format fmt("%-24s %8d %8d %-10s %-20s %-10s %s\n");
g_outputBuffer = (fmt % "What" % "Seconds" % "Blocks" % "Warning" % "Action" % "eBPF" % "Reason").str();
- for (const auto& entry : slow) {
+ for (const auto& entry : clientAddressDynamicRules) {
if (now < entry.second.until) {
uint64_t counter = entry.second.blocks;
if (g_defaultBPFFilter && entry.second.bpf) {
counter += g_defaultBPFFilter->getHits(entry.first.getNetwork());
}
- g_outputBuffer += (fmt % entry.first.toString() % (entry.second.until.tv_sec - now.tv_sec) % counter % (entry.second.warning ? "true" : "false") % DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction) % (g_defaultBPFFilter && entry.second.bpf ? "*" : "") % entry.second.reason).str();
+ g_outputBuffer += (fmt % entry.first.toString() % (entry.second.until.tv_sec - now.tv_sec) % counter % (entry.second.warning ? "true" : "false") % DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : dynBlockDefaultAction) % (g_defaultBPFFilter && entry.second.bpf ? "*" : "") % entry.second.reason).str();
}
}
- auto slow2 = g_dynblockSMT.getCopy();
- slow2.visit([&now, &fmt](const SuffixMatchTree<DynBlock>& node) {
+ const auto& suffixDynamicRules = dnsdist::DynamicBlocks::getSuffixDynamicRules();
+ suffixDynamicRules.visit([&now, &fmt, dynBlockDefaultAction](const SuffixMatchTree<DynBlock>& node) {
if (now < node.d_value.until) {
string dom("empty");
if (!node.d_value.domain.empty()) {
dom = node.d_value.domain.toString();
}
- g_outputBuffer += (fmt % dom % (node.d_value.until.tv_sec - now.tv_sec) % node.d_value.blocks % (node.d_value.warning ? "true" : "false") % DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : g_dynBlockAction) % "" % node.d_value.reason).str();
+ g_outputBuffer += (fmt % dom % (node.d_value.until.tv_sec - now.tv_sec) % node.d_value.blocks % (node.d_value.warning ? "true" : "false") % DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : dynBlockDefaultAction) % "" % node.d_value.reason).str();
}
});
});
gettime(&now);
LuaAssociativeTable<DynBlock> entries;
- auto fullCopy = g_dynblockNMG.getCopy();
- for (const auto& blockPair : fullCopy) {
+ const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
+ for (const auto& blockPair : dnsdist::DynamicBlocks::getClientAddressDynamicRules()) {
const auto& requestor = blockPair.first;
if (!(now < blockPair.second.until)) {
continue;
entry.blocks += g_defaultBPFFilter->getHits(requestor.getNetwork());
}
if (entry.action == DNSAction::Action::None) {
- entry.action = g_dynBlockAction;
+ entry.action = defaultAction;
}
entries.emplace(requestor.toString(), std::move(entry));
}
gettime(&now);
LuaAssociativeTable<DynBlock> entries;
- auto fullCopy = g_dynblockSMT.getCopy();
- fullCopy.visit([&now, &entries](const SuffixMatchTree<DynBlock>& node) {
+ const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
+ const auto& suffixDynamicRules = dnsdist::DynamicBlocks::getSuffixDynamicRules();
+ suffixDynamicRules.visit([&now, &entries, defaultAction](const SuffixMatchTree<DynBlock>& node) {
if (!(now < node.d_value.until)) {
return;
}
key = entry.domain.toString();
}
if (entry.action == DNSAction::Action::None) {
- entry.action = g_dynBlockAction;
+ entry.action = defaultAction;
}
entries.emplace(std::move(key), std::move(entry));
});
luaCtx.writeFunction("clearDynBlocks", []() {
setLuaSideEffect();
- nmts_t nmg;
- g_dynblockNMG.setState(nmg);
- SuffixMatchTree<DynBlock> smt;
- g_dynblockSMT.setState(smt);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+ dnsdist::DynamicBlocks::clearSuffixDynamicRules();
});
#ifndef DISABLE_DEPRECATED_DYNBLOCK
return;
}
setLuaSideEffect();
- auto slow = g_dynblockNMG.getCopy();
+ auto dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
+
timespec now{};
gettime(&now);
timespec until{now};
unsigned int count = 0;
/* this legacy interface does not support ranges or ports, use DynBlockRulesGroup instead */
AddressAndPortRange requestor(capair.first, capair.first.isIPv4() ? 32 : 128, 0);
- auto* got = slow.lookup(requestor);
+ auto* got = dynamicRules.lookup(requestor);
bool expired = false;
if (got != nullptr) {
if (until < got->second.until) {
if (got == nullptr || expired) {
warnlog("Inserting dynamic block for %s for %d seconds: %s", capair.first.toString(), actualSeconds, msg);
}
- slow.insert(requestor).second = std::move(dblock);
+ dynamicRules.insert(requestor).second = std::move(dblock);
}
- g_dynblockNMG.setState(slow);
+ dnsdist::DynamicBlocks::setClientAddressDynamicRules(std::move(dynamicRules));
});
luaCtx.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
- if (!checkConfigurationTime("setDynBlocksAction")) {
- return;
- }
if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
- g_dynBlockAction = action;
+ dnsdist::configuration::updateRuntimeConfiguration([action](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_dynBlockAction = action;
+ });
}
else {
errlog("Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!");
}
});
#endif /* DISABLE_DEPRECATED_DYNBLOCK */
-
- luaCtx.writeFunction("setDynBlocksPurgeInterval", [](uint64_t interval) {
- DynBlockMaintenance::s_expiredDynBlocksPurgeInterval = static_cast<time_t>(interval);
- });
#endif /* DISABLE_DYNBLOCKS */
#ifdef HAVE_DNSCRYPT
auto ctx = std::make_shared<DNSCryptContext>(providerName, certKeys);
/* UDP */
- auto clientState = std::make_unique<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto clientState = std::make_shared<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
clientState->dnscryptCtx = ctx;
- g_dnsCryptLocals.push_back(ctx);
- g_frontends.push_back(std::move(clientState));
+
+ dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends.push_back(std::move(clientState));
+ });
/* TCP */
- clientState = std::make_unique<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState = std::make_shared<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
clientState->dnscryptCtx = std::move(ctx);
if (tcpListenQueueSize > 0) {
clientState->tcpListenQueueSize = tcpListenQueueSize;
clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
- g_frontends.push_back(std::move(clientState));
+ dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends.push_back(std::move(clientState));
+ });
}
catch (const std::exception& e) {
errlog("Error during addDNSCryptBind() processing: %s", e.what());
size_t idx = 0;
std::unordered_set<std::shared_ptr<DNSCryptContext>> contexts;
- for (const auto& frontend : g_frontends) {
+ for (const auto& frontend : dnsdist::getFrontends()) {
const std::shared_ptr<DNSCryptContext> ctx = frontend->dnscryptCtx;
if (!ctx || contexts.count(ctx) != 0) {
continue;
luaCtx.writeFunction("getDNSCryptBind", [](uint64_t idx) {
setLuaNoSideEffect();
std::shared_ptr<DNSCryptContext> ret = nullptr;
- if (idx < g_dnsCryptLocals.size()) {
- ret = g_dnsCryptLocals.at(idx);
+ auto frontends = dnsdist::getDNSCryptFrontends();
+ if (idx < frontends.size()) {
+ ret = frontends.at(idx);
}
return ret;
});
luaCtx.writeFunction("getDNSCryptBindCount", []() {
setLuaNoSideEffect();
- return g_dnsCryptLocals.size();
+ return dnsdist::getDNSCryptFrontends().size();
});
#endif /* HAVE_DNSCRYPT */
// 1 2 3 4
ret << (fmt % "Name" % "Cache" % "ServerPolicy" % "Servers") << endl;
- const auto localPools = g_pools.getCopy();
- for (const auto& entry : localPools) {
+ //coverity[auto_causes_copy]
+ const auto defaultPolicyName = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName();
+ //coverity[auto_causes_copy]
+ const auto pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ for (const auto& entry : pools) {
const string& name = entry.first;
const std::shared_ptr<ServerPool> pool = entry.second;
string cache = pool->packetCache != nullptr ? pool->packetCache->toString() : "";
- string policy = g_policy.getLocal()->getName();
+ string policy = defaultPolicyName;
if (pool->policy != nullptr) {
policy = pool->policy->getName();
}
setLuaNoSideEffect();
LuaArray<std::string> ret;
int count = 1;
- const auto localPools = g_pools.getCopy();
- for (const auto& entry : localPools) {
+ const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ for (const auto& entry : pools) {
const string& name = entry.first;
ret.emplace_back(count++, name);
}
if (client) {
return std::make_shared<ServerPool>();
}
- auto localPools = g_pools.getCopy();
- std::shared_ptr<ServerPool> pool = createPoolIfNotExists(localPools, poolName);
- g_pools.setState(localPools);
+ std::shared_ptr<ServerPool> pool = createPoolIfNotExists(poolName);
return pool;
});
- luaCtx.writeFunction("setVerbose", [](bool verbose) { g_verbose = verbose; });
- luaCtx.writeFunction("getVerbose", []() { return g_verbose; });
- luaCtx.writeFunction("setVerboseHealthChecks", [](bool verbose) { g_verboseHealthChecks = verbose; });
luaCtx.writeFunction("setVerboseLogDestination", [](const std::string& dest) {
if (!checkConfigurationTime("setVerboseLogDestination")) {
return;
dnsdist::logging::LoggingConfiguration::setStructuredLogging(enable, levelPrefix);
});
- luaCtx.writeFunction("setStaleCacheEntriesTTL", [](uint64_t ttl) {
- checkParameterBound("setStaleCacheEntriesTTL", ttl, std::numeric_limits<uint32_t>::max());
- g_staleCacheEntriesTTL = ttl;
- });
-
luaCtx.writeFunction("showBinds", []() {
setLuaNoSideEffect();
try {
ret << (fmt % "#" % "Address" % "Protocol" % "Queries") << endl;
size_t counter = 0;
- for (const auto& front : g_frontends) {
+ for (const auto& front : dnsdist::getFrontends()) {
ret << (fmt % counter % front->local.toStringWithPort() % front->getType() % front->queries) << endl;
counter++;
}
luaCtx.writeFunction("getBind", [](uint64_t num) {
setLuaNoSideEffect();
ClientState* ret = nullptr;
- if (num < g_frontends.size()) {
- ret = g_frontends[num].get();
+ auto frontends = dnsdist::getFrontends();
+ if (num < frontends.size()) {
+ ret = frontends[num].get();
}
return ret;
});
luaCtx.writeFunction("getBindCount", []() {
setLuaNoSideEffect();
- return g_frontends.size();
+ return dnsdist::getFrontends().size();
});
luaCtx.writeFunction("help", [](boost::optional<std::string> command) {
setLuaNoSideEffect();
g_outputBuffer = "";
#ifndef DISABLE_COMPLETION
- for (const auto& keyword : g_consoleKeywords) {
+ for (const auto& keyword : dnsdist::console::getConsoleKeywords()) {
if (!command) {
g_outputBuffer += keyword.toString() + "\n";
}
if (!checkConfigurationTime("includeDirectory")) {
return;
}
- if (g_included) {
+ static bool s_included{false};
+
+ if (s_included) {
errlog("includeDirectory() cannot be used recursively!");
g_outputBuffer = "includeDirectory() cannot be used recursively!\n";
return;
std::sort(files.begin(), files.end());
- g_included = true;
+ s_included = true;
for (const auto& file : files) {
std::ifstream ifs(file);
luaCtx.executeCode(ifs);
}
catch (...) {
- g_included = false;
+ s_included = false;
throw;
}
luaCtx.executeCode(ifs);
}
- g_included = false;
+ s_included = false;
});
luaCtx.writeFunction("setAPIWritable", [](bool writable, boost::optional<std::string> apiConfigDir) {
- setLuaSideEffect();
- g_apiReadWrite = writable;
- if (apiConfigDir) {
+ if (apiConfigDir && (*apiConfigDir).empty()) {
+ errlog("The API configuration directory value cannot be empty!");
+ g_outputBuffer = "The API configuration directory value cannot be empty!";
+ return;
+ }
+ dnsdist::configuration::updateRuntimeConfiguration([writable, &apiConfigDir](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_apiReadWrite = writable;
if (!(*apiConfigDir).empty()) {
- g_apiConfigDirectory = *apiConfigDir;
- }
- else {
- errlog("The API configuration directory value cannot be empty!");
- g_outputBuffer = "The API configuration directory value cannot be empty!";
+ config.d_apiConfigDirectory = *apiConfigDir;
}
- }
- });
-
- luaCtx.writeFunction("setServFailWhenNoServer", [](bool servfail) {
- setLuaSideEffect();
- g_servFailOnNoPolicy = servfail;
- });
-
- luaCtx.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
+ });
setLuaSideEffect();
- g_roundrobinFailOnNoServer = fail;
});
- luaCtx.writeFunction("setConsistentHashingBalancingFactor", [](double factor) {
- setLuaSideEffect();
- if (factor >= 1.0) {
- g_consistentHashBalancingFactor = factor;
- }
- else {
- errlog("Invalid value passed to setConsistentHashingBalancingFactor()!");
- g_outputBuffer = "Invalid value passed to setConsistentHashingBalancingFactor()!\n";
+ luaCtx.writeFunction("setRingBuffersSize", [client](uint64_t capacity, boost::optional<uint64_t> numberOfShards) {
+ if (client) {
return;
}
- });
-
- luaCtx.writeFunction("setWeightedBalancingFactor", [](double factor) {
setLuaSideEffect();
- if (factor >= 1.0) {
- g_weightedBalancingFactor = factor;
+ try {
+ dnsdist::configuration::updateImmutableConfiguration([capacity, numberOfShards](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_ringsCapacity = capacity;
+ if (numberOfShards) {
+ config.d_ringsNumberOfShards = *numberOfShards;
+ }
+ });
}
- else {
- errlog("Invalid value passed to setWeightedBalancingFactor()!");
- g_outputBuffer = "Invalid value passed to setWeightedBalancingFactor()!\n";
- return;
+ catch (const std::exception& exp) {
+ g_outputBuffer = "setRingBuffersSize cannot be used at runtime!\n";
+ errlog("setRingBuffersSize cannot be used at runtime!");
}
});
- luaCtx.writeFunction("setRingBuffersSize", [client](uint64_t capacity, boost::optional<uint64_t> numberOfShards) {
- setLuaSideEffect();
- if (!checkConfigurationTime("setRingBuffersSize")) {
+ luaCtx.writeFunction("setRingBuffersOptions", [client](const LuaAssociativeTable<boost::variant<bool, uint64_t>>& options) {
+ if (client) {
return;
}
- if (!client) {
- g_rings.setCapacity(capacity, numberOfShards ? *numberOfShards : 10);
- }
- else {
- g_rings.setCapacity(0, 1);
- }
- });
-
- luaCtx.writeFunction("setRingBuffersLockRetries", [](uint64_t retries) {
- setLuaSideEffect();
- g_rings.setNumberOfLockRetries(retries);
- });
-
- luaCtx.writeFunction("setRingBuffersOptions", [](const LuaAssociativeTable<boost::variant<bool, uint64_t>>& options) {
setLuaSideEffect();
- if (!checkConfigurationTime("setRingBuffersOptions")) {
- return;
- }
- if (options.count("lockRetries") > 0) {
- auto retries = boost::get<uint64_t>(options.at("lockRetries"));
- g_rings.setNumberOfLockRetries(retries);
- }
- if (options.count("recordQueries") > 0) {
- auto record = boost::get<bool>(options.at("recordQueries"));
- g_rings.setRecordQueries(record);
+ try {
+ dnsdist::configuration::updateImmutableConfiguration([&options](dnsdist::configuration::ImmutableConfiguration& config) {
+ if (options.count("lockRetries") > 0) {
+ config.d_ringsNbLockTries = boost::get<uint64_t>(options.at("lockRetries"));
+ }
+ if (options.count("recordQueries") > 0) {
+ config.d_ringsRecordQueries = boost::get<bool>(options.at("recordQueries"));
+ }
+ if (options.count("recordResponses") > 0) {
+ config.d_ringsRecordResponses = boost::get<bool>(options.at("recordResponses"));
+ }
+ });
}
- if (options.count("recordResponses") > 0) {
- auto record = boost::get<bool>(options.at("recordResponses"));
- g_rings.setRecordResponses(record);
+ catch (const std::exception& exp) {
+ g_outputBuffer = "setRingBuffersOption cannot be used at runtime!\n";
+ errlog("setRingBuffersOption cannot be used at runtime!");
}
});
- luaCtx.writeFunction("setWHashedPertubation", [](uint64_t perturb) {
- setLuaSideEffect();
- checkParameterBound("setWHashedPertubation", perturb, std::numeric_limits<uint32_t>::max());
- g_hashperturb = perturb;
- });
-
- luaCtx.writeFunction("setTCPInternalPipeBufferSize", [](uint64_t size) { g_tcpInternalPipeBufferSize = size; });
luaCtx.writeFunction("setTCPFastOpenKey", [](const std::string& keyString) {
- setLuaSideEffect();
- std::array<uint32_t, 4> key{};
- // NOLINTNEXTLINE(readability-container-data-pointer)
- auto ret = sscanf(keyString.c_str(), "%" SCNx32 "-%" SCNx32 "-%" SCNx32 "-%" SCNx32, &key[0], &key[1], &key[2], &key[3]);
- if (ret != 4) {
+ std::vector<uint32_t> key(4);
+ auto ret = sscanf(keyString.c_str(), "%" SCNx32 "-%" SCNx32 "-%" SCNx32 "-%" SCNx32, &key.at(0), &key.at(1), &key.at(2), &key.at(3));
+ if (ret < 0 || static_cast<size_t>(ret) != key.size()) {
g_outputBuffer = "Invalid value passed to setTCPFastOpenKey()!\n";
return;
}
- extern vector<uint32_t> g_TCPFastOpenKey;
- for (const auto byte : key) {
- g_TCPFastOpenKey.push_back(byte);
- }
+ dnsdist::configuration::updateImmutableConfiguration([&key](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_tcpFastOpenKey = std::move(key);
+ });
});
#ifdef HAVE_NET_SNMP
if (!checkConfigurationTime("snmpAgent")) {
return;
}
- if (g_snmpEnabled) {
- errlog("snmpAgent() cannot be used twice!");
- g_outputBuffer = "snmpAgent() cannot be used twice!\n";
- return;
+
+ {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpEnabled) {
+ errlog("snmpAgent() cannot be used twice!");
+ g_outputBuffer = "snmpAgent() cannot be used twice!\n";
+ return;
+ }
}
- g_snmpEnabled = true;
- g_snmpTrapsEnabled = enableTraps;
+ dnsdist::configuration::updateRuntimeConfiguration([enableTraps](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_snmpEnabled = true;
+ config.d_snmpTrapsEnabled = enableTraps;
+ });
+
g_snmpAgent = std::make_unique<DNSDistSNMPAgent>("dnsdist", daemonSocket ? *daemonSocket : std::string());
});
luaCtx.writeFunction("sendCustomTrap", [](const std::string& str) {
- if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+ if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
g_snmpAgent->sendCustomTrap(str);
}
});
#ifndef DISABLE_POLICIES_BINDINGS
luaCtx.writeFunction("setServerPolicy", [](const std::shared_ptr<ServerPolicy>& policy) {
setLuaSideEffect();
- g_policy.setState(*policy);
+ dnsdist::configuration::updateRuntimeConfiguration([&policy](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = policy;
+ });
});
luaCtx.writeFunction("setServerPolicyLua", [](const string& name, ServerPolicy::policyfunc_t policy) {
setLuaSideEffect();
- g_policy.setState(ServerPolicy{name, std::move(policy), true});
+ auto pol = std::make_shared<ServerPolicy>(name, std::move(policy), true);
+ dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(pol);
+ });
});
luaCtx.writeFunction("setServerPolicyLuaFFI", [](const string& name, ServerPolicy::ffipolicyfunc_t policy) {
setLuaSideEffect();
- auto pol = ServerPolicy(name, std::move(policy));
- g_policy.setState(std::move(pol));
+ auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+ dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(pol);
+ });
});
luaCtx.writeFunction("setServerPolicyLuaFFIPerThread", [](const string& name, const std::string& policyCode) {
setLuaSideEffect();
- auto pol = ServerPolicy(name, policyCode);
- g_policy.setState(std::move(pol));
+ auto policy = std::make_shared<ServerPolicy>(name, policyCode);
+ dnsdist::configuration::updateRuntimeConfiguration([&policy](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(policy);
+ });
});
luaCtx.writeFunction("showServerPolicy", []() {
setLuaSideEffect();
- g_outputBuffer = g_policy.getLocal()->getName() + "\n";
+ g_outputBuffer = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName() + "\n";
});
luaCtx.writeFunction("setPoolServerPolicy", [](const std::shared_ptr<ServerPolicy>& policy, const string& pool) {
setLuaSideEffect();
- auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, policy);
- g_pools.setState(localPools);
+ setPoolPolicy(pool, policy);
});
luaCtx.writeFunction("setPoolServerPolicyLua", [](const string& name, ServerPolicy::policyfunc_t policy, const string& pool) {
setLuaSideEffect();
- auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy), true}));
- g_pools.setState(localPools);
+ setPoolPolicy(pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy), true}));
});
luaCtx.writeFunction("setPoolServerPolicyLuaFFI", [](const string& name, ServerPolicy::ffipolicyfunc_t policy, const string& pool) {
setLuaSideEffect();
- auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy)}));
- g_pools.setState(localPools);
+ setPoolPolicy(pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy)}));
});
luaCtx.writeFunction("setPoolServerPolicyLuaFFIPerThread", [](const string& name, const std::string& policyCode, const std::string& pool) {
setLuaSideEffect();
- auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policyCode}));
- g_pools.setState(localPools);
+ setPoolPolicy(pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policyCode}));
});
luaCtx.writeFunction("showPoolServerPolicy", [](const std::string& pool) {
setLuaSideEffect();
- auto localPools = g_pools.getCopy();
- auto poolObj = getPool(localPools, pool);
+ auto poolObj = getPool(pool);
if (poolObj->policy == nullptr) {
- g_outputBuffer = g_policy.getLocal()->getName() + "\n";
+ g_outputBuffer = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName() + "\n";
}
else {
g_outputBuffer = poolObj->policy->getName() + "\n";
});
#endif /* DISABLE_POLICIES_BINDINGS */
- luaCtx.writeFunction("setTCPDownstreamCleanupInterval", [](uint64_t interval) {
- setLuaSideEffect();
- checkParameterBound("setTCPDownstreamCleanupInterval", interval);
- setTCPDownstreamCleanupInterval(interval);
- });
-
-#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
- luaCtx.writeFunction("setDoHDownstreamCleanupInterval", [](uint64_t interval) {
- setLuaSideEffect();
- checkParameterBound("setDoHDownstreamCleanupInterval", interval);
- setDoHDownstreamCleanupInterval(interval);
- });
-#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-
- luaCtx.writeFunction("setTCPDownstreamMaxIdleTime", [](uint64_t max) {
- setLuaSideEffect();
- checkParameterBound("setTCPDownstreamMaxIdleTime", max);
- setTCPDownstreamMaxIdleTime(max);
- });
-
-#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
- luaCtx.writeFunction("setDoHDownstreamMaxIdleTime", [](uint64_t max) {
- setLuaSideEffect();
- checkParameterBound("setDoHDownstreamMaxIdleTime", max);
- setDoHDownstreamMaxIdleTime(max);
- });
-#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-
- luaCtx.writeFunction("setConsoleConnectionsLogging", [](bool enabled) {
- g_logConsoleConnections = enabled;
- });
-
- luaCtx.writeFunction("setConsoleOutputMaxMsgSize", [](uint64_t size) {
- checkParameterBound("setConsoleOutputMaxMsgSize", size, std::numeric_limits<uint32_t>::max());
- g_consoleOutputMsgMaxSize = size;
- });
-
luaCtx.writeFunction("setProxyProtocolACL", [](LuaTypeOrArrayOf<std::string> inp) {
- if (!checkConfigurationTime("setProxyProtocolACL")) {
- return;
- }
setLuaSideEffect();
NetmaskGroup nmg;
if (auto* str = boost::get<string>(&inp)) {
nmg.addMask(entry.second);
}
}
- g_proxyProtocolACL = std::move(nmg);
- });
-
- luaCtx.writeFunction("setProxyProtocolApplyACLToProxiedClients", [](bool apply) {
- if (!checkConfigurationTime("setProxyProtocolApplyACLToProxiedClients")) {
- return;
- }
- setLuaSideEffect();
- g_applyACLToProxiedClients = apply;
- });
-
- luaCtx.writeFunction("setProxyProtocolMaximumPayloadSize", [](uint64_t size) {
- if (!checkConfigurationTime("setProxyProtocolMaximumPayloadSize")) {
- return;
- }
- setLuaSideEffect();
- g_proxyProtocolMaximumSize = std::max(static_cast<uint64_t>(16), size);
- });
-
-#ifndef DISABLE_RECVMMSG
- luaCtx.writeFunction("setUDPMultipleMessagesVectorSize", [](uint64_t vSize) {
- if (!checkConfigurationTime("setUDPMultipleMessagesVectorSize")) {
- return;
- }
-#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
- setLuaSideEffect();
- g_udpVectorSize = vSize;
-#else
- errlog("recvmmsg() support is not available!");
- g_outputBuffer = "recvmmsg support is not available!\n";
-#endif
- });
-#endif /* DISABLE_RECVMMSG */
-
- luaCtx.writeFunction("setAddEDNSToSelfGeneratedResponses", [](bool add) {
- g_addEDNSToSelfGeneratedResponses = add;
- });
-
- luaCtx.writeFunction("setPayloadSizeOnSelfGeneratedAnswers", [](uint64_t payloadSize) {
- if (payloadSize < 512) {
- warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!");
- g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!";
- payloadSize = 512;
- }
- if (payloadSize > s_udpIncomingBufferSize) {
- warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to %d instead!", s_udpIncomingBufferSize);
- g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to " + std::to_string(s_udpIncomingBufferSize) + " instead";
- payloadSize = s_udpIncomingBufferSize;
- }
- g_PayloadSizeSelfGenAnswers = payloadSize;
+ dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_proxyProtocolACL = std::move(nmg);
+ });
});
#ifndef DISABLE_SECPOLL
setLuaNoSideEffect();
g_outputBuffer = std::to_string(dnsdist::metrics::g_stats.securityStatus) + "\n";
});
-
- luaCtx.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
- if (!checkConfigurationTime("setSecurityPollSuffix")) {
- return;
- }
- g_secPollSuffix = suffix;
- });
-
- luaCtx.writeFunction("setSecurityPollInterval", [](time_t newInterval) {
- if (newInterval <= 0) {
- warnlog("setSecurityPollInterval() should be > 0, skipping");
- g_outputBuffer = "setSecurityPollInterval() should be > 0, skipping";
- }
-
- g_secPollInterval = newInterval;
- });
#endif /* DISABLE_SECPOLL */
luaCtx.writeFunction("setSyslogFacility", [](boost::variant<int, std::string> facility) {
return result;
});
- luaCtx.writeFunction("addDOHLocal", [client](const std::string& addr, boost::optional<boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>> certFiles, boost::optional<boost::variant<std::string, LuaArray<std::string>>> keyFiles, boost::optional<LuaTypeOrArrayOf<std::string>> urls, boost::optional<localbind_t> vars) {
+ luaCtx.writeFunction("addDOHLocal", [client](const std::string& addr, boost::optional<boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>> certFiles, boost::optional<LuaTypeOrArrayOf<std::string>> keyFiles, boost::optional<LuaTypeOrArrayOf<std::string>> urls, boost::optional<localbind_t> vars) {
if (client) {
return;
}
}
}
- g_dohlocals.push_back(frontend);
- auto clientState = std::make_unique<ClientState>(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto clientState = std::make_shared<ClientState>(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
clientState->dohFrontend = std::move(frontend);
clientState->d_additionalAddresses = std::move(additionalAddresses);
if (tcpMaxConcurrentConnections > 0) {
clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
- g_frontends.push_back(std::move(clientState));
+
+ dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends.push_back(std::move(clientState));
+ });
#else /* HAVE_DNS_OVER_HTTPS */
throw std::runtime_error("addDOHLocal() called but DNS over HTTPS support is not present!");
#endif /* HAVE_DNS_OVER_HTTPS */
});
// NOLINTNEXTLINE(performance-unnecessary-value-param): somehow clang-tidy gets confused about the fact vars could be const while it cannot
- luaCtx.writeFunction("addDOH3Local", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles, boost::optional<localbind_t> vars) {
+ luaCtx.writeFunction("addDOH3Local", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const LuaTypeOrArrayOf<std::string>& keyFiles, boost::optional<localbind_t> vars) {
if (client) {
return;
}
checkAllParametersConsumed("addDOH3Local", vars);
}
- g_doh3locals.push_back(frontend);
- auto clientState = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+
+ auto clientState = std::make_shared<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
clientState->doh3Frontend = frontend;
clientState->d_additionalAddresses = std::move(additionalAddresses);
- g_frontends.push_back(std::move(clientState));
+ dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends.push_back(std::move(clientState));
+ });
#else
throw std::runtime_error("addDOH3Local() called but DNS over HTTP/3 support is not present!");
#endif
});
// NOLINTNEXTLINE(performance-unnecessary-value-param): somehow clang-tidy gets confused about the fact vars could be const while it cannot
- luaCtx.writeFunction("addDOQLocal", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles, boost::optional<localbind_t> vars) {
+ luaCtx.writeFunction("addDOQLocal", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const LuaTypeOrArrayOf<std::string>& keyFiles, boost::optional<localbind_t> vars) {
if (client) {
return;
}
checkAllParametersConsumed("addDOQLocal", vars);
}
- g_doqlocals.push_back(frontend);
- auto clientState = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+
+ auto clientState = std::make_shared<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
clientState->doqFrontend = std::move(frontend);
clientState->d_additionalAddresses = std::move(additionalAddresses);
- g_frontends.push_back(std::move(clientState));
+ dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends.push_back(std::move(clientState));
+ });
#else
throw std::runtime_error("addDOQLocal() called but DNS over QUIC support is not present!");
#endif
boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d");
ret << (fmt % "#" % "Address" % "Bad Version" % "Invalid Token" % "Errors" % "Valid") << endl;
size_t counter = 0;
- for (const auto& ctx : g_doqlocals) {
+ for (const auto& ctx : dnsdist::getDoQFrontends()) {
ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_doqUnsupportedVersionErrors % ctx->d_doqInvalidTokensReceived % ctx->d_errorResponses % ctx->d_validResponses) << endl;
counter++;
}
}
setLuaNoSideEffect();
try {
- if (index < g_doqlocals.size()) {
- result = g_doqlocals.at(index);
+ auto doqFrontends = dnsdist::getDoQFrontends();
+ if (index < doqFrontends.size()) {
+ result = doqFrontends.at(index);
}
else {
- errlog("Error: trying to get DOQ frontend with index %d but we only have %d frontend(s)\n", index, g_doqlocals.size());
- g_outputBuffer = "Error: trying to get DOQ frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doqlocals.size()) + " frontend(s)\n";
+ errlog("Error: trying to get DOQ frontend with index %d but we only have %d frontend(s)\n", index, doqFrontends.size());
+ g_outputBuffer = "Error: trying to get DOQ frontend with index " + std::to_string(index) + " but we only have " + std::to_string(doqFrontends.size()) + " frontend(s)\n";
}
}
catch (const std::exception& e) {
luaCtx.writeFunction("getDOQFrontendCount", []() {
setLuaNoSideEffect();
- return g_doqlocals.size();
+ return dnsdist::getDoQFrontends().size();
});
luaCtx.registerFunction<void (std::shared_ptr<DOQFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOQFrontend>& frontend) {
boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "GET" % "POST" % "Bad" % "Errors" % "Redirects" % "Valid" % "# ticket keys" % "Rotation delay" % "Next rotation") << endl;
size_t counter = 0;
- for (const auto& ctx : g_dohlocals) {
+ for (const auto& ctx : dnsdist::getDoHFrontends()) {
ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http2Stats.d_nbQueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_redirectresponses % ctx->d_validresponses % ctx->getTicketsKeysCount() % ctx->getTicketsKeyRotationDelay() % ctx->getNextTicketsKeyRotation()) << endl;
counter++;
}
boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d");
ret << (fmt % "#" % "Address" % "Bad Version" % "Invalid Token" % "Errors" % "Valid") << endl;
size_t counter = 0;
- for (const auto& ctx : g_doh3locals) {
+ for (const auto& ctx : dnsdist::getDoH3Frontends()) {
ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_doh3UnsupportedVersionErrors % ctx->d_doh3InvalidTokensReceived % ctx->d_errorResponses % ctx->d_validResponses) << endl;
counter++;
}
}
setLuaNoSideEffect();
try {
- if (index < g_doh3locals.size()) {
- result = g_doh3locals.at(index);
+ auto doh3Frontends = dnsdist::getDoH3Frontends();
+ if (index < doh3Frontends.size()) {
+ result = doh3Frontends.at(index);
}
else {
- errlog("Error: trying to get DOH3 frontend with index %d but we only have %d frontend(s)\n", index, g_doh3locals.size());
- g_outputBuffer = "Error: trying to get DOH3 frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doh3locals.size()) + " frontend(s)\n";
+ errlog("Error: trying to get DOH3 frontend with index %d but we only have %d frontend(s)\n", index, doh3Frontends.size());
+ g_outputBuffer = "Error: trying to get DOH3 frontend with index " + std::to_string(index) + " but we only have " + std::to_string(doh3Frontends.size()) + " frontend(s)\n";
}
}
catch (const std::exception& e) {
luaCtx.writeFunction("getDOH3FrontendCount", []() {
setLuaNoSideEffect();
- return g_doh3locals.size();
+ return dnsdist::getDoH3Frontends().size();
});
luaCtx.registerFunction<void (std::shared_ptr<DOH3Frontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOH3Frontend>& frontend) {
g_outputBuffer = "\n- HTTP/1:\n\n";
ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others") << endl;
size_t counter = 0;
- for (const auto& ctx : g_dohlocals) {
+ for (const auto& ctx : dnsdist::getDoHFrontends()) {
ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_http1Stats.d_nb200Responses % ctx->d_http1Stats.d_nb400Responses % ctx->d_http1Stats.d_nb403Responses % ctx->d_http1Stats.d_nb500Responses % ctx->d_http1Stats.d_nb502Responses % ctx->d_http1Stats.d_nbOtherResponses) << endl;
counter++;
}
g_outputBuffer += "\n- HTTP/2:\n\n";
ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others") << endl;
counter = 0;
- for (const auto& ctx : g_dohlocals) {
+ for (const auto& ctx : dnsdist::getDoHFrontends()) {
ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_http2Stats.d_nb200Responses % ctx->d_http2Stats.d_nb400Responses % ctx->d_http2Stats.d_nb403Responses % ctx->d_http2Stats.d_nb500Responses % ctx->d_http2Stats.d_nb502Responses % ctx->d_http2Stats.d_nbOtherResponses) << endl;
counter++;
}
#ifdef HAVE_DNS_OVER_HTTPS
setLuaNoSideEffect();
try {
- if (index < g_dohlocals.size()) {
- result = g_dohlocals.at(index);
+ auto dohFrontends = dnsdist::getDoHFrontends();
+ if (index < dohFrontends.size()) {
+ result = dohFrontends.at(index);
}
else {
- errlog("Error: trying to get DOH frontend with index %d but we only have %d frontend(s)\n", index, g_dohlocals.size());
- g_outputBuffer = "Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_dohlocals.size()) + " frontend(s)\n";
+ errlog("Error: trying to get DOH frontend with index %d but we only have %d frontend(s)\n", index, dohFrontends.size());
+ g_outputBuffer = "Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(dohFrontends.size()) + " frontend(s)\n";
}
}
catch (const std::exception& e) {
luaCtx.writeFunction("getDOHFrontendCount", []() {
setLuaNoSideEffect();
- return g_dohlocals.size();
+ return dnsdist::getDoHFrontends().size();
});
luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOHFrontend>& frontend) {
}
});
- luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)(boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, boost::variant<std::string, LuaArray<std::string>> keyFiles)>("loadNewCertificatesAndKeys", [](const std::shared_ptr<DOHFrontend>& frontend, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles) {
+ luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)(boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, LuaTypeOrArrayOf<std::string> keyFiles)>("loadNewCertificatesAndKeys", [](const std::shared_ptr<DOHFrontend>& frontend, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const LuaTypeOrArrayOf<std::string>& keyFiles) {
#ifdef HAVE_DNS_OVER_HTTPS
if (frontend != nullptr) {
if (loadTLSCertificateAndKeys("DOHFrontend::loadNewCertificatesAndKeys", frontend->d_tlsContext.d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
vinfolog("Loading default TLS provider '%s'", provider);
}
// only works pre-startup, so no sync necessary
- auto clientState = std::make_unique<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto clientState = std::make_shared<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
clientState->tlsFrontend = frontend;
clientState->d_additionalAddresses = std::move(additionalAddresses);
if (tcpListenQueueSize > 0) {
clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConns;
}
- g_tlslocals.push_back(clientState->tlsFrontend);
- g_frontends.push_back(std::move(clientState));
+ dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends.push_back(std::move(clientState));
+ });
}
catch (const std::exception& e) {
g_outputBuffer = "Error: " + string(e.what()) + "\n";
// 1 2 3 4 5
ret << (fmt % "#" % "Address" % "# ticket keys" % "Rotation delay" % "Next rotation") << endl;
size_t counter = 0;
- for (const auto& ctx : g_tlslocals) {
+ for (const auto& ctx : dnsdist::getDoTFrontends()) {
ret << (fmt % counter % ctx->d_addr.toStringWithPort() % ctx->getTicketsKeysCount() % ctx->getTicketsKeyRotationDelay() % ctx->getNextTicketsKeyRotation()) << endl;
counter++;
}
std::shared_ptr<TLSCtx> result = nullptr;
#ifdef HAVE_DNS_OVER_TLS
setLuaNoSideEffect();
+ const auto tlsFrontends = dnsdist::getDoTFrontends();
try {
- if (index < g_tlslocals.size()) {
- result = g_tlslocals.at(index)->getContext();
+ if (index < tlsFrontends.size()) {
+ result = tlsFrontends.at(index)->getContext();
}
else {
- errlog("Error: trying to get TLS context with index %d but we only have %d context(s)\n", index, g_tlslocals.size());
- g_outputBuffer = "Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " context(s)\n";
+ errlog("Error: trying to get TLS context with index %d but we only have %d context(s)\n", index, tlsFrontends.size());
+ g_outputBuffer = "Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(tlsFrontends.size()) + " context(s)\n";
}
}
catch (const std::exception& e) {
#ifdef HAVE_DNS_OVER_TLS
setLuaNoSideEffect();
try {
- if (index < g_tlslocals.size()) {
- result = g_tlslocals.at(index);
+ auto tlsFrontends = dnsdist::getDoTFrontends();
+ if (index < tlsFrontends.size()) {
+ result = tlsFrontends.at(index);
}
else {
- errlog("Error: trying to get TLS frontend with index %d but we only have %d frontends\n", index, g_tlslocals.size());
- g_outputBuffer = "Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " frontend(s)\n";
+ errlog("Error: trying to get TLS frontend with index %d but we only have %d frontends\n", index, tlsFrontends.size());
+ g_outputBuffer = "Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(tlsFrontends.size()) + " frontend(s)\n";
}
}
catch (const std::exception& e) {
luaCtx.writeFunction("getTLSFrontendCount", []() {
setLuaNoSideEffect();
- return g_tlslocals.size();
+ return dnsdist::getDoTFrontends().size();
});
luaCtx.registerFunction<void (std::shared_ptr<TLSCtx>::*)()>("rotateTicketsKey", [](std::shared_ptr<TLSCtx>& ctx) {
});
luaCtx.writeFunction("reloadAllCertificates", []() {
- for (auto& frontend : g_frontends) {
+ for (const auto& frontend : dnsdist::getFrontends()) {
if (!frontend) {
continue;
}
}
});
- luaCtx.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse = allow; });
- luaCtx.writeFunction("setDropEmptyQueries", [](bool drop) { extern bool g_dropEmptyQueries; g_dropEmptyQueries = drop; });
-
#if defined(HAVE_LIBSSL) && defined(HAVE_OCSP_BASIC_SIGN) && !defined(DISABLE_OCSP_STAPLING)
luaCtx.writeFunction("generateOCSPResponse", [client](const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) {
if (client) {
#endif /* HAVE_LIBSSL && HAVE_OCSP_BASIC_SIGN && !DISABLE_OCSP_STAPLING */
luaCtx.writeFunction("addCapabilitiesToRetain", [](LuaTypeOrArrayOf<std::string> caps) {
- if (!checkConfigurationTime("addCapabilitiesToRetain")) {
- return;
- }
- setLuaSideEffect();
- if (caps.type() == typeid(std::string)) {
- g_capabilitiesToRetain.insert(boost::get<std::string>(caps));
+ try {
+ dnsdist::configuration::updateImmutableConfiguration([&caps](dnsdist::configuration::ImmutableConfiguration& config) {
+ if (caps.type() == typeid(std::string)) {
+ config.d_capabilitiesToRetain.insert(boost::get<std::string>(caps));
+ }
+ else if (caps.type() == typeid(LuaArray<std::string>)) {
+ for (const auto& cap : boost::get<LuaArray<std::string>>(caps)) {
+ config.d_capabilitiesToRetain.insert(cap.second);
+ }
+ }
+ });
+ setLuaSideEffect();
}
- else if (caps.type() == typeid(LuaArray<std::string>)) {
- for (const auto& cap : boost::get<LuaArray<std::string>>(caps)) {
- g_capabilitiesToRetain.insert(cap.second);
- }
+ catch (const std::exception& exp) {
+ g_outputBuffer = "addCapabilitiesToRetain cannot be used at runtime!\n";
+ errlog("addCapabilitiesToRetain cannot be used at runtime!");
}
});
if (client) {
return;
}
- if (!checkConfigurationTime("setUDPSocketBufferSizes")) {
- return;
- }
checkParameterBound("setUDPSocketBufferSizes", recv, std::numeric_limits<uint32_t>::max());
checkParameterBound("setUDPSocketBufferSizes", snd, std::numeric_limits<uint32_t>::max());
- setLuaSideEffect();
- g_socketUDPSendBuffer = snd;
- g_socketUDPRecvBuffer = recv;
- });
-
- luaCtx.writeFunction("setRandomizedOutgoingSockets", [](bool randomized) {
- DownstreamState::s_randomizeSockets = randomized;
- });
-
- luaCtx.writeFunction("setRandomizedIdsOverUDP", [](bool randomized) {
- DownstreamState::s_randomizeIDs = randomized;
+ try {
+ dnsdist::configuration::updateImmutableConfiguration([snd, recv](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_socketUDPSendBuffer = snd;
+ config.d_socketUDPRecvBuffer = recv;
+ });
+ setLuaSideEffect();
+ }
+ catch (const std::exception& exp) {
+ g_outputBuffer = "setUDPSocketBufferSizes cannot be used at runtime!\n";
+ errlog("setUDPSocketBufferSizes cannot be used at runtime!");
+ }
});
#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
});
}
-vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config)
+void setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config)
{
- // this needs to exist only during the parsing of the configuration
- // and cannot be captured by lambdas
- g_launchWork = std::vector<std::function<void(void)>>();
-
setupLuaActions(luaCtx);
setupLuaConfig(luaCtx, client, configCheck);
setupLuaBindings(luaCtx, client, configCheck);
setupLuaBindingsDNSParser(luaCtx);
setupLuaBindingsDNSQuestion(luaCtx);
setupLuaBindingsKVS(luaCtx, client);
+ setupLuaBindingsLogging(luaCtx);
setupLuaBindingsNetwork(luaCtx, client);
setupLuaBindingsPacketCache(luaCtx, client);
setupLuaBindingsProtoBuf(luaCtx, client, configCheck);
}
luaCtx.executeCode(ifs);
-
- auto ret = *g_launchWork;
- g_launchWork = boost::none;
- return ret;
}
*/
#pragma once
+#include <random>
+
#include "dolog.hh"
#include "dnsdist.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsparser.hh"
-#include <random>
-struct ResponseConfig
-{
- boost::optional<bool> setAA{boost::none};
- boost::optional<bool> setAD{boost::none};
- boost::optional<bool> setRA{boost::none};
- uint32_t ttl{60};
-};
-void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config);
+#include "ext/luawrapper/include/LuaContext.hpp"
+
+extern RecursiveLockGuarded<LuaContext> g_lua;
+extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
class SpoofAction : public DNSAction
{
return ret;
}
- [[nodiscard]] ResponseConfig& getResponseConfig()
+ [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
{
return d_responseConfig;
}
private:
- ResponseConfig d_responseConfig;
+ dnsdist::ResponseConfig d_responseConfig;
static thread_local std::default_random_engine t_randomEngine;
std::vector<ComboAddress> d_addrs;
std::unordered_set<uint16_t> d_types;
using LuaTypeOrArrayOf = boost::variant<T, LuaArray<T>>;
using luaruleparams_t = LuaAssociativeTable<std::string>;
-using nmts_t = NetmaskTree<DynBlock, AddressAndPortRange>;
using luadnsrule_t = boost::variant<string, LuaArray<std::string>, std::shared_ptr<DNSRule>, DNSName, LuaArray<DNSName>>;
std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var, const std::string& calledFrom);
void parseRuleParams(boost::optional<luaruleparams_t>& params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder);
void checkParameterBound(const std::string& parameter, uint64_t value, size_t max = std::numeric_limits<uint16_t>::max());
-vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config);
+void setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config);
void setupLuaActions(LuaContext& luaCtx);
void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck);
void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client);
void setupLuaBindingsDNSParser(LuaContext& luaCtx);
void setupLuaBindingsDNSQuestion(LuaContext& luaCtx);
void setupLuaBindingsKVS(LuaContext& luaCtx, bool client);
+void setupLuaBindingsLogging(LuaContext& luaCtx);
void setupLuaBindingsNetwork(LuaContext& luaCtx, bool client);
void setupLuaBindingsPacketCache(LuaContext& luaCtx, bool client);
void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck);
#include "dnsdist-metrics.hh"
#include "dnsdist.hh"
+#include "dnsdist-dynblocks.hh"
#include "dnsdist-web.hh"
namespace dnsdist::metrics
}
~MutableGauge() = default;
- mutable pdns::stat_t_trait<double> d_value{0};
+ mutable pdns::stat_double_t d_value{0};
};
static SharedLockGuarded<std::map<std::string, MutableCounter, std::less<>>> s_customCounters;
{"cpu-user-msec", getCPUTimeUser},
{"fd-usage", getOpenFileDescriptors},
{"dyn-blocked", &dynBlocked},
- {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }},
+#ifndef DISABLE_DYNBLOCKS
+ {"dyn-block-nmg-size", [](const std::string&) { return dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(); }},
+#endif /* DISABLE_DYNBLOCKS */
{"security-status", &securityStatus},
{"doh-query-pipe-full", &dohQueryPipeFull},
{"doh-response-pipe-full", &dohResponsePipeFull},
if (itp.second) {
g_stats.entries.write_lock()->emplace_back(Stats::EntryPair{name, &(*customCounters)[name].d_value});
dnsdist::prometheus::PrometheusMetricDefinition def{name, type, description, finalCustomName};
- addMetricDefinition(def);
+ dnsdist::webserver::addMetricDefinition(def);
}
}
else if (type == "gauge") {
if (itp.second) {
g_stats.entries.write_lock()->emplace_back(Stats::EntryPair{name, &(*customGauges)[name].d_value});
dnsdist::prometheus::PrometheusMetricDefinition def{name, type, description, finalCustomName};
- addMetricDefinition(def);
+ dnsdist::webserver::addMetricDefinition(def);
}
}
else {
stat_t tcpQueryPipeFull{0};
stat_t tcpCrossProtocolQueryPipeFull{0};
stat_t tcpCrossProtocolResponsePipeFull{0};
- double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
- double latencyTCPAvg100{0}, latencyTCPAvg1000{0}, latencyTCPAvg10000{0}, latencyTCPAvg1000000{0};
- double latencyDoTAvg100{0}, latencyDoTAvg1000{0}, latencyDoTAvg10000{0}, latencyDoTAvg1000000{0};
- double latencyDoHAvg100{0}, latencyDoHAvg1000{0}, latencyDoHAvg10000{0}, latencyDoHAvg1000000{0};
- double latencyDoQAvg100{0}, latencyDoQAvg1000{0}, latencyDoQAvg10000{0}, latencyDoQAvg1000000{0};
- double latencyDoH3Avg100{0}, latencyDoH3Avg1000{0}, latencyDoH3Avg10000{0}, latencyDoH3Avg1000000{0};
+ pdns::stat_double_t latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
+ pdns::stat_double_t latencyTCPAvg100{0}, latencyTCPAvg1000{0}, latencyTCPAvg10000{0}, latencyTCPAvg1000000{0};
+ pdns::stat_double_t latencyDoTAvg100{0}, latencyDoTAvg1000{0}, latencyDoTAvg10000{0}, latencyDoTAvg1000000{0};
+ pdns::stat_double_t latencyDoHAvg100{0}, latencyDoHAvg1000{0}, latencyDoHAvg10000{0}, latencyDoHAvg1000000{0};
+ pdns::stat_double_t latencyDoQAvg100{0}, latencyDoQAvg1000{0}, latencyDoQAvg10000{0}, latencyDoQAvg1000000{0};
+ pdns::stat_double_t latencyDoH3Avg100{0}, latencyDoH3Avg1000{0}, latencyDoH3Avg10000{0}, latencyDoH3Avg1000000{0};
using statfunction_t = std::function<uint64_t(const std::string&)>;
- using entry_t = std::variant<stat_t*, pdns::stat_t_trait<double>*, double*, statfunction_t>;
+ using entry_t = std::variant<stat_t*, pdns::stat_double_t*, statfunction_t>;
struct EntryPair
{
std::string d_name;
gettimeofday(&now, nullptr);
try {
- if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+ if (maxConnectionDurationReached(dnsdist::configuration::getCurrentRuntimeConfiguration().d_maxTCPConnectionDuration, now)) {
vinfolog("Terminating DoH connection from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
stopIO();
d_connectionClosing = true;
}
}
else {
- d_currentPos = 0;
- d_proxyProtocolNeed = 0;
- d_buffer.clear();
d_state = State::waitingForQuery;
handleConnectionReady();
}
processForwardedForHeader(query.d_headers, d_proxiedRemote);
/* second ACL lookup based on the updated address */
- auto& holders = d_threadData.holders;
- if (!holders.acl->match(d_proxiedRemote)) {
+ if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(d_proxiedRemote)) {
++dnsdist::metrics::g_stats.aclDrops;
vinfolog("Query from %s (%s) (DoH) dropped because of ACL", d_ci.remote.toStringWithPort(), d_proxiedRemote.toStringWithPort());
handleImmediateResponse(403, "DoH query not allowed because of ACL");
boost::optional<struct timeval> IncomingHTTP2Connection::getIdleClientReadTTD(struct timeval now) const
{
+ const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
auto idleTimeout = d_ci.cs->dohFrontend->d_idleTimeout;
- if (g_maxTCPConnectionDuration == 0 && idleTimeout == 0) {
+ if (currentConfig.d_maxTCPConnectionDuration == 0 && idleTimeout == 0) {
return boost::none;
}
- if (g_maxTCPConnectionDuration > 0) {
+ if (currentConfig.d_maxTCPConnectionDuration > 0) {
auto elapsed = now.tv_sec - d_connectionStartTime.tv_sec;
- if (elapsed < 0 || (static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration)) {
+ if (elapsed < 0 || (static_cast<size_t>(elapsed) >= currentConfig.d_maxTCPConnectionDuration)) {
return now;
}
- auto remaining = g_maxTCPConnectionDuration - elapsed;
+ auto remaining = currentConfig.d_maxTCPConnectionDuration - elapsed;
if (idleTimeout == 0 || remaining <= static_cast<size_t>(idleTimeout)) {
now.tv_sec += static_cast<time_t>(remaining);
return now;
std::atomic<uint64_t> g_dohStatesDumpRequested{0};
std::unique_ptr<DoHClientCollection> g_dohClientThreads{nullptr};
-std::optional<uint16_t> g_outgoingDoHWorkerThreads{std::nullopt};
#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
class DoHConnectionToBackend : public ConnectionToBackend
errlog("Fatal error in outgoing DoH thread: %s", e.what());
}
}
-
-static bool select_next_proto_callback(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen)
-{
- if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
- vinfolog("The remote DoH backend did not advertise " NGHTTP2_PROTO_VERSION_ID);
- return false;
- }
- return true;
-}
-
#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
struct DoHClientCollection::DoHWorkerThread
{
#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
try {
- auto [sender, receiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+ const auto internalPipeBufferSize = dnsdist::configuration::getImmutableConfiguration().d_tcpInternalPipeBufferSize;
+ auto [sender, receiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
vinfolog("Adding DoH Client thread");
std::lock_guard<std::mutex> lock(d_mutex);
bool initDoHWorkers()
{
#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
- if (!g_outgoingDoHWorkerThreads) {
+ auto outgoingDoHWorkerThreads = dnsdist::configuration::getImmutableConfiguration().d_outgoingDoHWorkers;
+ if (!outgoingDoHWorkerThreads) {
/* Unless the value has been set to 0 explicitly, always start at least one outgoing DoH worker thread, in case a DoH backend
is added at a later time. */
- g_outgoingDoHWorkerThreads = 1;
+ outgoingDoHWorkerThreads = 1;
}
- if (g_outgoingDoHWorkerThreads && *g_outgoingDoHWorkerThreads > 0) {
- g_dohClientThreads = std::make_unique<DoHClientCollection>(*g_outgoingDoHWorkerThreads);
- for (size_t idx = 0; idx < *g_outgoingDoHWorkerThreads; idx++) {
+ if (outgoingDoHWorkerThreads && *outgoingDoHWorkerThreads > 0) {
+ g_dohClientThreads = std::make_unique<DoHClientCollection>(*outgoingDoHWorkerThreads);
+ for (size_t idx = 0; idx < *outgoingDoHWorkerThreads; idx++) {
g_dohClientThreads->addThread();
}
}
#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
-bool setupDoHClientProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
-{
- if (ctx == nullptr) {
- return false;
- }
-#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
- /* we want to set the ALPN to h2, if only to mitigate the ALPACA attack */
- const std::vector<std::vector<uint8_t>> h2Alpns = {{'h', '2'}};
- ctx->setALPNProtos(h2Alpns);
- ctx->setNextProtocolSelectCallback(select_next_proto_callback);
- return true;
-#else /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
- return false;
-#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-}
-
bool sendH2Query(const std::shared_ptr<DownstreamState>& ds, std::unique_ptr<FDMultiplexer>& mplexer, std::shared_ptr<TCPQuerySender>& sender, InternalQuery&& query, bool healthCheck)
{
#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
extern std::unique_ptr<DoHClientCollection> g_dohClientThreads;
extern std::atomic<uint64_t> g_dohStatesDumpRequested;
-extern std::optional<uint16_t> g_outgoingDoHWorkerThreads;
class TLSCtx;
bool initDoHWorkers();
-bool setupDoHClientProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx);
/* opens a new HTTP/2 connection to the supplied backend (attached to the supplied multiplexer), sends the query,
waits for the response to come back or an error to occur then notifies the sender, closing the connection. */
*/
#include "dnsdist-proxy-protocol.hh"
+
+#include "dnsdist.hh"
#include "dnsdist-metrics.hh"
#include "dolog.hh"
-NetmaskGroup g_proxyProtocolACL;
-size_t g_proxyProtocolMaximumSize = 512;
-bool g_applyACLToProxiedClients = false;
-
std::string getProxyProtocolPayload(const DNSQuestion& dq)
{
return makeProxyHeader(dq.overTCP(), dq.ids.origRemote, dq.ids.origDest, dq.proxyProtocolValues ? *dq.proxyProtocolValues : std::vector<ProxyProtocolValue>());
bool expectProxyProtocolFrom(const ComboAddress& remote)
{
- return g_proxyProtocolACL.match(remote);
+ return dnsdist::configuration::getCurrentRuntimeConfiguration().d_proxyProtocolACL.match(remote);
}
bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGroup& acl, PacketBuffer& query, ComboAddress& realRemote, ComboAddress& realDestination, std::vector<ProxyProtocolValue>& values)
vinfolog("Ignoring invalid proxy protocol (%d, %d) query over %s from %s", query.size(), used, (isTCP ? "TCP" : "UDP"), remote.toStringWithPort());
return false;
}
- else if (static_cast<size_t>(used) > g_proxyProtocolMaximumSize) {
+ if (static_cast<size_t>(used) > dnsdist::configuration::getCurrentRuntimeConfiguration().d_proxyProtocolMaximumSize) {
vinfolog("Proxy protocol header in %s packet from %s is larger than proxy-protocol-maximum-size (%d), dropping", (isTCP ? "TCP" : "UDP"), remote.toStringWithPort(), used);
++dnsdist::metrics::g_stats.proxyProtocolInvalid;
return false;
return false;
}
- if (proxyProto && g_applyACLToProxiedClients) {
+ if (proxyProto && dnsdist::configuration::getCurrentRuntimeConfiguration().d_applyACLToProxiedClients) {
if (!acl.match(realRemote)) {
vinfolog("Query from %s dropped because of ACL", realRemote.toStringWithPort());
++dnsdist::metrics::g_stats.aclDrops;
*/
#pragma once
-#include "dnsdist.hh"
+#include <string>
-extern NetmaskGroup g_proxyProtocolACL;
-extern size_t g_proxyProtocolMaximumSize;
-extern bool g_applyACLToProxiedClients;
+#include "iputils.hh"
+#include "noinitvector.hh"
+#include "proxy-protocol.hh"
+
+struct DNSQuestion;
std::string getProxyProtocolPayload(const DNSQuestion& dq);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-query-count.hh"
+
+namespace dnsdist::QueryCount
+{
+SharedLockGuarded<Records> g_queryCountRecords;
+}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/ordered_index.hpp>
-#include <boost/multi_index/key_extractors.hpp>
-#include <boost/multi_index/sequenced_index.hpp>
-#include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
+#pragma once
+
+#include <functional>
+#include <unordered_map>
#include <string>
-#include <sstream>
+#include <tuple>
+
+#include "lock.hh"
+
+struct DNSQuestion;
-#include "namespaces.hh"
-int main()
+namespace dnsdist::QueryCount
{
- ostringstream str;
- str << "Everything is ok!"<<"\n"; // FIXME400: boost test?
- exit(0);
+struct Configuration
+{
+ using Filter = std::function<std::tuple<bool, std::string>(const DNSQuestion* dq)>;
+ Configuration() = default;
+ Filter d_filter;
+ bool d_enabled{false};
+};
+
+using Records = std::unordered_map<std::string, unsigned int>;
+extern SharedLockGuarded<Records> g_queryCountRecords;
}
#include "dnsdist-rings.hh"
-void Rings::setCapacity(size_t newCapacity, size_t numberOfShards)
-{
- if (d_initialized) {
- throw std::runtime_error("Rings::setCapacity() should not be called once the rings have been initialized");
- }
- d_capacity = newCapacity;
- d_numberOfShards = numberOfShards;
-}
-
-void Rings::init()
+void Rings::init(size_t capacity, size_t numberOfShards, size_t nbLockRetries, bool recordQueries, bool recordResponses)
{
if (d_initialized.exchange(true)) {
throw std::runtime_error("Rings::init() should only be called once");
}
+ d_capacity = capacity;
+ d_numberOfShards = numberOfShards;
+ d_nbLockTries = nbLockRetries;
+ d_recordQueries = recordQueries;
+ d_recordResponses = recordResponses;
if (d_numberOfShards <= 1) {
d_nbLockTries = 0;
}
d_nbResponseEntries = 0;
}
-void Rings::setNumberOfLockRetries(size_t retries)
-{
- if (d_numberOfShards <= 1) {
- d_nbLockTries = 0;
- }
- else {
- d_nbLockTries = retries;
- }
-}
-
-void Rings::setRecordQueries(bool record)
-{
- d_recordQueries = record;
-}
-
-void Rings::setRecordResponses(bool record)
-{
- d_recordResponses = record;
-}
-
size_t Rings::numDistinctRequestors()
{
std::set<ComboAddress, ComboAddress::addressOnlyLessThan> requestors;
LockGuarded<boost::circular_buffer<Response>> respRing;
};
- Rings(size_t capacity = 10000, size_t numberOfShards = 10, size_t nbLockTries = 5, bool keepLockingStats = false) :
- d_blockingQueryInserts(0), d_blockingResponseInserts(0), d_deferredQueryInserts(0), d_deferredResponseInserts(0), d_nbQueryEntries(0), d_nbResponseEntries(0), d_currentShardId(0), d_capacity(capacity), d_numberOfShards(numberOfShards), d_nbLockTries(nbLockTries), d_keepLockingStats(keepLockingStats)
- {
- }
-
std::unordered_map<int, vector<boost::variant<string, double>>> getTopBandwidth(unsigned int numentries);
size_t numDistinctRequestors();
- /* this function should not be called after init() has been called */
- void setCapacity(size_t newCapacity, size_t numberOfShards);
/* This function should only be called at configuration time before any query or response has been inserted */
- void init();
-
- void setNumberOfLockRetries(size_t retries);
- void setRecordQueries(bool);
- void setRecordResponses(bool);
+ void init(size_t capacity, size_t numberOfShards, size_t nbLockRetries = 5, bool recordQueries = true, bool recordResponses = true);
size_t getNumberOfShards() const
{
#endif
return;
}
- if (d_keepLockingStats) {
+ if (s_keepLockingStats) {
++d_deferredQueryInserts;
}
}
/* out of luck, let's just wait */
- if (d_keepLockingStats) {
+ if (s_keepLockingStats) {
++d_blockingResponseInserts;
}
auto& shard = getOneShard();
insertResponseLocked(*lock, when, requestor, name, qtype, usec, size, dh, backend, protocol);
return;
}
- if (d_keepLockingStats) {
+ if (s_keepLockingStats) {
++d_deferredResponseInserts;
}
}
/* out of luck, let's just wait */
- if (d_keepLockingStats) {
+ if (s_keepLockingStats) {
++d_blockingResponseInserts;
}
auto& shard = getOneShard();
}
std::vector<std::unique_ptr<Shard>> d_shards;
- pdns::stat_t d_blockingQueryInserts;
- pdns::stat_t d_blockingResponseInserts;
- pdns::stat_t d_deferredQueryInserts;
- pdns::stat_t d_deferredResponseInserts;
+ pdns::stat_t d_blockingQueryInserts{0};
+ pdns::stat_t d_blockingResponseInserts{0};
+ pdns::stat_t d_deferredQueryInserts{0};
+ pdns::stat_t d_deferredResponseInserts{0};
private:
size_t getShardId()
ring.push_back({requestor, backend, name, when, dh, usec, size, qtype, protocol});
}
- std::atomic<size_t> d_nbQueryEntries;
- std::atomic<size_t> d_nbResponseEntries;
- std::atomic<size_t> d_currentShardId;
+ static constexpr bool s_keepLockingStats{false};
+
+ std::atomic<size_t> d_nbQueryEntries{0};
+ std::atomic<size_t> d_nbResponseEntries{0};
+ std::atomic<size_t> d_currentShardId{0};
std::atomic<bool> d_initialized{false};
- size_t d_capacity;
- size_t d_numberOfShards;
- size_t d_nbLockTries = 5;
- bool d_keepLockingStats{false};
+ size_t d_capacity{10000};
+ size_t d_numberOfShards{10};
+ size_t d_nbLockTries{5};
bool d_recordQueries{true};
bool d_recordResponses{true};
};
namespace dnsdist::rules
{
-GlobalStateHolder<std::vector<RuleAction>> s_ruleActions;
-GlobalStateHolder<std::vector<RuleAction>> s_cacheMissRuleActions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_respruleactions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_cachehitrespruleactions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_selfansweredrespruleactions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_cacheInsertedRespRuleActions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_XFRRespRuleActions;
-
static const std::vector<ResponseRuleChainDescription> s_responseRuleChains{
- {"", "response-rules", s_respruleactions},
- {"CacheHit", "cache-hit-response-rules", s_cachehitrespruleactions},
- {"CacheInserted", "cache-inserted-response-rules", s_selfansweredrespruleactions},
- {"SelfAnswered", "self-answered-response-rules", s_cacheInsertedRespRuleActions},
- {"XFR", "xfr-response-rules", s_XFRRespRuleActions},
+ {"", "response-rules", ResponseRuleChain::ResponseRules},
+ {"CacheHit", "cache-hit-response-rules", ResponseRuleChain::CacheHitResponseRules},
+ {"CacheInserted", "cache-inserted-response-rules", ResponseRuleChain::CacheInsertedResponseRules},
+ {"SelfAnswered", "self-answered-response-rules", ResponseRuleChain::SelfAnsweredResponseRules},
+ {"XFR", "xfr-response-rules", ResponseRuleChain::XFRResponseRules},
};
-const std::vector<ResponseRuleChainDescription>& getResponseRuleChains()
+const std::vector<ResponseRuleChainDescription>& getResponseRuleChainDescriptions()
{
return s_responseRuleChains;
}
-GlobalStateHolder<std::vector<ResponseRuleAction>>& getResponseRuleChainHolder(ResponseRuleChain chain)
-{
- return s_responseRuleChains.at(static_cast<size_t>(chain)).holder;
-}
-
static const std::vector<RuleChainDescription> s_ruleChains{
- {"", "rules", s_ruleActions},
- {"CacheMiss", "cache-miss-rules", s_cacheMissRuleActions},
+ {"", "rules", RuleChain::Rules},
+ {"CacheMiss", "cache-miss-rules", RuleChain::CacheMissRules},
};
-const std::vector<RuleChainDescription>& getRuleChains()
+const std::vector<RuleChainDescription>& getRuleChainDescriptions()
{
return s_ruleChains;
}
-GlobalStateHolder<std::vector<RuleAction>>& getRuleChainHolder(RuleChain chain)
+std::vector<RuleAction>& getRuleChain(RuleChains& chains, RuleChain chain)
+{
+ switch (chain) {
+ case RuleChain::Rules:
+ return chains.d_ruleActions;
+ case RuleChain::CacheMissRules:
+ return chains.d_cacheMissRuleActions;
+ }
+
+ throw std::runtime_error("Trying to accept an invalid rule chain");
+}
+
+const std::vector<RuleAction>& getRuleChain(const RuleChains& chains, RuleChain chain)
+{
+ switch (chain) {
+ case RuleChain::Rules:
+ return chains.d_ruleActions;
+ case RuleChain::CacheMissRules:
+ return chains.d_cacheMissRuleActions;
+ }
+
+ throw std::runtime_error("Trying to accept an invalid rule chain");
+}
+
+std::vector<ResponseRuleAction>& getRuleChain(RuleChains& chains, ResponseRuleChain chain)
+{
+ return getResponseRuleChain(chains, chain);
+}
+
+const std::vector<ResponseRuleAction>& getRuleChain(const RuleChains& chains, ResponseRuleChain chain)
{
- return s_ruleChains.at(static_cast<size_t>(chain)).holder;
+ return getResponseRuleChain(chains, chain);
}
+
+std::vector<ResponseRuleAction>& getResponseRuleChain(RuleChains& chains, ResponseRuleChain chain)
+{
+ switch (chain) {
+ case ResponseRuleChain::ResponseRules:
+ return chains.d_respruleactions;
+ case ResponseRuleChain::CacheHitResponseRules:
+ return chains.d_cachehitrespruleactions;
+ case ResponseRuleChain::CacheInsertedResponseRules:
+ return chains.d_cacheInsertedRespRuleActions;
+ case ResponseRuleChain::SelfAnsweredResponseRules:
+ return chains.d_selfansweredrespruleactions;
+ case ResponseRuleChain::XFRResponseRules:
+ return chains.d_XFRRespRuleActions;
+ }
+
+ throw std::runtime_error("Trying to accept an invalid response rule chain");
+}
+
+const std::vector<ResponseRuleAction>& getResponseRuleChain(const RuleChains& chains, ResponseRuleChain chain)
+{
+ switch (chain) {
+ case ResponseRuleChain::ResponseRules:
+ return chains.d_respruleactions;
+ case ResponseRuleChain::CacheHitResponseRules:
+ return chains.d_cachehitrespruleactions;
+ case ResponseRuleChain::CacheInsertedResponseRules:
+ return chains.d_cacheInsertedRespRuleActions;
+ case ResponseRuleChain::SelfAnsweredResponseRules:
+ return chains.d_selfansweredrespruleactions;
+ case ResponseRuleChain::XFRResponseRules:
+ return chains.d_XFRRespRuleActions;
+ }
+
+ throw std::runtime_error("Trying to accept an invalid response rule chain");
+}
+
+void add(RuleChains& chains, RuleChain identifier, const std::shared_ptr<DNSRule>& selector, const std::shared_ptr<DNSAction>& action, std::string&& name, const boost::uuids::uuid& uuid, uint64_t creationOrder)
+{
+ auto& chain = getRuleChain(chains, identifier);
+ chain.push_back({selector, action, std::move(name), uuid, creationOrder});
+}
+
+void add(RuleChains& chains, ResponseRuleChain identifier, const std::shared_ptr<DNSRule>& selector, const std::shared_ptr<DNSResponseAction>& action, std::string&& name, const boost::uuids::uuid& uuid, uint64_t creationOrder)
+{
+ auto& chain = getResponseRuleChain(chains, identifier);
+ chain.push_back({selector, action, std::move(name), uuid, creationOrder});
+}
+
}
#include <string>
#include <vector>
-#include "sholder.hh"
#include "uuid-utils.hh"
class DNSRule;
uint64_t d_creationOrder;
};
-struct RuleChainDescription
-{
- std::string prefix;
- std::string metricName;
- GlobalStateHolder<std::vector<RuleAction>>& holder;
-};
-
enum class RuleChain : uint8_t
{
Rules = 0,
CacheMissRules = 1,
};
-const std::vector<RuleChainDescription>& getRuleChains();
-GlobalStateHolder<std::vector<RuleAction>>& getRuleChainHolder(RuleChain chain);
+struct RuleChainDescription
+{
+ const std::string prefix;
+ const std::string metricName;
+ const RuleChain identifier;
+};
struct ResponseRuleAction
{
struct ResponseRuleChainDescription
{
- std::string prefix;
- std::string metricName;
- GlobalStateHolder<std::vector<ResponseRuleAction>>& holder;
+ const std::string prefix;
+ const std::string metricName;
+ const ResponseRuleChain identifier;
};
-const std::vector<ResponseRuleChainDescription>& getResponseRuleChains();
-GlobalStateHolder<std::vector<ResponseRuleAction>>& getResponseRuleChainHolder(ResponseRuleChain chain);
+struct RuleChains
+{
+ std::vector<RuleAction> d_ruleActions;
+ std::vector<RuleAction> d_cacheMissRuleActions;
+ std::vector<ResponseRuleAction> d_respruleactions;
+ std::vector<ResponseRuleAction> d_cachehitrespruleactions;
+ std::vector<ResponseRuleAction> d_selfansweredrespruleactions;
+ std::vector<ResponseRuleAction> d_cacheInsertedRespRuleActions;
+ std::vector<ResponseRuleAction> d_XFRRespRuleActions;
+};
+const std::vector<RuleChainDescription>& getRuleChainDescriptions();
+std::vector<RuleAction>& getRuleChain(RuleChains& chains, RuleChain chain);
+const std::vector<RuleAction>& getRuleChain(const RuleChains& chains, RuleChain chain);
+const std::vector<ResponseRuleChainDescription>& getResponseRuleChainDescriptions();
+std::vector<ResponseRuleAction>& getRuleChain(RuleChains& chains, ResponseRuleChain chain);
+const std::vector<ResponseRuleAction>& getRuleChain(const RuleChains& chains, ResponseRuleChain chain);
+std::vector<ResponseRuleAction>& getResponseRuleChain(RuleChains& chains, ResponseRuleChain chain);
+const std::vector<ResponseRuleAction>& getResponseRuleChain(const RuleChains& chains, ResponseRuleChain chain);
+void add(RuleChains& chains, RuleChain identifier, const std::shared_ptr<DNSRule>& selector, const std::shared_ptr<DNSAction>& action, std::string&& name, const boost::uuids::uuid& uuid, uint64_t creationOrder);
+void add(RuleChains& chains, ResponseRuleChain identifier, const std::shared_ptr<DNSRule>& selector, const std::shared_ptr<DNSResponseAction>& action, std::string&& name, const boost::uuids::uuid& uuid, uint64_t creationOrder);
}
#include "dnsdist.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-kvs.hh"
+#include "dnsdist-lua.hh"
#include "dnsdist-lua-ffi.hh"
#include "dolog.hh"
#include "dnsparser.hh"
}
bool matches(const DNSQuestion* dq) const override
{
- return dq->getHeader()->cd || (getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO); // turns out dig sets ad by default..
+ return dq->getHeader()->cd || (dnsdist::getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO); // turns out dig sets ad by default..
}
string toString() const override
class PoolAvailableRule : public DNSRule
{
public:
- PoolAvailableRule(const std::string& poolname) : d_pools(&g_pools), d_poolname(poolname)
+ PoolAvailableRule(const std::string& poolname) : d_poolname(poolname)
{
}
bool matches(const DNSQuestion* dq) const override
{
- return (getPool(*d_pools, d_poolname)->countServers(true) > 0);
+ return (getPool(d_poolname)->countServers(true) > 0);
}
string toString() const override
return "pool '" + d_poolname + "' is available";
}
private:
- mutable LocalStateHolder<pools_t> d_pools;
std::string d_poolname;
};
class PoolOutstandingRule : public DNSRule
{
public:
- PoolOutstandingRule(const std::string& poolname, const size_t limit) : d_pools(&g_pools), d_poolname(poolname), d_limit(limit)
+ PoolOutstandingRule(const std::string& poolname, const size_t limit) : d_poolname(poolname), d_limit(limit)
{
}
bool matches(const DNSQuestion* dq) const override
{
- return (getPool(*d_pools, d_poolname)->poolLoad()) > d_limit;
+ return (getPool(d_poolname)->poolLoad()) > d_limit;
}
string toString() const override
return "pool '" + d_poolname + "' outstanding > " + std::to_string(d_limit);
}
private:
- mutable LocalStateHolder<pools_t> d_pools;
std::string d_poolname;
size_t d_limit;
};
static std::string getSecPollStatus(const std::string& queriedName, int timeout=2)
{
+ const auto verbose = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+
const DNSName sentName(queriedName);
std::vector<uint8_t> packet;
DNSPacketWriter pw(packet, sentName, QType::TXT);
string reply;
int ret = waitForData(sock.getHandle(), timeout, 0);
if (ret < 0) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Error while waiting for the secpoll response from stub resolver %s: %d", dest.toString(), ret);
}
continue;
}
else if (ret == 0) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Timeout while waiting for the secpoll response from stub resolver %s", dest.toString());
}
continue;
sock.read(reply);
}
catch(const std::exception& e) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Error while reading for the secpoll response from stub resolver %s: %s", dest.toString(), e.what());
}
continue;
}
if (reply.size() <= sizeof(struct dnsheader)) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Too short answer of size %d received from the secpoll stub resolver %s", reply.size(), dest.toString());
}
continue;
struct dnsheader d;
memcpy(&d, reply.c_str(), sizeof(d));
if (d.id != pw.getHeader()->id) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Invalid ID (%d / %d) received from the secpoll stub resolver %s", d.id, pw.getHeader()->id, dest.toString());
}
continue;
}
if (d.rcode != RCode::NoError) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Response code '%s' received from the secpoll stub resolver %s for '%s'", RCode::to_s(d.rcode), dest.toString(), queriedName);
}
}
if (ntohs(d.qdcount) != 1 || ntohs(d.ancount) != 1) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Invalid answer (qdcount %d / ancount %d) received from the secpoll stub resolver %s", ntohs(d.qdcount), ntohs(d.ancount), dest.toString());
}
continue;
DNSName receivedName(reply.c_str(), reply.size(), sizeof(dnsheader), false, &receivedType, &receivedClass);
if (receivedName != sentName || receivedType != QType::TXT || receivedClass != QClass::IN) {
- if (g_verbose) {
+ if (verbose) {
warnlog("Invalid answer, either the qname (%s / %s), qtype (%s / %s) or qclass (%s / %s) does not match, received from the secpoll stub resolver %s", receivedName, sentName, QType(receivedType).toString(), QType(QType::TXT).toString(), QClass(receivedClass).toString(), QClass::IN.toString(), dest.toString());
}
continue;
throw std::runtime_error("Unable to get a valid Security Status update");
}
-static bool g_secPollDone{false};
-std::string g_secPollSuffix{"secpoll.powerdns.com."};
-time_t g_secPollInterval{3600};
-
+namespace dnsdist::secpoll
+{
void doSecPoll(const std::string& suffix)
{
+ static bool s_secPollDone{false};
+
if (suffix.empty()) {
return;
}
int securityStatus = std::stoi(split.first);
std::string securityMessage = split.second;
- if (securityStatus == 1 && !g_secPollDone) {
+ if (securityStatus == 1 && !s_secPollDone) {
infolog("Polled security status of version %s at startup, no known issues reported: %s", std::string(VERSION), securityMessage);
}
if (securityStatus == 2) {
}
dnsdist::metrics::g_stats.securityStatus = securityStatus;
- g_secPollDone = true;
+ s_secPollDone = true;
return;
}
catch (const std::exception& e) {
if (releaseVersion) {
warnlog("Error while retrieving the security update for version %s: %s", version, e.what());
}
- else if (!g_secPollDone) {
+ else if (!s_secPollDone) {
infolog("Error while retrieving the security update for version %s: %s", version, e.what());
}
}
if (releaseVersion) {
warnlog("Failed to retrieve security status update for '%s' on %s", pkgv, queriedName);
}
- else if (!g_secPollDone) {
+ else if (!s_secPollDone) {
infolog("Not validating response for security status update, this is a non-release version.");
/* for non-released versions, there is no use sending the same message several times,
let's just accept that there will be no security polling for this exact version */
- g_secPollDone = true;
+ s_secPollDone = true;
}
}
+}
#endif /* DISABLE_SECPOLL */
#ifndef DISABLE_SECPOLL
#include <string>
-#include <ctime>
-
-extern std::string g_secPollSuffix;
-extern time_t g_secPollInterval;
+namespace dnsdist::secpoll
+{
void doSecPoll(const std::string& suffix);
+}
#endif /* DISABLE_SECPOLL */
*/
#include "dnsdist-session-cache.hh"
-TLSSessionCache g_sessionCache;
+#include "dnsdist-configuration.hh"
-time_t TLSSessionCache::s_cleanupDelay{60};
-time_t TLSSessionCache::s_sessionValidity{600};
-uint16_t TLSSessionCache::s_maxSessionsPerBackend{20};
+TLSSessionCache g_sessionCache;
void TLSSessionCache::cleanup(time_t now, LockGuardedHolder<TLSSessionCache::CacheData>& data)
{
- time_t cutOff = now + s_sessionValidity;
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ time_t cutOff = now + runtimeConfig.d_tlsSessionCacheSessionValidity;
for (auto it = data->d_sessions.begin(); it != data->d_sessions.end();) {
if (it->second.d_lastUsed > cutOff || it->second.d_sessions.size() == 0) {
}
}
- data->d_nextCleanup = now + s_cleanupDelay;
+ data->d_nextCleanup = now + runtimeConfig.d_tlsSessionCacheCleanupDelay;
}
void TLSSessionCache::putSessions(const boost::uuids::uuid& backendID, time_t now, std::vector<std::unique_ptr<TLSSession>>&& sessions)
cleanup(now, data);
}
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
for (auto& session : sessions) {
auto& entry = data->d_sessions[backendID];
- if (entry.d_sessions.size() >= s_maxSessionsPerBackend) {
+ if (entry.d_sessions.size() >= runtimeConfig.d_tlsSessionCacheMaxSessionsPerBackend) {
entry.d_sessions.pop_back();
}
entry.d_sessions.push_front(std::move(session));
void putSessions(const boost::uuids::uuid& backendID, time_t now, std::vector<std::unique_ptr<TLSSession>>&& sessions);
std::unique_ptr<TLSSession> getSession(const boost::uuids::uuid& backendID, time_t now);
- static void setCleanupDelay(time_t delay)
- {
- s_cleanupDelay = delay;
- }
-
- static void setSessionValidity(time_t validity)
- {
- s_sessionValidity = validity;
- }
-
- static void setMaxTicketsPerBackend(uint16_t max)
- {
- s_maxSessionsPerBackend = max;
- }
-
size_t getSize();
private:
- static time_t s_cleanupDelay;
- static time_t s_sessionValidity;
- static uint16_t s_maxSessionsPerBackend;
-
struct BackendEntry
{
std::deque<std::unique_ptr<TLSSession>> d_sessions;
#include "dnsdist-snmp.hh"
+#include "dnsdist-dynblocks.hh"
#include "dnsdist-metrics.hh"
#include "dolog.hh"
-bool g_snmpEnabled{false};
-bool g_snmpTrapsEnabled{false};
std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent{nullptr};
#ifdef HAVE_NET_SNMP
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/definitions.h>
+#include <net-snmp/types.h>
+#include <net-snmp/utilities.h>
+#include <net-snmp/config_api.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#undef INET6 /* SRSLY? */
+
#define DNSDIST_OID 1, 3, 6, 1, 4, 1, 43315, 3
#define DNSDIST_STATS_OID DNSDIST_OID, 1
#define DNSDIST_STATS_TABLE_OID DNSDIST_OID, 2
return SNMP_ERR_GENERR;
}
- if (const auto& val = std::get_if<double*>(&stIt->second)) {
- std::string str(std::to_string(**val));
+ if (const auto& val = std::get_if<pdns::stat_double_t*>(&stIt->second)) {
+ std::string str(std::to_string((*val)->load()));
snmp_set_var_typed_value(requests->requestvb,
ASN_OCTET_STR,
str.c_str(),
return SNMP_ERR_GENERR;
}
-static void registerFloatStat(const char* name, const OIDStat& statOID, double* ptr)
+static void registerFloatStat(const char* name, const OIDStat& statOID, pdns::stat_double_t* ptr)
{
if (statOID.size() != OID_LENGTH(queriesOID)) {
errlog("Invalid OID for SNMP Float statistic %s", name);
/* get a copy of the shared_ptrs so they are not
destroyed while we process the request */
- auto dstates = g_dstates.getLocal();
+ auto backends = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
s_servers.clear();
- s_servers.reserve(dstates->size());
- for (const auto& server : *dstates) {
- s_servers.push_back(server);
+ s_servers.reserve(backends.size());
+ for (auto& server : backends) {
+ s_servers.push_back(std::move(server));
}
return backendStatTable_get_next_data_point(loop_context,
const string backendStatus = dss.getStatus();
netsnmp_variable_list* varList = nullptr;
- snmp_varlist_add_variable(&varList,
- snmpTrapOID.data(),
- snmpTrapOID.size(),
- ASN_OBJECT_ID,
- backendStatusChangeTrapOID.data(),
- backendStatusChangeTrapOID.size() * sizeof(oid));
+ addSNMPTrapOID(&varList,
+ backendStatusChangeTrapOID.data(),
+ backendStatusChangeTrapOID.size() * sizeof(oid));
snmp_varlist_add_variable(&varList,
backendNameOID.data(),
#ifdef HAVE_NET_SNMP
netsnmp_variable_list* varList = nullptr;
- snmp_varlist_add_variable(&varList,
- snmpTrapOID.data(),
- snmpTrapOID.size(),
- ASN_OBJECT_ID,
- customTrapOID.data(),
- customTrapOID.size() * sizeof(oid));
+ addSNMPTrapOID(&varList,
+ customTrapOID.data(),
+ customTrapOID.size() * sizeof(oid));
snmp_varlist_add_variable(&varList,
trapReasonOID.data(),
netsnmp_variable_list* varList = nullptr;
- snmp_varlist_add_variable(&varList,
- snmpTrapOID.data(),
- snmpTrapOID.size(),
- ASN_OBJECT_ID,
- actionTrapOID.data(),
- actionTrapOID.size() * sizeof(oid));
+ addSNMPTrapOID(&varList,
+ actionTrapOID.data(),
+ actionTrapOID.size() * sizeof(oid));
snmp_varlist_add_variable(&varList,
socketFamilyOID.data(),
registerGauge64Stat("cpuUserMSec", cpuUserMSecOID, &getCPUTimeUser);
registerGauge64Stat("cpuSysMSec", cpuSysMSecOID, &getCPUTimeSystem);
registerGauge64Stat("fdUsage", fdUsageOID, &getOpenFileDescriptors);
- registerGauge64Stat("dynBlockedNMGSize", dynBlockedNMGSizeOID, [](const std::string&) { return g_dynblockNMG.getLocal()->size(); });
+ registerGauge64Stat("dynBlockedNMGSize", dynBlockedNMGSizeOID, [](const std::string&) { return dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(); });
registerGauge64Stat("securityStatus", securityStatusOID, [](const std::string&) { return dnsdist::metrics::g_stats.securityStatus.load(); });
registerGauge64Stat("realMemoryUsage", realMemoryUsageOID, &getRealMemoryUsage);
bool sendCustomTrap(const std::string& reason);
bool sendDNSTrap(const DNSQuestion&, const std::string& reason = "");
};
+
+extern std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent;
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "dnsdist-svc.hh"
+#include "dnsdist.hh"
+#include "dnsdist-ecs.hh"
+#include "dnsdist-lua.hh"
#include "dnswriter.hh"
#include "svc-records.hh"
}
return parameters;
}
+
+namespace dnsdist::svc
+{
+bool generateSVCResponse(DNSQuestion& dnsQuestion, const std::vector<std::vector<uint8_t>>& svcRecordPayloads, const std::set<std::pair<DNSName, ComboAddress>>& additionals4, const std::set<std::pair<DNSName, ComboAddress>>& additionals6, const ResponseConfig& responseConfig)
+{
+ /* it will likely be a bit bigger than that because of additionals */
+ size_t totalPayloadsSize = 0;
+ for (const auto& payload : svcRecordPayloads) {
+ totalPayloadsSize += payload.size();
+ }
+ const auto numberOfRecords = svcRecordPayloads.size();
+ const auto qnameWireLength = dnsQuestion.ids.qname.wirelength();
+ if (dnsQuestion.getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totalPayloadsSize)) {
+ return false;
+ }
+
+ PacketBuffer newPacket;
+ newPacket.reserve(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totalPayloadsSize);
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(newPacket, dnsQuestion.ids.qname, dnsQuestion.ids.qtype);
+ for (const auto& payload : svcRecordPayloads) {
+ packetWriter.startRecord(dnsQuestion.ids.qname, dnsQuestion.ids.qtype, responseConfig.ttl);
+ packetWriter.xfrBlob(payload);
+ packetWriter.commit();
+ }
+
+ if (newPacket.size() < dnsQuestion.getMaximumSize()) {
+ for (const auto& additional : additionals4) {
+ packetWriter.startRecord(additional.first.isRoot() ? dnsQuestion.ids.qname : additional.first, QType::A, responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ packetWriter.xfrCAWithoutPort(4, additional.second);
+ packetWriter.commit();
+ }
+ }
+
+ if (newPacket.size() < dnsQuestion.getMaximumSize()) {
+ for (const auto& additional : additionals6) {
+ packetWriter.startRecord(additional.first.isRoot() ? dnsQuestion.ids.qname : additional.first, QType::AAAA, responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ packetWriter.xfrCAWithoutPort(6, additional.second);
+ packetWriter.commit();
+ }
+ }
+
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (runtimeConfig.d_addEDNSToSelfGeneratedResponses && queryHasEDNS(dnsQuestion)) {
+ bool dnssecOK = ((dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0);
+ packetWriter.addOpt(runtimeConfig.d_payloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0);
+ packetWriter.commit();
+ }
+
+ if (newPacket.size() >= dnsQuestion.getMaximumSize()) {
+ /* sorry! */
+ return false;
+ }
+
+ packetWriter.getHeader()->id = dnsQuestion.getHeader()->id;
+ packetWriter.getHeader()->qr = true; // for good measure
+ setResponseHeadersFromConfig(*packetWriter.getHeader(), responseConfig);
+ dnsQuestion.getMutableData() = std::move(newPacket);
+
+ return true;
+}
+
+bool generateSVCResponse(DNSQuestion& dnsQuestion, uint32_t ttl, const std::vector<SVCRecordParameters>& parameters)
+{
+ std::vector<std::vector<uint8_t>> payloads;
+ std::set<std::pair<DNSName, ComboAddress>> additionals4;
+ std::set<std::pair<DNSName, ComboAddress>> additionals6;
+ ResponseConfig responseConfig;
+ responseConfig.setAA = true;
+ responseConfig.ttl = ttl;
+
+ payloads.reserve(parameters.size());
+ for (const auto& parameter : parameters) {
+ std::vector<uint8_t> payload;
+ if (!generateSVCPayload(payload, parameter)) {
+ throw std::runtime_error("Unable to generate a valid SVC record from the supplied parameters");
+ }
+
+ payloads.push_back(std::move(payload));
+
+ for (const auto& hint : parameter.ipv4hints) {
+ additionals4.insert({parameter.target, ComboAddress(hint)});
+ }
+
+ for (const auto& hint : parameter.ipv6hints) {
+ additionals6.insert({parameter.target, ComboAddress(hint)});
+ }
+ }
+
+ return generateSVCResponse(dnsQuestion, payloads, additionals4, additionals6, responseConfig);
+}
+}
bool noDefaultAlpn{false};
};
-typedef std::unordered_map<
+using svcParamsLua_t = std::unordered_map<
std::string,
boost::variant<
uint16_t,
bool,
std::string,
std::vector<std::pair<int, std::string>>,
- std::vector<std::pair<int, ComboAddress>>>>
- svcParamsLua_t;
+ std::vector<std::pair<int, ComboAddress>>>>;
struct SVCRecordParameters parseSVCParameters(const svcParamsLua_t& params);
bool generateSVCPayload(std::vector<uint8_t>& payload, uint16_t priority, const DNSName& target, const std::set<uint16_t>& mandatoryParams, const std::vector<std::string>& alpns, bool noDefaultAlpn, std::optional<uint16_t> port, const std::string& ech, const std::vector<ComboAddress>& ipv4hints, const std::vector<ComboAddress>& ipv6hints, const std::vector<std::pair<uint16_t, std::string>>& additionalParams);
bool generateSVCPayload(std::vector<uint8_t>& payload, const SVCRecordParameters& parameters);
+
+struct DNSQuestion;
+namespace dnsdist
+{
+struct ResponseConfig;
+}
+
+namespace dnsdist::svc
+{
+bool generateSVCResponse(DNSQuestion& dnsQuestion, const std::vector<std::vector<uint8_t>>& svcRecordPayloads, const std::set<std::pair<DNSName, ComboAddress>>& additionals4, const std::set<std::pair<DNSName, ComboAddress>>& additionals6, const dnsdist::ResponseConfig& d_responseConfig);
+bool generateSVCResponse(DNSQuestion& dnsQuestion, uint32_t ttl, const std::vector<SVCRecordParameters>& parameters);
+}
MOADNSParser parser(true, reinterpret_cast<const char*>(query.d_buffer.data() + sizeof(uint16_t) + proxyPayloadSize), payloadSize);
for (const auto& record : parser.d_answers) {
- if (record.first.d_place != DNSResourceRecord::AUTHORITY || record.first.d_class != QClass::IN || record.first.d_type != QType::SOA) {
+ if (record.d_place != DNSResourceRecord::AUTHORITY || record.d_class != QClass::IN || record.d_type != QType::SOA) {
return false;
}
- auto unknownContent = getRR<UnknownRecordContent>(record.first);
+ auto unknownContent = getRR<UnknownRecordContent>(record);
if (!unknownContent) {
return false;
}
}
else {
for (const auto& record : parser.d_answers) {
- if (record.first.d_class != QClass::IN || record.first.d_type != QType::SOA) {
+ if (record.d_class != QClass::IN || record.d_type != QType::SOA) {
continue;
}
- auto unknownContent = getRR<UnknownRecordContent>(record.first);
+ auto unknownContent = getRR<UnknownRecordContent>(record);
if (!unknownContent) {
continue;
}
{
public:
TCPClientThreadData():
- localRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal()), localCacheInsertedRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal()), localXFRRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::XFRResponseRules).getLocal()), mplexer(std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent()))
+ mplexer(std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent()))
{
}
- LocalHolders holders;
- LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions;
- LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions;
- LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localXFRRespRuleActions;
std::unique_ptr<FDMultiplexer> mplexer{nullptr};
pdns::channel::Receiver<ConnectionInfo> queryReceiver;
pdns::channel::Receiver<CrossProtocolQuery> crossProtocolQueryReceiver;
enum class QueryProcessingResult : uint8_t { Forwarded, TooSmall, InvalidHeaders, Dropped, SelfAnswered, NoBackend, Asynchronous };
enum class ProxyProtocolResult : uint8_t { Reading, Done, Error };
- IncomingTCPConnectionState(ConnectionInfo&& ci, TCPClientThreadData& threadData, const struct timeval& now): d_buffer(sizeof(uint16_t)), d_ci(std::move(ci)), d_handler(d_ci.fd, timeval{g_tcpRecvTimeout,0}, d_ci.cs->tlsFrontend ? d_ci.cs->tlsFrontend->getContext() : (d_ci.cs->dohFrontend ? d_ci.cs->dohFrontend->d_tlsContext.getContext() : nullptr), now.tv_sec), d_connectionStartTime(now), d_ioState(make_unique<IOStateHandler>(*threadData.mplexer, d_ci.fd)), d_threadData(threadData), d_creatorThreadID(std::this_thread::get_id())
+ IncomingTCPConnectionState(ConnectionInfo&& ci, TCPClientThreadData& threadData, const struct timeval& now): d_buffer(sizeof(uint16_t)), d_ci(std::move(ci)), d_handler(d_ci.fd, timeval{dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout,0}, d_ci.cs->tlsFrontend ? d_ci.cs->tlsFrontend->getContext() : (d_ci.cs->dohFrontend ? d_ci.cs->dohFrontend->d_tlsContext.getContext() : nullptr), now.tv_sec), d_connectionStartTime(now), d_ioState(make_unique<IOStateHandler>(*threadData.mplexer, d_ci.fd)), d_threadData(threadData), d_creatorThreadID(std::this_thread::get_id())
{
d_origDest.reset();
d_origDest.sin4.sin_family = d_ci.remote.sin4.sin_family;
boost::optional<struct timeval> getClientReadTTD(struct timeval now) const
{
- if (g_maxTCPConnectionDuration == 0 && g_tcpRecvTimeout == 0) {
+ const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (runtimeConfiguration.d_maxTCPConnectionDuration == 0 && runtimeConfiguration.d_tcpRecvTimeout == 0) {
return boost::none;
}
- if (g_maxTCPConnectionDuration > 0) {
+ if (runtimeConfiguration.d_maxTCPConnectionDuration > 0) {
auto elapsed = now.tv_sec - d_connectionStartTime.tv_sec;
- if (elapsed < 0 || (static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration)) {
+ if (elapsed < 0 || (static_cast<size_t>(elapsed) >= runtimeConfiguration.d_maxTCPConnectionDuration)) {
return now;
}
- auto remaining = g_maxTCPConnectionDuration - elapsed;
- if (g_tcpRecvTimeout == 0 || remaining <= static_cast<size_t>(g_tcpRecvTimeout)) {
+ auto remaining = runtimeConfiguration.d_maxTCPConnectionDuration - elapsed;
+ if (runtimeConfiguration.d_tcpRecvTimeout == 0 || remaining <= static_cast<size_t>(runtimeConfiguration.d_tcpRecvTimeout)) {
now.tv_sec += remaining;
return now;
}
}
- now.tv_sec += g_tcpRecvTimeout;
+ now.tv_sec += runtimeConfiguration.d_tcpRecvTimeout;
return now;
}
boost::optional<struct timeval> getClientWriteTTD(const struct timeval& now) const
{
- if (g_maxTCPConnectionDuration == 0 && g_tcpSendTimeout == 0) {
+ const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (runtimeConfiguration.d_maxTCPConnectionDuration == 0 && runtimeConfiguration.d_tcpSendTimeout == 0) {
return boost::none;
}
- struct timeval res = now;
+ timeval res(now);
- if (g_maxTCPConnectionDuration > 0) {
+ if (runtimeConfiguration.d_maxTCPConnectionDuration > 0) {
auto elapsed = res.tv_sec - d_connectionStartTime.tv_sec;
- if (elapsed < 0 || static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration) {
+ if (elapsed < 0 || static_cast<size_t>(elapsed) >= runtimeConfiguration.d_maxTCPConnectionDuration) {
return res;
}
- auto remaining = g_maxTCPConnectionDuration - elapsed;
- if (g_tcpSendTimeout == 0 || remaining <= static_cast<size_t>(g_tcpSendTimeout)) {
+ auto remaining = runtimeConfiguration.d_maxTCPConnectionDuration - elapsed;
+ if (runtimeConfiguration.d_tcpSendTimeout == 0 || remaining <= static_cast<size_t>(runtimeConfiguration.d_tcpSendTimeout)) {
res.tv_sec += remaining;
return res;
}
}
- res.tv_sec += g_tcpSendTimeout;
+ res.tv_sec += runtimeConfiguration.d_tcpSendTimeout;
return res;
}
#include <thread>
#include <netinet/tcp.h>
#include <queue>
+#include <boost/format.hpp>
#include "dnsdist.hh"
#include "dnsdist-concurrent-connections.hh"
Let's start naively.
*/
-size_t g_maxTCPQueriesPerConn{0};
-size_t g_maxTCPConnectionDuration{0};
-
-#ifdef __linux__
-// On Linux this gives us 128k pending queries (default is 8192 queries),
-// which should be enough to deal with huge spikes
-size_t g_tcpInternalPipeBufferSize{1048576U};
-uint64_t g_maxTCPQueuedConnections{10000};
-#else
-size_t g_tcpInternalPipeBufferSize{0};
-uint64_t g_maxTCPQueuedConnections{1000};
-#endif
-
-int g_tcpRecvTimeout{2};
-int g_tcpSendTimeout{2};
std::atomic<uint64_t> g_tcpStatesDumpRequested{0};
LockGuarded<std::map<ComboAddress, size_t, ComboAddress::addressOnlyLessThan>> dnsdist::IncomingConcurrentTCPConnectionsManager::s_tcpClientsConcurrentConnectionsCount;
-size_t dnsdist::IncomingConcurrentTCPConnectionsManager::s_maxTCPConnectionsPerClient = 0;
IncomingTCPConnectionState::~IncomingTCPConnectionState()
{
void TCPClientCollection::addTCPClientThread(std::vector<ClientState*>& tcpAcceptStates)
{
try {
- auto [queryChannelSender, queryChannelReceiver] = pdns::channel::createObjectQueue<ConnectionInfo>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+ const auto internalPipeBufferSize = dnsdist::configuration::getImmutableConfiguration().d_tcpInternalPipeBufferSize;
- auto [crossProtocolQueryChannelSender, crossProtocolQueryChannelReceiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+ auto [queryChannelSender, queryChannelReceiver] = pdns::channel::createObjectQueue<ConnectionInfo>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
- auto [crossProtocolResponseChannelSender, crossProtocolResponseChannelReceiver] = pdns::channel::createObjectQueue<TCPCrossProtocolResponse>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+ auto [crossProtocolQueryChannelSender, crossProtocolQueryChannelReceiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
+
+ auto [crossProtocolResponseChannelSender, crossProtocolResponseChannelReceiver] = pdns::channel::createObjectQueue<TCPCrossProtocolResponse>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
vinfolog("Adding TCP Client thread");
++d_numthreads;
}
catch (const std::exception& e) {
- errlog("Error creating TCP worker: %", e.what());
+ errlog("Error creating TCP worker: %s", e.what());
}
}
return false;
}
- if (g_maxTCPQueriesPerConn != 0 && d_queriesCount > g_maxTCPQueriesPerConn) {
- vinfolog("not accepting new queries from %s because it reached the maximum number of queries per conn (%d / %d)", d_ci.remote.toStringWithPort(), d_queriesCount, g_maxTCPQueriesPerConn);
+ const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (currentConfig.d_maxTCPQueriesPerConn != 0 && d_queriesCount > currentConfig.d_maxTCPQueriesPerConn) {
+ vinfolog("not accepting new queries from %s because it reached the maximum number of queries per conn (%d / %d)", d_ci.remote.toStringWithPort(), d_queriesCount, currentConfig.d_maxTCPQueriesPerConn);
return false;
}
- if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+ if (maxConnectionDurationReached(currentConfig.d_maxTCPConnectionDuration, now)) {
vinfolog("not accepting new queries from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
return false;
}
try {
auto& ids = response.d_idstate;
std::shared_ptr<DownstreamState> backend = response.d_ds ? response.d_ds : (response.d_connection ? response.d_connection->getDS() : nullptr);
- if (backend == nullptr || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, backend)) {
+ if (backend == nullptr || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, backend, dnsdist::configuration::getCurrentRuntimeConfiguration().d_allowEmptyResponse)) {
state->terminateClientConnection();
return;
}
memcpy(&response.d_cleartextDH, dnsResponse.getHeader().get(), sizeof(response.d_cleartextDH));
- if (!processResponse(response.d_buffer, *state->d_threadData.localRespRuleActions, *state->d_threadData.localCacheInsertedRespRuleActions, dnsResponse, false)) {
+ if (!processResponse(response.d_buffer, dnsResponse, false)) {
state->terminateClientConnection();
return;
}
}
std::shared_ptr<DownstreamState> backend;
- auto result = processQuery(dnsQuestion, d_threadData.holders, backend);
+ auto result = processQuery(dnsQuestion, backend);
if (result == ProcessQueryResult::Asynchronous) {
/* we are done for now */
else {
/* proxy header received */
std::vector<ProxyProtocolValue> proxyProtocolValues;
- if (!handleProxyProtocol(d_ci.remote, true, *d_threadData.holders.acl, d_buffer, d_proxiedRemote, d_proxiedDestination, proxyProtocolValues)) {
+ if (!handleProxyProtocol(d_ci.remote, true, dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL, d_buffer, d_proxiedRemote, d_proxiedDestination, proxyProtocolValues)) {
vinfolog("Error handling the Proxy Protocol received from TCP client %s", d_ci.remote.toStringWithPort());
return ProxyProtocolResult::Error;
}
d_proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(std::move(proxyProtocolValues));
}
+ d_currentPos = 0;
+ d_proxyProtocolNeed = 0;
+ d_buffer.clear();
return ProxyProtocolResult::Done;
}
}
iostate = IOState::Done;
IOStateGuard ioGuard(d_ioState);
- if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+ if (maxConnectionDurationReached(dnsdist::configuration::getCurrentRuntimeConfiguration().d_maxTCPConnectionDuration, now)) {
vinfolog("Terminating TCP connection from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
// will be handled by the ioGuard
// handleNewIOState(state, IOState::Done, fd, handleIOCallback);
if (!d_lastIOBlocked && d_state == State::readingProxyProtocolHeader) {
auto status = handleProxyProtocolPayload();
if (status == ProxyProtocolResult::Done) {
+ d_buffer.resize(sizeof(uint16_t));
+
if (isProxyPayloadOutsideTLS()) {
d_state = State::doingHandshake;
iostate = handleHandshake(now);
}
else {
d_state = State::readingQuerySize;
- d_buffer.resize(sizeof(uint16_t));
- d_currentPos = 0;
- d_proxyProtocolNeed = 0;
}
}
else if (status == ProxyProtocolResult::Error) {
}
}
-static bool processXFRResponse(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& xfrRespRuleActions, DNSResponse& dnsResponse)
+static bool processXFRResponse(PacketBuffer& response, DNSResponse& dnsResponse)
{
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& xfrRespRuleActions = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::XFRResponseRules);
+
if (!applyRulesToResponse(xfrRespRuleActions, dnsResponse)) {
return false;
}
dnsResponse.d_incomingTCPState = state;
memcpy(&response.d_cleartextDH, dnsResponse.getHeader().get(), sizeof(response.d_cleartextDH));
- if (!processXFRResponse(response.d_buffer, *state->d_threadData.localXFRRespRuleActions, dnsResponse)) {
+ if (!processXFRResponse(response.d_buffer, dnsResponse)) {
state->terminateClientConnection();
return;
}
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
ClientState& clientState;
ComboAddress local;
- // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
- LocalStateHolder<NetmaskGroup>& acl;
int socket{-1};
};
data.mplexer->addReadFD(data.crossProtocolResponseReceiver.getDescriptor(), handleCrossProtocolResponse, &data);
/* only used in single acceptor mode for now */
- auto acl = g_ACL.getLocal();
std::vector<TCPAcceptorParam> acceptParams;
acceptParams.reserve(tcpAcceptStates.size());
for (auto& state : tcpAcceptStates) {
- acceptParams.emplace_back(TCPAcceptorParam{*state, state->local, acl, state->tcpFD});
+ acceptParams.emplace_back(TCPAcceptorParam{*state, state->local, state->tcpFD});
for (const auto& [addr, socket] : state->d_additionalAddresses) {
- acceptParams.emplace_back(TCPAcceptorParam{*state, addr, acl, socket});
+ acceptParams.emplace_back(TCPAcceptorParam{*state, addr, socket});
}
}
static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadData* threadData)
{
auto& clientState = param.clientState;
- auto& acl = param.acl;
const bool checkACL = clientState.dohFrontend == nullptr || (!clientState.dohFrontend->d_trustForwardedForHeader && clientState.dohFrontend->d_earlyACLDrop);
const int socket = param.socket;
bool tcpClientCountIncremented = false;
throw std::runtime_error((boost::format("accepting new connection on socket: %s") % stringerror()).str());
}
- if (checkACL && !acl->match(remote)) {
+ if (checkACL && !dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
++dnsdist::metrics::g_stats.aclDrops;
vinfolog("Dropped TCP connection from %s because of ACL", remote.toStringWithPort());
return;
setTCPNoDelay(connInfo.fd); // disable NAGLE
- if (g_maxTCPQueuedConnections > 0 && g_tcpclientthreads->getQueuedCount() >= g_maxTCPQueuedConnections) {
+ const auto maxTCPQueuedConnections = dnsdist::configuration::getImmutableConfiguration().d_maxTCPQueuedConnections;
+ if (maxTCPQueuedConnections > 0 && g_tcpclientthreads->getQueuedCount() >= maxTCPQueuedConnections) {
vinfolog("Dropping TCP connection from %s because we have too many queued already", remote.toStringWithPort());
return;
}
{
setThreadName("dnsdist/tcpAcce");
- auto acl = g_ACL.getLocal();
std::vector<TCPAcceptorParam> params;
params.reserve(states.size());
for (const auto& state : states) {
- params.emplace_back(TCPAcceptorParam{*state, state->local, acl, state->tcpFD});
+ params.emplace_back(TCPAcceptorParam{*state, state->local, state->tcpFD});
for (const auto& [addr, socket] : state->d_additionalAddresses) {
- params.emplace_back(TCPAcceptorParam{*state, addr, acl, socket});
+ params.emplace_back(TCPAcceptorParam{*state, addr, socket});
}
}
#include "base64.hh"
#include "connection-management.hh"
#include "dnsdist.hh"
+#include "dnsdist-cache.hh"
+#include "dnsdist-configuration.hh"
#include "dnsdist-dynblocks.hh"
+#include "dnsdist-dynbpf.hh"
+#include "dnsdist-frontend.hh"
#include "dnsdist-healthchecks.hh"
+#include "dnsdist-lua.hh"
#include "dnsdist-metrics.hh"
#include "dnsdist-prometheus.hh"
#include "dnsdist-rings.hh"
#include "threadname.hh"
#include "sstuff.hh"
-struct WebserverConfig
-{
- WebserverConfig()
- {
- acl.toMasks("127.0.0.1, ::1");
- }
-
- NetmaskGroup acl;
- std::unique_ptr<CredentialsHolder> password;
- std::unique_ptr<CredentialsHolder> apiKey;
- boost::optional<std::unordered_map<std::string, std::string>> customHeaders;
- bool apiRequiresAuthentication{true};
- bool dashboardRequiresAuthentication{true};
- bool statsRequireAuthentication{true};
-};
-
-bool g_apiReadWrite{false};
-LockGuarded<WebserverConfig> g_webserverConfig;
-std::string g_apiConfigDirectory;
-
-static ConcurrentConnectionManager s_connManager(100);
-
-std::string getWebserverConfig()
-{
- ostringstream out;
-
- {
- auto config = g_webserverConfig.lock();
- out << "Current web server configuration:" << endl;
- out << "ACL: " << config->acl.toString() << endl;
- out << "Custom headers: ";
- if (config->customHeaders) {
- out << endl;
- for (const auto& header : *config->customHeaders) {
- out << " - " << header.first << ": " << header.second << endl;
- }
- }
- else {
- out << "None" << endl;
- }
- out << "API requires authentication: " << (config->apiRequiresAuthentication ? "yes" : "no") << endl;
- out << "Dashboard requires authentication: " << (config->dashboardRequiresAuthentication ? "yes" : "no") << endl;
- out << "Statistics require authentication: " << (config->statsRequireAuthentication ? "yes" : "no") << endl;
- out << "Password: " << (config->password ? "set" : "unset") << endl;
- out << "API key: " << (config->apiKey ? "set" : "unset") << endl;
- }
- out << "API writable: " << (g_apiReadWrite ? "yes" : "no") << endl;
- out << "API configuration directory: " << g_apiConfigDirectory << endl;
- out << "Maximum concurrent connections: " << s_connManager.getMaxConcurrentConnections() << endl;
-
- return out.str();
-}
-
-class WebClientConnection
-{
-public:
- WebClientConnection(const ComboAddress& client, int socketDesc) :
- d_client(client), d_socket(socketDesc)
- {
- if (!s_connManager.registerConnection()) {
- throw std::runtime_error("Too many concurrent web client connections");
- }
- }
- WebClientConnection(WebClientConnection&& rhs) noexcept :
- d_client(rhs.d_client), d_socket(std::move(rhs.d_socket))
- {
- }
- WebClientConnection(const WebClientConnection&) = delete;
- WebClientConnection& operator=(const WebClientConnection&) = delete;
- WebClientConnection& operator=(WebClientConnection&& rhs) noexcept
- {
- d_client = rhs.d_client;
- d_socket = std::move(rhs.d_socket);
- return *this;
- }
-
- ~WebClientConnection()
- {
- if (d_socket.getHandle() != -1) {
- s_connManager.releaseConnection();
- }
- }
-
- [[nodiscard]] const Socket& getSocket() const
- {
- return d_socket;
- }
-
- [[nodiscard]] const ComboAddress& getClient() const
- {
- return d_client;
- }
-
-private:
- ComboAddress d_client;
- Socket d_socket;
-};
-
#ifndef DISABLE_PROMETHEUS
static MetricDefinitionStorage s_metricDefinitions;
};
#endif /* DISABLE_PROMETHEUS */
+namespace dnsdist::webserver
+{
+static ConcurrentConnectionManager s_connManager(100);
+
+std::string getConfig()
+{
+ ostringstream out;
+
+ {
+ const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ out << "Current web server configuration:" << endl;
+ out << "ACL: " << config.d_webServerACL.toString() << endl;
+ out << "Custom headers: ";
+ if (config.d_webCustomHeaders) {
+ out << endl;
+ for (const auto& header : *config.d_webCustomHeaders) {
+ out << " - " << header.first << ": " << header.second << endl;
+ }
+ }
+ else {
+ out << "None" << endl;
+ }
+ out << "API requires authentication: " << (config.d_apiRequiresAuthentication ? "yes" : "no") << endl;
+ out << "Dashboard requires authentication: " << (config.d_dashboardRequiresAuthentication ? "yes" : "no") << endl;
+ out << "Statistics require authentication: " << (config.d_statsRequireAuthentication ? "yes" : "no") << endl;
+ out << "Password: " << (config.d_webPassword ? "set" : "unset") << endl;
+ out << "API key: " << (config.d_webAPIKey ? "set" : "unset") << endl;
+ out << "API writable: " << (config.d_apiReadWrite ? "yes" : "no") << endl;
+ out << "API configuration directory: " << config.d_apiConfigDirectory << endl;
+ out << "Maximum concurrent connections: " << s_connManager.getMaxConcurrentConnections() << endl;
+ }
+
+ return out.str();
+}
+
+class WebClientConnection
+{
+public:
+ WebClientConnection(const ComboAddress& client, int socketDesc) :
+ d_client(client), d_socket(socketDesc)
+ {
+ if (!s_connManager.registerConnection()) {
+ throw std::runtime_error("Too many concurrent web client connections");
+ }
+ }
+ WebClientConnection(WebClientConnection&& rhs) noexcept :
+ d_client(rhs.d_client), d_socket(std::move(rhs.d_socket))
+ {
+ }
+ WebClientConnection(const WebClientConnection&) = delete;
+ WebClientConnection& operator=(const WebClientConnection&) = delete;
+ WebClientConnection& operator=(WebClientConnection&& rhs) noexcept
+ {
+ d_client = rhs.d_client;
+ d_socket = std::move(rhs.d_socket);
+ return *this;
+ }
+
+ ~WebClientConnection()
+ {
+ if (d_socket.getHandle() != -1) {
+ s_connManager.releaseConnection();
+ }
+ }
+
+ [[nodiscard]] const Socket& getSocket() const
+ {
+ return d_socket;
+ }
+
+ [[nodiscard]] const ComboAddress& getClient() const
+ {
+ return d_client;
+ }
+
+private:
+ ComboAddress d_client;
+ Socket d_socket;
+};
+
bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def)
{
#ifndef DISABLE_PROMETHEUS
#ifndef DISABLE_WEB_CONFIG
static bool apiWriteConfigFile(const string& filebasename, const string& content)
{
- if (!g_apiReadWrite) {
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (!runtimeConfig.d_apiReadWrite) {
warnlog("Not writing content to %s since the API is read-only", filebasename);
return false;
}
- if (g_apiConfigDirectory.empty()) {
+ if (runtimeConfig.d_apiConfigDirectory.empty()) {
vinfolog("Not writing content to %s since the API configuration directory is not set", filebasename);
return false;
}
- string filename = g_apiConfigDirectory + "/" + filebasename + ".conf";
+ string filename = runtimeConfig.d_apiConfigDirectory + "/" + filebasename + ".conf";
ofstream ofconf(filename.c_str());
if (!ofconf) {
errlog("Could not open configuration fragment file '%s' for writing: %s", filename, stringerror());
}
#endif /* DISABLE_WEB_CONFIG */
-static bool checkAPIKey(const YaHTTP::Request& req, const std::unique_ptr<CredentialsHolder>& apiKey)
+static bool checkAPIKey(const YaHTTP::Request& req, const std::shared_ptr<const CredentialsHolder>& apiKey)
{
if (!apiKey) {
return false;
return false;
}
-static bool checkWebPassword(const YaHTTP::Request& req, const std::unique_ptr<CredentialsHolder>& password, bool dashboardRequiresAuthentication)
+static bool checkWebPassword(const YaHTTP::Request& req, const std::shared_ptr<const CredentialsHolder>& password, bool dashboardRequiresAuthentication)
{
if (!dashboardRequiresAuthentication) {
return true;
static bool handleAuthorization(const YaHTTP::Request& req)
{
- auto config = g_webserverConfig.lock();
+ const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
if (isAStatsRequest(req)) {
- if (config->statsRequireAuthentication) {
+ if (config.d_statsRequireAuthentication) {
/* Access to the stats is allowed for both API and Web users */
- return checkAPIKey(req, config->apiKey) || checkWebPassword(req, config->password, config->dashboardRequiresAuthentication);
+ return checkAPIKey(req, config.d_webAPIKey) || checkWebPassword(req, config.d_webPassword, config.d_dashboardRequiresAuthentication);
}
return true;
}
if (isAnAPIRequest(req)) {
/* Access to the API requires a valid API key */
- if (!config->apiRequiresAuthentication || checkAPIKey(req, config->apiKey)) {
+ if (!config.d_apiRequiresAuthentication || checkAPIKey(req, config.d_webAPIKey)) {
return true;
}
- return isAnAPIRequestAllowedWithWebAuth(req) && checkWebPassword(req, config->password, config->dashboardRequiresAuthentication);
+ return isAnAPIRequestAllowedWithWebAuth(req) && checkWebPassword(req, config.d_webPassword, config.d_dashboardRequiresAuthentication);
}
- return checkWebPassword(req, config->password, config->dashboardRequiresAuthentication);
+ return checkWebPassword(req, config.d_webPassword, config.d_dashboardRequiresAuthentication);
}
static bool isMethodAllowed(const YaHTTP::Request& req)
if (req.method == "GET") {
return true;
}
- if (req.method == "PUT" && g_apiReadWrite) {
+ if (req.method == "PUT" && dnsdist::configuration::getCurrentRuntimeConfiguration().d_apiReadWrite) {
if (req.url.path == "/api/v1/servers/localhost/config/allow-from") {
return true;
}
static bool isClientAllowedByACL(const ComboAddress& remote)
{
- return g_webserverConfig.lock()->acl.match(remote);
+ const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ return config.d_webServerACL.match(remote);
}
static void handleCORS(const YaHTTP::Request& req, YaHTTP::Response& resp)
if (origin != req.headers.end()) {
if (req.method == "OPTIONS") {
/* Pre-flight request */
- if (g_apiReadWrite) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_apiReadWrite) {
resp.headers["Access-Control-Allow-Methods"] = "GET, PUT";
}
else {
}
}
-static void addSecurityHeaders(YaHTTP::Response& resp, const boost::optional<std::unordered_map<std::string, std::string>>& customHeaders)
+static void addSecurityHeaders(YaHTTP::Response& resp, const std::optional<std::unordered_map<std::string, std::string>>& customHeaders)
{
static const std::vector<std::pair<std::string, std::string>> headers = {
{"X-Content-Type-Options", "nosniff"},
}
}
-static void addCustomHeaders(YaHTTP::Response& resp, const boost::optional<std::unordered_map<std::string, std::string>>& customHeaders)
+static void addCustomHeaders(YaHTTP::Response& resp, const std::optional<std::unordered_map<std::string, std::string>>& customHeaders)
{
if (!customHeaders) {
return;
}
template <typename T>
-static json11::Json::array someResponseRulesToJson(GlobalStateHolder<vector<T>>* someResponseRules)
+static json11::Json::array someResponseRulesToJson(const std::vector<T>& someResponseRules)
{
using namespace json11;
Json::array responseRules;
int num = 0;
- auto localResponseRules = someResponseRules->getLocal();
- responseRules.reserve(localResponseRules->size());
- for (const auto& rule : *localResponseRules) {
+ responseRules.reserve(someResponseRules.size());
+ for (const auto& rule : someResponseRules) {
responseRules.emplace_back(Json::object{
{"id", num++},
{"creationOrder", static_cast<double>(rule.d_creationOrder)},
#ifndef DISABLE_PROMETHEUS
template <typename T>
-static void addRulesToPrometheusOutput(std::ostringstream& output, GlobalStateHolder<vector<T>>& rules)
+static void addRulesToPrometheusOutput(std::ostringstream& output, const std::vector<T>& rules)
{
- auto localRules = rules.getLocal();
- for (const auto& entry : *localRules) {
+ for (const auto& entry : rules) {
std::string identifier = !entry.d_name.empty() ? entry.d_name : boost::uuids::to_string(entry.d_id);
output << "dnsdist_rule_hits{id=\"" << identifier << "\"} " << entry.d_rule->d_matches << "\n";
}
static const std::set<std::string> metricBlacklist = {"special-memory-usage", "latency-count", "latency-sum"};
{
auto entries = dnsdist::metrics::g_stats.entries.read_lock();
+ std::unordered_set<std::string> helpAndTypeSent;
for (const auto& entry : *entries) {
const auto& metricName = entry.d_name;
// for these we have the help and types encoded in the sources
// but we need to be careful about labels in custom metrics
std::string helpName = prometheusMetricName.substr(0, prometheusMetricName.find('{'));
- output << "# HELP " << helpName << " " << metricDetails.description << "\n";
- output << "# TYPE " << helpName << " " << prometheusTypeName << "\n";
+ if (helpAndTypeSent.count(helpName) == 0) {
+ helpAndTypeSent.insert(helpName);
+ output << "# HELP " << helpName << " " << metricDetails.description << "\n";
+ output << "# TYPE " << helpName << " " << prometheusTypeName << "\n";
+ }
output << prometheusMetricName << " ";
if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
output << (*val)->load();
}
- else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&entry.d_value)) {
output << (*adval)->load();
}
- else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
- output << **dval;
- }
else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
output << (*func)(entry.d_name);
}
output << "dnsdist_latency_sum " << dnsdist::metrics::g_stats.latencySum << "\n";
output << "dnsdist_latency_count " << dnsdist::metrics::g_stats.latencyCount << "\n";
- auto states = g_dstates.getLocal();
const string statesbase = "dnsdist_server_";
// clang-format off
output << "# HELP " << statesbase << "healthcheckfailuresinvalid " << "Number of health check attempts where the DNS response was invalid" << "\n";
output << "# TYPE " << statesbase << "healthcheckfailuresinvalid " << "counter" << "\n";
- for (const auto& state : *states) {
+ for (const auto& state : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
string serverName;
if (state->getName().empty()) {
output << "# TYPE " << frontsbase << "tlshandshakefailures " << "counter" << "\n";
std::map<std::string,uint64_t> frontendDuplicates;
- for (const auto& front : g_frontends) {
+ for (const auto& front : dnsdist::getFrontends()) {
if (front->udpFD == -1 && front->tcpFD == -1) {
continue;
}
#ifdef HAVE_DNS_OVER_HTTPS
std::map<std::string,uint64_t> dohFrontendDuplicates;
- for(const auto& doh : g_dohlocals) {
+ for(const auto& doh : dnsdist::getDoHFrontends()) {
const string frontName = doh->d_tlsContext.d_addr.toStringWithPort();
uint64_t threadNumber = 0;
auto dupPair = frontendDuplicates.emplace(frontName, 1);
}
#endif /* HAVE_DNS_OVER_HTTPS */
- auto localPools = g_pools.getLocal();
const string cachebase = "dnsdist_pool_";
output << "# HELP dnsdist_pool_servers " << "Number of servers in that pool" << "\n";
output << "# TYPE dnsdist_pool_servers " << "gauge" << "\n";
output << "# HELP dnsdist_pool_cache_cleanup_count_total " << "Number of times the cache has been scanned to remove expired entries, if any" << "\n";
output << "# TYPE dnsdist_pool_cache_cleanup_count_total " << "counter" << "\n";
- for (const auto& entry : *localPools) {
+ for (const auto& entry : dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools) {
string poolName = entry.first;
if (poolName.empty()) {
output << "# HELP dnsdist_rule_hits " << "Number of hits of that rule" << "\n";
output << "# TYPE dnsdist_rule_hits " << "counter" << "\n";
- for (const auto& chain : dnsdist::rules::getRuleChains()) {
- addRulesToPrometheusOutput(output, chain.holder);
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ for (const auto& chainDescription : dnsdist::rules::getRuleChainDescriptions()) {
+ const auto& chain = dnsdist::rules::getRuleChain(chains, chainDescription.identifier);
+ addRulesToPrometheusOutput(output, chain);
}
- for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
- addRulesToPrometheusOutput(output, chain.holder);
+ for (const auto& chainDescription : dnsdist::rules::getResponseRuleChainDescriptions()) {
+ const auto& chain = dnsdist::rules::getResponseRuleChain(chains, chainDescription.identifier);
+ addRulesToPrometheusOutput(output, chain);
}
#ifndef DISABLE_DYNBLOCKS
if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
obj.emplace(entry.d_name, (double)(*val)->load());
}
- else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&entry.d_value)) {
obj.emplace(entry.d_name, (*adval)->load());
}
- else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
- obj.emplace(entry.d_name, (**dval));
- }
else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
obj.emplace(entry.d_name, (double)(*func)(entry.d_name));
}
}
const string& command = req.getvars.at("command");
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
if (command == "stats") {
auto obj = Json::object{
{"packetcache-misses", 0},
{"over-capacity-drops", 0},
{"too-old-drops", 0},
- {"server-policy", g_policy.getLocal()->getName()}};
+ {"server-policy", runtimeConfig.d_lbPolicy->getName()}};
addStatsToJSONObject(obj);
else if (command == "dynblocklist") {
Json::object obj;
#ifndef DISABLE_DYNBLOCKS
- auto nmg = g_dynblockNMG.getLocal();
timespec now{};
gettime(&now);
- for (const auto& entry : *nmg) {
+ const auto& dynamicClientAddressRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
+ for (const auto& entry : dynamicClientAddressRules) {
if (!(now < entry.second.until)) {
continue;
}
{"reason", entry.second.reason},
{"seconds", static_cast<double>(entry.second.until.tv_sec - now.tv_sec)},
{"blocks", static_cast<double>(counter)},
- {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction)},
+ {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : runtimeConfig.d_dynBlockAction)},
{"warning", entry.second.warning},
{"ebpf", entry.second.bpf}};
obj.emplace(entry.first.toString(), thing);
}
- auto smt = g_dynblockSMT.getLocal();
- smt->visit([&now, &obj](const SuffixMatchTree<DynBlock>& node) {
+ const auto& dynamicSuffixRules = dnsdist::DynamicBlocks::getSuffixDynamicRules();
+ dynamicSuffixRules.visit([&now, &obj, &runtimeConfig](const SuffixMatchTree<DynBlock>& node) {
if (!(now < node.d_value.until)) {
return;
}
{"reason", node.d_value.reason},
{"seconds", static_cast<double>(node.d_value.until.tv_sec - now.tv_sec)},
{"blocks", static_cast<double>(node.d_value.blocks)},
- {"action", DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : g_dynBlockAction)},
+ {"action", DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : runtimeConfig.d_dynBlockAction)},
{"ebpf", node.d_value.bpf}};
obj.emplace(dom, thing);
});
}
}
if (g_defaultBPFFilter) {
- auto nmg = g_dynblockNMG.getLocal();
- for (const auto& entry : *nmg) {
+ const auto& dynamicClientAddressRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
+ for (const auto& entry : dynamicClientAddressRules) {
if (!(now < entry.second.until) || !entry.second.bpf) {
continue;
}
{"reason", entry.second.reason},
{"seconds", static_cast<double>(entry.second.until.tv_sec - now.tv_sec)},
{"blocks", static_cast<double>(counter)},
- {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction)},
+ {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : runtimeConfig.d_dynBlockAction)},
{"warning", entry.second.warning},
};
obj.emplace(entry.first.toString(), thing);
status = "DOWN";
}
else {
- status = (backend->upStatus ? "up" : "down");
+ status = (backend->upStatus.load(std::memory_order_relaxed) ? "up" : "down");
}
Json::array pools;
Json::array servers;
{
- auto localServers = g_dstates.getLocal();
- servers.reserve(localServers->size());
- for (const auto& server : *localServers) {
+ const auto& localServers = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
+ servers.reserve(localServers.size());
+ for (const auto& server : localServers) {
addServerToJSON(servers, num++, server);
}
}
Json::array frontends;
num = 0;
- frontends.reserve(g_frontends.size());
- for (const auto& front : g_frontends) {
+ frontends.reserve(dnsdist::getFrontends().size());
+ for (const auto& front : dnsdist::getFrontends()) {
if (front->udpFD == -1 && front->tcpFD == -1) {
continue;
}
Json::array dohs;
#ifdef HAVE_DNS_OVER_HTTPS
{
- dohs.reserve(g_dohlocals.size());
+ const auto dohFrontends = dnsdist::getDoHFrontends();
+ dohs.reserve(dohFrontends.size());
num = 0;
- for (const auto& doh : g_dohlocals) {
+ for (const auto& doh : dohFrontends) {
dohs.emplace_back(Json::object{
{"id", num++},
{"address", doh->d_tlsContext.d_addr.toStringWithPort()},
Json::array pools;
{
- auto localPools = g_pools.getLocal();
num = 0;
- pools.reserve(localPools->size());
- for (const auto& pool : *localPools) {
+ const auto& localPools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ pools.reserve(localPools.size());
+ for (const auto& pool : localPools) {
const auto& cache = pool.second->packetCache;
Json::object entry{
{"id", num++},
string acl;
{
- auto aclEntries = g_ACL.getLocal()->toStringVector();
+ auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.toStringVector();
for (const auto& entry : aclEntries) {
if (!acl.empty()) {
string localaddressesStr;
{
std::set<std::string> localaddresses;
- for (const auto& front : g_frontends) {
+ for (const auto& front : dnsdist::getFrontends()) {
localaddresses.insert(front->local.toStringWithPort());
}
for (const auto& addr : localaddresses) {
/* unfortunately DNSActions have getStats(),
and DNSResponseActions do not. */
- for (const auto& chain : dnsdist::rules::getRuleChains()) {
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ for (const auto& chainDescription : dnsdist::rules::getRuleChainDescriptions()) {
Json::array rules;
- auto localRules = chain.holder.getLocal();
+ const auto& chain = dnsdist::rules::getRuleChain(chains, chainDescription.identifier);
num = 0;
- rules.reserve(localRules->size());
- for (const auto& lrule : *localRules) {
+ rules.reserve(chain.size());
+ for (const auto& lrule : chain) {
Json::object rule{
{"id", num++},
{"creationOrder", (double)lrule.d_creationOrder},
{"action-stats", lrule.d_action->getStats()}};
rules.emplace_back(std::move(rule));
}
- responseObject[chain.metricName] = std::move(rules);
+ responseObject[chainDescription.metricName] = std::move(rules);
}
- for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
- auto responseRules = someResponseRulesToJson(&chain.holder);
- responseObject[chain.metricName] = std::move(responseRules);
+ for (const auto& chainDescription : dnsdist::rules::getResponseRuleChainDescriptions()) {
+ const auto& chain = dnsdist::rules::getResponseRuleChain(chains, chainDescription.identifier);
+ auto responseRules = someResponseRulesToJson(chain);
+ responseObject[chainDescription.metricName] = std::move(responseRules);
}
resp.headers["Content-Type"] = "application/json";
resp.status = 200;
Json::array doc;
- auto localPools = g_pools.getLocal();
- const auto poolIt = localPools->find(poolName->second);
- if (poolIt == localPools->end()) {
+ const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ const auto poolIt = pools.find(poolName->second);
+ if (poolIt == pools.end()) {
resp.status = 404;
return;
}
{"name", item.d_name},
{"value", (double)(*val)->load()}});
}
- else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&item.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&item.d_value)) {
doc.emplace_back(Json::object{
{"type", "StatisticItem"},
{"name", item.d_name},
{"value", (*adval)->load()}});
}
- else if (const auto& dval = std::get_if<double*>(&item.d_value)) {
- doc.emplace_back(Json::object{
- {"type", "StatisticItem"},
- {"name", item.d_name},
- {"value", (**dval)}});
- }
else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&item.d_value)) {
doc.emplace_back(Json::object{
{"type", "StatisticItem"},
resp.status = 200;
Json::array doc;
- typedef boost::variant<bool, double, std::string> configentry_t;
+ const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
+ using configentry_t = boost::variant<bool, double, std::string>;
std::vector<std::pair<std::string, configentry_t>> configEntries{
- {"acl", g_ACL.getLocal()->toString()},
- {"allow-empty-response", g_allowEmptyResponse},
- {"control-socket", g_serverControl.toStringWithPort()},
- {"ecs-override", g_ECSOverride},
- {"ecs-source-prefix-v4", (double)g_ECSSourcePrefixV4},
- {"ecs-source-prefix-v6", (double)g_ECSSourcePrefixV6},
- {"fixup-case", g_fixupCase},
- {"max-outstanding", (double)g_maxOutstanding},
- {"server-policy", g_policy.getLocal()->getName()},
- {"stale-cache-entries-ttl", (double)g_staleCacheEntriesTTL},
- {"tcp-recv-timeout", (double)g_tcpRecvTimeout},
- {"tcp-send-timeout", (double)g_tcpSendTimeout},
- {"truncate-tc", g_truncateTC},
- {"verbose", g_verbose},
- {"verbose-health-checks", g_verboseHealthChecks}};
+ {"acl", runtimeConfiguration.d_ACL.toString()},
+ {"allow-empty-response", runtimeConfiguration.d_allowEmptyResponse},
+ {"control-socket", runtimeConfiguration.d_consoleServerAddress.toStringWithPort()},
+ {"ecs-override", runtimeConfiguration.d_ecsOverride},
+ {"ecs-source-prefix-v4", static_cast<double>(runtimeConfiguration.d_ECSSourcePrefixV4)},
+ {"ecs-source-prefix-v6", static_cast<double>(runtimeConfiguration.d_ECSSourcePrefixV6)},
+ {"fixup-case", runtimeConfiguration.d_fixupCase},
+ {"max-outstanding", static_cast<double>(immutableConfig.d_maxUDPOutstanding)},
+ {"server-policy", runtimeConfiguration.d_lbPolicy->getName()},
+ {"stale-cache-entries-ttl", static_cast<double>(runtimeConfiguration.d_staleCacheEntriesTTL)},
+ {"tcp-recv-timeout", static_cast<double>(runtimeConfiguration.d_tcpRecvTimeout)},
+ {"tcp-send-timeout", static_cast<double>(runtimeConfiguration.d_tcpSendTimeout)},
+ {"truncate-tc", runtimeConfiguration.d_truncateTC},
+ {"verbose", runtimeConfiguration.d_verbose},
+ {"verbose-health-checks", runtimeConfiguration.d_verboseHealthChecks}};
for (const auto& item : configEntries) {
if (const auto& bval = boost::get<bool>(&item.second)) {
doc.emplace_back(Json::object{
if (resp.status == 200) {
infolog("Updating the ACL via the API to %s", nmg.toString());
- g_ACL.setState(nmg);
+ dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_ACL = nmg;
+ });
apiSaveACL(nmg);
}
}
}
}
if (resp.status == 200) {
- auto aclEntries = g_ACL.getLocal()->toStringVector();
+ auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.toStringVector();
Json::object obj{
{"type", "ConfigSetting"},
std::shared_ptr<ServerPool> pool;
try {
- pool = getPool(g_pools.getCopy(), poolName->second);
+ pool = getPool(poolName->second);
}
catch (const std::exception& e) {
resp.status = 404;
}
using WebHandler = std::function<void(const YaHTTP::Request&, YaHTTP::Response&)>;
-static SharedLockGuarded<std::unordered_map<std::string, WebHandler>> s_webHandlers;
+struct WebHandlerContext
+{
+ WebHandler d_handler;
+ bool d_isLua{false};
+};
+
+static SharedLockGuarded<std::unordered_map<std::string, WebHandlerContext>> s_webHandlers;
-void registerWebHandler(const std::string& endpoint, WebHandler handler);
+void registerWebHandler(const std::string& endpoint, WebHandler handler, bool isLua = false);
-void registerWebHandler(const std::string& endpoint, WebHandler handler)
+void registerWebHandler(const std::string& endpoint, WebHandler handler, bool isLua)
{
auto handlers = s_webHandlers.write_lock();
- (*handlers)[endpoint] = std::move(handler);
+ (*handlers)[endpoint] = WebHandlerContext{std::move(handler), isLua};
}
void clearWebHandlers()
resp.version = req.version;
{
- auto config = g_webserverConfig.lock();
-
- addCustomHeaders(resp, config->customHeaders);
- addSecurityHeaders(resp, config->customHeaders);
+ const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ addCustomHeaders(resp, config.d_webCustomHeaders);
+ addSecurityHeaders(resp, config.d_webCustomHeaders);
}
/* indicate that the connection will be closed after completion of the response */
resp.headers["Connection"] = "close";
resp.status = 405;
}
else {
- WebHandler handler;
+ std::optional<WebHandlerContext> handlerCtx{std::nullopt};
{
auto handlers = s_webHandlers.read_lock();
const auto webHandlersIt = handlers->find(req.url.path);
if (webHandlersIt != handlers->end()) {
- handler = webHandlersIt->second;
+ handlerCtx = webHandlersIt->second;
}
}
- if (handler) {
- handler(req, resp);
+ if (handlerCtx) {
+ if (handlerCtx->d_isLua) {
+ auto lua = g_lua.lock();
+ handlerCtx->d_handler(req, resp);
+ }
+ else {
+ handlerCtx->d_handler(req, resp);
+ }
}
else {
resp.status = 404;
}
}
-void setWebserverAPIKey(std::unique_ptr<CredentialsHolder>&& apiKey)
-{
- auto config = g_webserverConfig.lock();
-
- if (apiKey) {
- config->apiKey = std::move(apiKey);
- }
- else {
- config->apiKey.reset();
- }
-}
-
-void setWebserverPassword(std::unique_ptr<CredentialsHolder>&& password)
-{
- g_webserverConfig.lock()->password = std::move(password);
-}
-
-void setWebserverACL(const std::string& acl)
-{
- NetmaskGroup newACL;
- newACL.toMasks(acl);
-
- g_webserverConfig.lock()->acl = std::move(newACL);
-}
-
-void setWebserverCustomHeaders(const boost::optional<std::unordered_map<std::string, std::string>>& customHeaders)
-{
- g_webserverConfig.lock()->customHeaders = customHeaders;
-}
-
-void setWebserverStatsRequireAuthentication(bool require)
-{
- g_webserverConfig.lock()->statsRequireAuthentication = require;
-}
-
-void setWebserverAPIRequiresAuthentication(bool require)
-{
- g_webserverConfig.lock()->apiRequiresAuthentication = require;
-}
-
-void setWebserverDashboardRequiresAuthentication(bool require)
-{
- g_webserverConfig.lock()->dashboardRequiresAuthentication = require;
-}
-
-void setWebserverMaxConcurrentConnections(size_t max)
+void setMaxConcurrentConnections(size_t max)
{
s_connManager.setMaxConcurrentConnections(max);
}
-void dnsdistWebserverThread(int sock, const ComboAddress& local)
+void WebserverThread(Socket sock)
{
setThreadName("dnsdist/webserv");
+ //coverity[auto_causes_copy]
+ const auto local = *dnsdist::configuration::getCurrentRuntimeConfiguration().d_webServerAddress;
infolog("Webserver launched on %s", local.toStringWithPort());
{
- auto config = g_webserverConfig.lock();
- if (!config->password && config->dashboardRequiresAuthentication) {
+ const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (!config.d_webPassword && config.d_dashboardRequiresAuthentication) {
warnlog("Webserver launched on %s without a password set!", local.toStringWithPort());
}
}
for (;;) {
try {
ComboAddress remote(local);
- int fileDesc = SAccept(sock, remote);
+ int fileDesc = SAccept(sock.getHandle(), remote);
if (!isClientAllowedByACL(remote)) {
vinfolog("Connection to webserver from client %s is not allowed, closing", remote.toStringWithPort());
}
}
}
+}
#include "credentials.hh"
#include "dnsdist-prometheus.hh"
+#include "sstuff.hh"
-void setWebserverAPIKey(std::unique_ptr<CredentialsHolder>&& apiKey);
-void setWebserverPassword(std::unique_ptr<CredentialsHolder>&& password);
-void setWebserverACL(const std::string& acl);
-void setWebserverCustomHeaders(const boost::optional<std::unordered_map<std::string, std::string> >& customHeaders);
-void setWebserverAPIRequiresAuthentication(bool);
-void setWebserverDashboardRequiresAuthentication(bool);
-void setWebserverStatsRequireAuthentication(bool);
-void setWebserverMaxConcurrentConnections(size_t);
-
-void dnsdistWebserverThread(int sock, const ComboAddress& local);
-
+namespace dnsdist::webserver
+{
+void WebserverThread(Socket sock);
+void setMaxConcurrentConnections(size_t max);
void registerBuiltInWebHandlers();
void clearWebHandlers();
-
-std::string getWebserverConfig();
-
+std::string getConfig();
bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def);
+}
{
try {
setThreadName("dnsdist/XskResp");
- auto localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
- auto localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
auto pollfds = getPollFdsForWorker(*xskInfo);
while (!dss->isStopped()) {
poll(pollfds.data(), pollfds.size(), -1);
if ((pollfds[0].revents & POLLIN) != 0) {
needNotify = true;
xskInfo->cleanSocketNotification();
-#if defined(__SANITIZE_THREAD__)
- xskInfo->incomingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
-#else
- xskInfo->incomingPacketsQueue.consume_all([&](XskPacket& packet) {
-#endif
+ xskInfo->processIncomingFrames([&](XskPacket& packet) {
if (packet.getDataLen() < sizeof(dnsheader)) {
xskInfo->markAsFree(packet);
return;
/* fallback to sending the packet via normal socket */
ids->xskPacketHeader.clear();
}
- if (!processResponderPacket(dss, response, *localRespRuleActions, *localCacheInsertedRespRuleActions, std::move(*ids))) {
+ if (!processResponderPacket(dss, response, std::move(*ids))) {
xskInfo->markAsFree(packet);
- infolog("XSK packet pushed to queue because processResponderPacket failed");
+ vinfolog("XSK packet dropped because processResponderPacket failed");
return;
}
if (response.size() > packet.getCapacity()) {
}
}
-bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, LocalHolders& holders, bool& expectProxyProtocol)
+bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, bool& expectProxyProtocol)
{
const auto& from = packet.getFromAddr();
expectProxyProtocol = expectProxyProtocolFrom(from);
- if (!holders.acl->match(from) && !expectProxyProtocol) {
+ if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(from) && !expectProxyProtocol) {
vinfolog("Query from %s dropped because of ACL", from.toStringWithPort());
++dnsdist::metrics::g_stats.aclDrops;
return false;
if ((fds.at(fdIndex).revents & POLLIN) != 0) {
ready--;
const auto& info = xsk->getWorkerByDescriptor(fds.at(fdIndex).fd);
-#if defined(__SANITIZE_THREAD__)
- info->outgoingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
-#else
- info->outgoingPacketsQueue.consume_all([&](XskPacket& packet) {
-#endif
+ info->processOutgoingFrames([&](XskPacket& packet) {
if ((packet.getFlags() & XskPacket::UPDATE) == 0) {
xsk->markAsFree(packet);
return;
{
setThreadName("dnsdist/xskClient");
auto xskInfo = clientState->xskInfo;
- LocalHolders holders;
for (;;) {
-#if defined(__SANITIZE_THREAD__)
- while (xskInfo->incomingPacketsQueue.lock()->read_available() == 0U) {
-#else
- while (xskInfo->incomingPacketsQueue.read_available() == 0U) {
-#endif
+ while (!xskInfo->hasIncomingFrames()) {
xskInfo->waitForXskSocket();
}
-#if defined(__SANITIZE_THREAD__)
- xskInfo->incomingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
-#else
- xskInfo->incomingPacketsQueue.consume_all([&](XskPacket& packet) {
-#endif
- if (XskProcessQuery(*clientState, holders, packet)) {
+ xskInfo->processIncomingFrames([&](XskPacket& packet) {
+ if (XskProcessQuery(*clientState, packet)) {
packet.updatePacket();
xskInfo->pushToSendQueue(packet);
}
namespace dnsdist::xsk
{
void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<XskWorker> xskInfo);
-bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, LocalHolders& holders, bool& expectProxyProtocol);
-bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket& packet);
+bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, bool& expectProxyProtocol);
+bool XskProcessQuery(ClientState& clientState, XskPacket& packet);
void XskRouter(std::shared_ptr<XskSocket> xsk);
void XskClientThread(ClientState* clientState);
void addDestinationAddress(const ComboAddress& addr);
#include <sys/resource.h>
#include <unistd.h>
-#ifdef HAVE_LIBEDIT
-#if defined(__OpenBSD__) || defined(__NetBSD__)
-// If this is not undeffed, __attribute__ wil be redefined by /usr/include/readline/rlstdc.h
-#undef __STRICT_ANSI__
-#include <readline/readline.h>
-#else
-#include <editline/readline.h>
-#endif
-#endif /* HAVE_LIBEDIT */
-
#include "dnsdist-systemd.hh"
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
#include "dnsdist-async.hh"
#include "dnsdist-cache.hh"
#include "dnsdist-carbon.hh"
+#include "dnsdist-configuration.hh"
#include "dnsdist-console.hh"
#include "dnsdist-crypto.hh"
#include "dnsdist-discovery.hh"
-#include "dnsdist-dnsparser.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-edns.hh"
+#include "dnsdist-frontend.hh"
#include "dnsdist-healthchecks.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-lua-hooks.hh"
#include "dnsdist-random.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-secpoll.hh"
+#include "dnsdist-snmp.hh"
#include "dnsdist-tcp.hh"
+#include "dnsdist-tcp-downstream.hh"
#include "dnsdist-web.hh"
#include "dnsdist-xsk.hh"
#include "doh.hh"
#include "dolog.hh"
#include "dnsname.hh"
-#include "dnsparser.hh"
#include "ednsoptions.hh"
#include "gettime.hh"
#include "lock.hh"
on the Lua side we can't do that. */
using std::thread;
-bool g_verbose;
-uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
-uint32_t g_staleCacheEntriesTTL{0};
-bool g_allowEmptyResponse{false};
-
-GlobalStateHolder<NetmaskGroup> g_ACL;
string g_outputBuffer;
-std::vector<std::shared_ptr<TLSFrontend>> g_tlslocals;
-std::vector<std::shared_ptr<DOHFrontend>> g_dohlocals;
-std::vector<std::shared_ptr<DOQFrontend>> g_doqlocals;
-std::vector<std::shared_ptr<DOH3Frontend>> g_doh3locals;
-std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
-
shared_ptr<BPFFilter> g_defaultBPFFilter{nullptr};
-std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
-std::vector<std::unique_ptr<ClientState>> g_frontends;
-GlobalStateHolder<pools_t> g_pools;
-size_t g_udpVectorSize{1};
-std::vector<uint32_t> g_TCPFastOpenKey;
/* UDP: the grand design. Per socket we listen on for incoming queries there is one thread.
Then we have a bunch of connected sockets for talking to downstream servers.
We send directly to those sockets.
*/
Rings g_rings;
-QueryCount g_qcount;
-
-GlobalStateHolder<servers_t> g_dstates;
-
-bool g_servFailOnNoPolicy{false};
-bool g_truncateTC{false};
-bool g_fixupCase{false};
-bool g_dropEmptyQueries{false};
-uint32_t g_socketUDPSendBuffer{0};
-uint32_t g_socketUDPRecvBuffer{0};
-
-std::set<std::string> g_capabilitiesToRetain;
// we are not willing to receive a bigger UDP response than that, no matter what
static constexpr size_t s_maxUDPResponsePacketSize{4096U};
}
}
-static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qnameWireLength)
+static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qnameWireLength, bool addEDNSToSelfGeneratedResponses)
{
try {
bool hadEDNS = false;
uint16_t payloadSize = 0;
uint16_t zValue = 0;
- if (g_addEDNSToSelfGeneratedResponses) {
+ if (addEDNSToSelfGeneratedResponses) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
hadEDNS = getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(packet.data()), packet.size(), &payloadSize, &zValue);
}
static std::unique_ptr<DelayPipe<DelayedPacket>> g_delay{nullptr};
#endif /* DISABLE_DELAY_PIPE */
-std::string DNSQuestion::getTrailingData() const
-{
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- const auto* message = reinterpret_cast<const char*>(this->getData().data());
- const uint16_t messageLen = getDNSPacketLength(message, this->getData().size());
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- return {message + messageLen, this->getData().size() - messageLen};
-}
-
-bool DNSQuestion::setTrailingData(const std::string& tail)
-{
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- const char* message = reinterpret_cast<const char*>(this->data.data());
- const uint16_t messageLen = getDNSPacketLength(message, this->data.size());
- this->data.resize(messageLen);
- if (!tail.empty()) {
- if (!hasRoomFor(tail.size())) {
- return false;
- }
- this->data.insert(this->data.end(), tail.begin(), tail.end());
- }
- return true;
-}
-
-bool DNSQuestion::editHeader(const std::function<bool(dnsheader&)>& editFunction)
-{
- if (data.size() < sizeof(dnsheader)) {
- throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
- }
- return dnsdist::PacketMangling::editDNSHeaderFromPacket(data, editFunction);
-}
-
static void doLatencyStats(dnsdist::Protocol protocol, double udiff)
{
- constexpr auto doAvg = [](double& var, double n, double weight) {
- var = (weight - 1) * var / weight + n / weight;
+ constexpr auto doAvg = [](pdns::stat_double_t& var, double n, double weight) {
+ var.store((weight - 1) * var.load() / weight + n / weight);
};
if (protocol == dnsdist::Protocol::DoUDP || protocol == dnsdist::Protocol::DNSCryptUDP) {
}
}
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse)
{
if (response.size() < sizeof(dnsheader)) {
return false;
}
if (dnsHeader->qdcount == 0) {
- if ((dnsHeader->rcode != RCode::NoError && dnsHeader->rcode != RCode::NXDomain) || g_allowEmptyResponse) {
+ if ((dnsHeader->rcode != RCode::NoError && dnsHeader->rcode != RCode::NXDomain) || allowEmptyResponse) {
return true;
}
return true;
}
- if (g_fixupCase) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_fixupCase) {
const auto& realname = qname.getStorage();
if (response.size() >= (sizeof(dnsheader) + realname.length())) {
memcpy(&response.at(sizeof(dnsheader)), realname.c_str(), realname.length());
header.qr = true;
return true;
});
- truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+ truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
++dnsdist::metrics::g_stats.ruleTruncated;
return true;
}
return true;
}
-bool processResponseAfterRules(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted)
+bool processResponseAfterRules(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
{
bool zeroScope = false;
if (!fixUpResponse(response, dnsResponse.ids.qname, dnsResponse.ids.origFlags, dnsResponse.ids.ednsAdded, dnsResponse.ids.ecsAdded, dnsResponse.ids.useZeroScope ? &zeroScope : nullptr)) {
dnsResponse.ids.packetCache->insert(cacheKey, zeroScope ? boost::none : dnsResponse.ids.subnet, dnsResponse.ids.cacheFlags, dnsResponse.ids.dnssecOK, dnsResponse.ids.qname, dnsResponse.ids.qtype, dnsResponse.ids.qclass, response, dnsResponse.ids.forwardedOverUDP, dnsResponse.getHeader()->rcode, dnsResponse.ids.tempFailureTTL);
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& cacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules);
if (!applyRulesToResponse(cacheInsertedRespRuleActions, dnsResponse)) {
return false;
}
return true;
}
-bool processResponse(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted)
+bool processResponse(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
{
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& respRuleActions = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::ResponseRules);
+
if (!applyRulesToResponse(respRuleActions, dnsResponse)) {
return false;
}
return true;
}
- return processResponseAfterRules(response, cacheInsertedRespRuleActions, dnsResponse, muted);
+ return processResponseAfterRules(response, dnsResponse, muted);
}
static size_t getInitialUDPPacketBufferSize(bool expectProxyProtocol)
{
- static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
+ static_assert(dnsdist::configuration::s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
- if (!expectProxyProtocol || g_proxyProtocolACL.empty()) {
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (!expectProxyProtocol || runtimeConfig.d_proxyProtocolACL.empty()) {
return s_initialUDPPacketBufferSize;
}
- return s_initialUDPPacketBufferSize + g_proxyProtocolMaximumSize;
+ return s_initialUDPPacketBufferSize + runtimeConfig.d_proxyProtocolMaximumSize;
}
static size_t getMaximumIncomingPacketSize(const ClientState& clientState)
return getInitialUDPPacketBufferSize(clientState.d_enableProxyProtocol);
}
- if (!clientState.d_enableProxyProtocol || g_proxyProtocolACL.empty()) {
- return s_udpIncomingBufferSize;
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (!clientState.d_enableProxyProtocol || runtimeConfig.d_proxyProtocolACL.empty()) {
+ return dnsdist::configuration::s_udpIncomingBufferSize;
}
- return s_udpIncomingBufferSize + g_proxyProtocolMaximumSize;
+ return dnsdist::configuration::s_udpIncomingBufferSize + runtimeConfig.d_proxyProtocolMaximumSize;
}
bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
doLatencyStats(incomingProtocol, udiff);
}
-static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, const std::shared_ptr<DownstreamState>& backend, bool isAsync, bool selfGenerated)
+static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& response, const std::shared_ptr<DownstreamState>& backend, bool isAsync, bool selfGenerated)
{
DNSResponse dnsResponse(ids, response, backend);
if (ids.udpPayloadSize > 0 && response.size() > ids.udpPayloadSize) {
vinfolog("Got a response of size %d while the initial UDP payload size was %d, truncating", response.size(), ids.udpPayloadSize);
- truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+ truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsResponse.getMutableData(), [](dnsheader& header) {
header.tc = true;
return true;
});
}
- else if (dnsResponse.getHeader()->tc && g_truncateTC) {
- truncateTC(response, dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+ else if (dnsResponse.getHeader()->tc && dnsdist::configuration::getCurrentRuntimeConfiguration().d_truncateTC) {
+ truncateTC(response, dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
}
/* when the answer is encrypted in place, we need to get a copy
memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
if (!isAsync) {
- if (!processResponse(response, respRuleActions, cacheInsertedRespRuleActions, dnsResponse, ids.cs != nullptr && ids.cs->muted)) {
+ if (!processResponse(response, dnsResponse, ids.cs != nullptr && ids.cs->muted)) {
return;
}
}
}
-bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& localRespRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids)
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, InternalQueryState&& ids)
{
const dnsheader_aligned dnsHeader(response.data());
auto queryId = dnsHeader->id;
- if (!responseContentMatches(response, ids.qname, ids.qtype, ids.qclass, dss)) {
+ if (!responseContentMatches(response, ids.qname, ids.qtype, ids.qclass, dss, dnsdist::configuration::getCurrentRuntimeConfiguration().d_allowEmptyResponse)) {
dss->restoreState(queryId, std::move(ids));
return false;
}
return false;
}
- handleResponseForUDPClient(ids, response, localRespRuleActions, cacheInsertedRespRuleActions, dss, false, false);
+ handleResponseForUDPClient(ids, response, dss, false, false);
return true;
}
{
try {
setThreadName("dnsdist/respond");
- auto localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
- auto localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
const size_t initialBufferSize = getInitialUDPPacketBufferSize(false);
/* allocate one more byte so we can detect truncation */
PacketBuffer response(initialBufferSize + 1);
continue;
}
- if (processResponderPacket(dss, response, *localRespRuleActions, *localCacheInsertedRespRuleActions, std::move(*ids)) && ids->isXSK() && ids->cs->xskInfo) {
+ if (processResponderPacket(dss, response, std::move(*ids)) && ids->isXSK() && ids->cs->xskInfoResponder) {
#ifdef HAVE_XSK
- auto& xskInfo = ids->cs->xskInfo;
+ auto& xskInfo = ids->cs->xskInfoResponder;
auto xskPacket = xskInfo->getEmptyFrame();
if (!xskPacket) {
continue;
}
}
-LockGuarded<LuaContext> g_lua{LuaContext()};
-ComboAddress g_serverControl{"127.0.0.1:5199"};
+RecursiveLockGuarded<LuaContext> g_lua{LuaContext()};
static void spoofResponseFromString(DNSQuestion& dnsQuestion, const string& spoofContent, bool raw)
{
return !drop;
}
-static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, const timespec& now)
+static bool applyRulesToQuery(DNSQuestion& dnsQuestion, const timespec& now)
{
if (g_rings.shouldRecordQueries()) {
g_rings.insertQuery(now, dnsQuestion.ids.origRemote, dnsQuestion.ids.qname, dnsQuestion.ids.qtype, dnsQuestion.getData().size(), *dnsQuestion.getHeader(), dnsQuestion.getProtocol());
}
- if (g_qcount.enabled) {
- string qname = dnsQuestion.ids.qname.toLogString();
- bool countQuery{true};
- if (g_qcount.filter) {
- auto lock = g_lua.lock();
- std::tie(countQuery, qname) = g_qcount.filter(&dnsQuestion);
- }
-
- if (countQuery) {
- auto records = g_qcount.records.write_lock();
- if (records->count(qname) == 0) {
- (*records)[qname] = 0;
+ {
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+ if (runtimeConfig.d_queryCountConfig.d_enabled) {
+ string qname = dnsQuestion.ids.qname.toLogString();
+ bool countQuery{true};
+ if (runtimeConfig.d_queryCountConfig.d_filter) {
+ auto lock = g_lua.lock();
+ std::tie(countQuery, qname) = runtimeConfig.d_queryCountConfig.d_filter(&dnsQuestion);
+ }
+
+ if (countQuery) {
+ auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
+ if (records->count(qname) == 0) {
+ (*records)[qname] = 0;
+ }
+ (*records)[qname]++;
}
- (*records)[qname]++;
}
}
#ifndef DISABLE_DYNBLOCKS
+ const auto defaultDynBlockAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
auto setRCode = [&dnsQuestion](uint8_t rcode) {
dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [rcode](dnsheader& header) {
header.rcode = rcode;
};
/* the Dynamic Block mechanism supports address and port ranges, so we need to pass the full address and port */
- if (auto* got = holders.dynNMGBlock->lookup(AddressAndPortRange(dnsQuestion.ids.origRemote, dnsQuestion.ids.origRemote.isIPv4() ? 32 : 128, 16))) {
+ if (auto* got = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(dnsQuestion.ids.origRemote, dnsQuestion.ids.origRemote.isIPv4() ? 32 : 128, 16))) {
auto updateBlockStats = [&got]() {
++dnsdist::metrics::g_stats.dynBlocked;
got->second.blocks++;
if (now < got->second.until) {
DNSAction::Action action = got->second.action;
if (action == DNSAction::Action::None) {
- action = g_dynBlockAction;
+ action = defaultDynBlockAction;
}
switch (action) {
}
}
- if (auto* got = holders.dynSMTBlock->lookup(dnsQuestion.ids.qname)) {
+ if (auto* got = dnsdist::DynamicBlocks::getSuffixDynamicRules().lookup(dnsQuestion.ids.qname)) {
auto updateBlockStats = [&got]() {
++dnsdist::metrics::g_stats.dynBlocked;
got->blocks++;
if (now < got->until) {
DNSAction::Action action = got->action;
if (action == DNSAction::Action::None) {
- action = g_dynBlockAction;
+ action = defaultDynBlockAction;
}
switch (action) {
case DNSAction::Action::NoOp:
}
#endif /* DISABLE_DYNBLOCKS */
- return applyRulesChainToQuery(*holders.ruleactions, dnsQuestion);
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& queryRules = dnsdist::rules::getRuleChain(chains, dnsdist::rules::RuleChain::Rules);
+ return applyRulesChainToQuery(queryRules, dnsQuestion);
}
ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& backend, const int socketDesc, const PacketBuffer& request, bool healthCheck)
return result;
}
-static bool isUDPQueryAcceptable(ClientState& clientState, LocalHolders& holders, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, bool& expectProxyProtocol)
+static bool isUDPQueryAcceptable(ClientState& clientState, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, bool& expectProxyProtocol)
{
if ((msgh->msg_flags & MSG_TRUNC) != 0) {
/* message was too large for our buffer */
}
expectProxyProtocol = clientState.d_enableProxyProtocol && expectProxyProtocolFrom(remote);
- if (!holders.acl->match(remote) && !expectProxyProtocol) {
+ if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote) && !expectProxyProtocol) {
vinfolog("Query from %s dropped because of ACL", remote.toStringWithPort());
++dnsdist::metrics::g_stats.aclDrops;
return false;
if (dnsHeader.qdcount == 0) {
++dnsdist::metrics::g_stats.emptyQueries;
- if (g_dropEmptyQueries) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_dropEmptyQueries) {
return false;
}
}
#endif
/* self-generated responses or cache hits */
-static bool prepareOutgoingResponse(LocalHolders& holders, const ClientState& clientState, DNSQuestion& dnsQuestion, bool cacheHit)
+static bool prepareOutgoingResponse(const ClientState& clientState, DNSQuestion& dnsQuestion, bool cacheHit)
{
std::shared_ptr<DownstreamState> backend{nullptr};
DNSResponse dnsResponse(dnsQuestion.ids, dnsQuestion.getMutableData(), backend);
dnsResponse.d_incomingTCPState = dnsQuestion.d_incomingTCPState;
dnsResponse.ids.selfGenerated = true;
- if (!applyRulesToResponse(cacheHit ? *holders.cacheHitRespRuleactions : *holders.selfAnsweredRespRuleactions, dnsResponse)) {
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& cacheHitRespRules = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::CacheHitResponseRules);
+ const auto& selfAnsweredRespRules = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::SelfAnsweredResponseRules);
+ if (!applyRulesToResponse(cacheHit ? cacheHitRespRules : selfAnsweredRespRules, dnsResponse)) {
return false;
}
return true;
}
-static ProcessQueryResult handleQueryTurnedIntoSelfAnsweredResponse(DNSQuestion& dnsQuestion, LocalHolders& holders)
+static ProcessQueryResult handleQueryTurnedIntoSelfAnsweredResponse(DNSQuestion& dnsQuestion)
{
fixUpQueryTurnedResponse(dnsQuestion, dnsQuestion.ids.origFlags);
- if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, false)) {
+ if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, false)) {
return ProcessQueryResult::Drop;
}
return ProcessQueryResult::SendAnswer;
}
-static void selectBackendForOutgoingQuery(DNSQuestion& dnsQuestion, const std::shared_ptr<ServerPool>& serverPool, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+static void selectBackendForOutgoingQuery(DNSQuestion& dnsQuestion, const std::shared_ptr<ServerPool>& serverPool, std::shared_ptr<DownstreamState>& selectedBackend)
{
std::shared_ptr<ServerPolicy> poolPolicy = serverPool->policy;
- const auto& policy = poolPolicy != nullptr ? *poolPolicy : *(holders.policy);
+ const auto& policy = poolPolicy != nullptr ? *poolPolicy : *dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
const auto servers = serverPool->getServers();
selectedBackend = policy.getSelectedBackend(*servers, dnsQuestion);
}
-ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
{
const uint16_t queryId = ntohs(dnsQuestion.getHeader()->id);
try {
if (dnsQuestion.getHeader()->qr) { // something turned it into a response
- return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion, holders);
+ return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion);
}
- std::shared_ptr<ServerPool> serverPool = getPool(*holders.pools, dnsQuestion.ids.poolName);
+ std::shared_ptr<ServerPool> serverPool = getPool(dnsQuestion.ids.poolName);
dnsQuestion.ids.packetCache = serverPool->packetCache;
- selectBackendForOutgoingQuery(dnsQuestion, serverPool, holders, selectedBackend);
+ selectBackendForOutgoingQuery(dnsQuestion, serverPool, selectedBackend);
- uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL;
+ uint32_t allowExpired = selectedBackend ? 0 : dnsdist::configuration::getCurrentRuntimeConfiguration().d_staleCacheEntriesTTL;
if (dnsQuestion.ids.packetCache && !dnsQuestion.ids.skipCache) {
- dnsQuestion.ids.dnssecOK = (getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0;
+ dnsQuestion.ids.dnssecOK = (dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0;
}
if (dnsQuestion.useECS && ((selectedBackend && selectedBackend->d_config.useECS) || (!selectedBackend && serverPool->getECS()))) {
vinfolog("Packet cache hit for query for %s|%s from %s (%s, %d bytes)", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort(), dnsQuestion.ids.protocol.toString(), dnsQuestion.getData().size());
- if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, true)) {
+ if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, true)) {
return ProcessQueryResult::Drop;
}
vinfolog("Packet cache hit for query for %s|%s from %s (%s, %d bytes)", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort(), dnsQuestion.ids.protocol.toString(), dnsQuestion.getData().size());
- if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, true)) {
+ if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, true)) {
return ProcessQueryResult::Drop;
}
if (dnsQuestion.ids.protocol == dnsdist::Protocol::DoH && !forwardedOverUDP) {
/* do a second-lookup for UDP responses, but we do not want TC=1 answers */
if (dnsQuestion.ids.packetCache->get(dnsQuestion, dnsQuestion.getHeader()->id, &dnsQuestion.ids.cacheKeyUDP, dnsQuestion.ids.subnet, dnsQuestion.ids.dnssecOK, true, allowExpired, false, false, true)) {
- if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, true)) {
+ if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, true)) {
return ProcessQueryResult::Drop;
}
++dnsdist::metrics::g_stats.cacheMisses;
+ //coverity[auto_causes_copy]
const auto existingPool = dnsQuestion.ids.poolName;
- if (!applyRulesChainToQuery(*holders.cacheMissRuleActions, dnsQuestion)) {
+ const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+ const auto& cacheMissRuleActions = dnsdist::rules::getRuleChain(chains, dnsdist::rules::RuleChain::CacheMissRules);
+
+ if (!applyRulesChainToQuery(cacheMissRuleActions, dnsQuestion)) {
return ProcessQueryResult::Drop;
}
if (dnsQuestion.getHeader()->qr) { // something turned it into a response
- return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion, holders);
+ return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion);
}
/* let's be nice and allow the selection of a different pool,
but no second cache-lookup for you */
if (dnsQuestion.ids.poolName != existingPool) {
- serverPool = getPool(*holders.pools, dnsQuestion.ids.poolName);
+ serverPool = getPool(dnsQuestion.ids.poolName);
dnsQuestion.ids.packetCache = serverPool->packetCache;
- selectBackendForOutgoingQuery(dnsQuestion, serverPool, holders, selectedBackend);
+ selectBackendForOutgoingQuery(dnsQuestion, serverPool, selectedBackend);
}
}
if (!selectedBackend) {
+ auto servFailOnNoPolicy = dnsdist::configuration::getCurrentRuntimeConfiguration().d_servFailOnNoPolicy;
++dnsdist::metrics::g_stats.noPolicy;
- vinfolog("%s query for %s|%s from %s, no downstream server available", g_servFailOnNoPolicy ? "ServFailed" : "Dropped", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort());
- if (g_servFailOnNoPolicy) {
+ vinfolog("%s query for %s|%s from %s, no downstream server available", servFailOnNoPolicy ? "ServFailed" : "Dropped", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort());
+ if (servFailOnNoPolicy) {
dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [](dnsheader& header) {
header.rcode = RCode::ServFail;
header.qr = true;
fixUpQueryTurnedResponse(dnsQuestion, dnsQuestion.ids.origFlags);
- if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, false)) {
+ if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, false)) {
return ProcessQueryResult::Drop;
}
++dnsdist::metrics::g_stats.responses;
auto& ids = response.d_idstate;
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
- handleResponseForUDPClient(ids, response.d_buffer, *localRespRuleActions, *localCacheInsertedRespRuleActions, response.d_ds, response.isAsync(), response.d_idstate.selfGenerated);
+ handleResponseForUDPClient(ids, response.d_buffer, response.d_ds, response.isAsync(), response.d_idstate.selfGenerated);
}
void handleXFRResponse(const struct timeval& now, TCPResponse&& response) override
return std::make_unique<UDPCrossProtocolQuery>(std::move(dnsQuestion.getMutableData()), std::move(dnsQuestion.ids), nullptr);
}
-ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
{
const uint16_t queryId = ntohs(dnsQuestion.getHeader()->id);
header.qr = true;
return true;
});
- return processQueryAfterRules(dnsQuestion, holders, selectedBackend);
+ return processQueryAfterRules(dnsQuestion, selectedBackend);
}
- if (!applyRulesToQuery(holders, dnsQuestion, now)) {
+ if (!applyRulesToQuery(dnsQuestion, now)) {
return ProcessQueryResult::Drop;
}
return ProcessQueryResult::Asynchronous;
}
- return processQueryAfterRules(dnsQuestion, holders, selectedBackend);
+ return processQueryAfterRules(dnsQuestion, selectedBackend);
}
catch (const std::exception& e) {
vinfolog("Got an error while parsing a %s query from %s, id %d: %s", (dnsQuestion.overTCP() ? "TCP" : "UDP"), dnsQuestion.ids.origRemote.toStringWithPort(), queryId, e.what());
return true;
}
-static void processUDPQuery(ClientState& clientState, LocalHolders& holders, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, PacketBuffer& query, std::vector<mmsghdr>* responsesVect, unsigned int* queuedResponses, struct iovec* respIOV, cmsgbuf_aligned* respCBuf)
+static void processUDPQuery(ClientState& clientState, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, PacketBuffer& query, std::vector<mmsghdr>* responsesVect, unsigned int* queuedResponses, struct iovec* respIOV, cmsgbuf_aligned* respCBuf)
{
assert(responsesVect == nullptr || (queuedResponses != nullptr && respIOV != nullptr && respCBuf != nullptr));
uint16_t queryId = 0;
try {
bool expectProxyProtocol = false;
- if (!isUDPQueryAcceptable(clientState, holders, msgh, remote, dest, expectProxyProtocol)) {
+ if (!isUDPQueryAcceptable(clientState, msgh, remote, dest, expectProxyProtocol)) {
return;
}
/* dest might have been updated, if we managed to harvest the destination address */
}
std::vector<ProxyProtocolValue> proxyProtocolValues;
- if (expectProxyProtocol && !handleProxyProtocol(remote, false, *holders.acl, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
+ if (expectProxyProtocol && !handleProxyProtocol(remote, false, dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
return;
}
}
std::shared_ptr<DownstreamState> backend{nullptr};
- auto result = processQuery(dnsQuestion, holders, backend);
+ auto result = processQuery(dnsQuestion, backend);
if (result == ProcessQueryResult::Drop || result == ProcessQueryResult::Asynchronous) {
return;
#ifdef HAVE_XSK
namespace dnsdist::xsk
{
-bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket& packet)
+bool XskProcessQuery(ClientState& clientState, XskPacket& packet)
{
uint16_t queryId = 0;
const auto& remote = packet.getFromAddr();
try {
bool expectProxyProtocol = false;
- if (!XskIsQueryAcceptable(packet, clientState, holders, expectProxyProtocol)) {
+ if (!XskIsQueryAcceptable(packet, clientState, expectProxyProtocol)) {
return false;
}
auto query = packet.clonePacketBuffer();
std::vector<ProxyProtocolValue> proxyProtocolValues;
- if (expectProxyProtocol && !handleProxyProtocol(remote, false, *holders.acl, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
+ if (expectProxyProtocol && !handleProxyProtocol(remote, false, dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
return false;
}
dnsQuestion.proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(std::move(proxyProtocolValues));
}
std::shared_ptr<DownstreamState> backend{nullptr};
- auto result = processQuery(dnsQuestion, holders, backend);
+ auto result = processQuery(dnsQuestion, backend);
if (result == ProcessQueryResult::Drop) {
return false;
#ifndef DISABLE_RECVMMSG
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
-static void MultipleMessagesUDPClientThread(ClientState* clientState, LocalHolders& holders)
+static void MultipleMessagesUDPClientThread(ClientState* clientState)
{
struct MMReceiver
{
/* used by HarvestDestinationAddress */
cmsgbuf_aligned cbuf{};
};
- const size_t vectSize = g_udpVectorSize;
+ const size_t vectSize = dnsdist::configuration::getImmutableConfiguration().d_udpVectorSize;
if (vectSize > std::numeric_limits<uint16_t>::max()) {
throw std::runtime_error("The value of setUDPMultipleMessagesVectorSize is too high, the maximum value is " + std::to_string(std::numeric_limits<uint16_t>::max()));
}
recvData[msgIdx].packet.resize(got);
- processUDPQuery(*clientState, holders, msgh, remote, recvData[msgIdx].dest, recvData[msgIdx].packet, &outMsgVec, &msgsToSend, &recvData[msgIdx].iov, &recvData[msgIdx].cbuf);
+ processUDPQuery(*clientState, msgh, remote, recvData[msgIdx].dest, recvData[msgIdx].packet, &outMsgVec, &msgsToSend, &recvData[msgIdx].iov, &recvData[msgIdx].cbuf);
}
/* immediate (not delayed or sent to a backend) responses (mostly from a rule, dynamic block
{
try {
setThreadName("dnsdist/udpClie");
- LocalHolders holders;
#ifndef DISABLE_RECVMMSG
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
- if (g_udpVectorSize > 1) {
- MultipleMessagesUDPClientThread(states.at(0), holders);
+ if (dnsdist::configuration::getImmutableConfiguration().d_udpVectorSize > 1) {
+ MultipleMessagesUDPClientThread(states.at(0));
}
else
#endif /* defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE) */
ComboAddress remote;
ComboAddress dest;
- auto handleOnePacket = [&packet, &iov, &holders, &msgh, &remote, &dest, initialBufferSize](const UDPStateParam& param) {
+ auto handleOnePacket = [&packet, &iov, &msgh, &remote, &dest, initialBufferSize](const UDPStateParam& param) {
packet.resize(initialBufferSize);
iov.iov_base = &packet.at(0);
iov.iov_len = packet.size();
packet.resize(static_cast<size_t>(got));
- processUDPQuery(*param.cs, holders, &msgh, remote, dest, packet, nullptr, nullptr, nullptr, nullptr);
+ processUDPQuery(*param.cs, &msgh, remote, dest, packet, nullptr, nullptr, nullptr, nullptr);
};
std::vector<UDPStateParam> params;
}
}
-boost::optional<uint64_t> g_maxTCPClientThreads{boost::none};
-pdns::stat16_t g_cacheCleaningDelay{60};
-pdns::stat16_t g_cacheCleaningPercentage{100};
-
static void maintThread()
{
setThreadName("dnsdist/main");
}
counter++;
- if (counter >= g_cacheCleaningDelay) {
+ if (counter >= dnsdist::configuration::getCurrentRuntimeConfiguration().d_cacheCleaningDelay) {
/* keep track, for each cache, of whether we should keep
expired entries */
std::map<std::shared_ptr<DNSDistPacketCache>, bool> caches;
/* gather all caches actually used by at least one pool, and see
if something prevents us from cleaning the expired entries */
- auto localPools = g_pools.getLocal();
- for (const auto& entry : *localPools) {
+ const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+ for (const auto& entry : pools) {
const auto& pool = entry.second;
auto packetCache = pool->packetCache;
continue;
}
const auto& packetCache = pair.first;
- size_t upTo = (packetCache->getMaxEntries() * (100 - g_cacheCleaningPercentage)) / 100;
+ size_t upTo = (packetCache->getMaxEntries() * (100 - dnsdist::configuration::getCurrentRuntimeConfiguration().d_cacheCleaningPercentage)) / 100;
packetCache->purgeExpired(upTo, now);
}
counter = 0;
setThreadName("dnsdist/secpoll");
for (;;) {
+ const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+
try {
- doSecPoll(g_secPollSuffix);
+ dnsdist::secpoll::doSecPoll(runtimeConfig.d_secPollSuffix);
}
catch (...) {
}
// coverity[store_truncates_time_t]
- std::this_thread::sleep_for(std::chrono::seconds(g_secPollInterval));
+ std::this_thread::sleep_for(std::chrono::seconds(runtimeConfig.d_secPollInterval));
}
}
#endif /* DISABLE_SECPOLL */
.tv_sec = 0,
.tv_usec = 0
};
- auto states = g_dstates.getLocal(); // this points to the actual shared_ptrs!
for (;;) {
timeval now{};
}
std::unique_ptr<FDMultiplexer> mplexer{nullptr};
- for (const auto& dss : *states) {
+ // this points to the actual shared_ptrs!
+ //coverity[auto_causes_copy]
+ const auto servers = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
+ for (const auto& dss : servers) {
dss->updateStatisticsInfo();
dss->handleUDPTimeouts();
}
if (!mplexer) {
- mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(states->size()));
+ mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(servers.size()));
}
if (!queueHealthCheck(mplexer, dss)) {
static void checkFileDescriptorsLimits(size_t udpBindsCount, size_t tcpBindsCount)
{
+ const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
/* stdin, stdout, stderr */
rlim_t requiredFDsCount = 3;
- auto backends = g_dstates.getLocal();
+ const auto& backends = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
/* UDP sockets to backends */
size_t backendUDPSocketsCount = 0;
- for (const auto& backend : *backends) {
+ for (const auto& backend : backends) {
backendUDPSocketsCount += backend->sockets.size();
}
requiredFDsCount += backendUDPSocketsCount;
/* TCP sockets to backends */
- if (g_maxTCPClientThreads) {
- requiredFDsCount += (backends->size() * (*g_maxTCPClientThreads));
+ if (immutableConfig.d_maxTCPClientThreads > 0) {
+ requiredFDsCount += (backends.size() * immutableConfig.d_maxTCPClientThreads);
}
/* listening sockets */
requiredFDsCount += udpBindsCount;
requiredFDsCount += tcpBindsCount;
/* number of TCP connections currently served, assuming 1 connection per worker thread which is of course not right */
- if (g_maxTCPClientThreads) {
- requiredFDsCount += *g_maxTCPClientThreads;
+ if (immutableConfig.d_maxTCPClientThreads > 0) {
+ requiredFDsCount += immutableConfig.d_maxTCPClientThreads;
/* max pipes for communicating between TCP acceptors and client threads */
- requiredFDsCount += (*g_maxTCPClientThreads * 2);
+ requiredFDsCount += (immutableConfig.d_maxTCPClientThreads * 2);
}
/* max TCP queued connections */
- requiredFDsCount += g_maxTCPQueuedConnections;
+ requiredFDsCount += immutableConfig.d_maxTCPQueuedConnections;
/* DelayPipe pipe */
requiredFDsCount += 2;
/* syslog socket */
}
}
-static bool g_warned_ipv6_recvpktinfo = false;
-
static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr, int& socket, bool tcp, bool warn)
{
+ const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
+ static bool s_warned_ipv6_recvpktinfo = false;
(void)warn;
socket = SSocket(addr.sin4.sin_family, !tcp ? SOCK_DGRAM : SOCK_STREAM, 0);
#ifdef TCP_FASTOPEN
SSetsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, clientState.fastOpenQueueSize);
#ifdef TCP_FASTOPEN_KEY
- if (!g_TCPFastOpenKey.empty()) {
- auto res = setsockopt(socket, IPPROTO_IP, TCP_FASTOPEN_KEY, g_TCPFastOpenKey.data(), g_TCPFastOpenKey.size() * sizeof(g_TCPFastOpenKey[0]));
+ if (!immutableConfig.d_tcpFastOpenKey.empty()) {
+ auto res = setsockopt(socket, IPPROTO_IP, TCP_FASTOPEN_KEY, immutableConfig.d_tcpFastOpenKey.data(), immutableConfig.d_tcpFastOpenKey.size() * sizeof(immutableConfig.d_tcpFastOpenKey[0]));
if (res == -1) {
throw runtime_error("setsockopt for level IPPROTO_TCP and opname TCP_FASTOPEN_KEY failed: " + stringerror());
}
int one = 1;
(void)setsockopt(socket, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
#ifdef IPV6_RECVPKTINFO
- if (addr.isIPv6() && setsockopt(socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)) < 0 && !g_warned_ipv6_recvpktinfo) {
+ if (addr.isIPv6() && setsockopt(socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)) < 0 && !s_warned_ipv6_recvpktinfo) {
warnlog("Warning: IPV6_RECVPKTINFO setsockopt failed: %s", stringerror());
- g_warned_ipv6_recvpktinfo = true;
+ s_warned_ipv6_recvpktinfo = true;
}
#endif
}
}
if (!tcp) {
- if (g_socketUDPSendBuffer > 0) {
+ if (immutableConfig.d_socketUDPSendBuffer > 0) {
try {
- setSocketSendBuffer(socket, g_socketUDPSendBuffer);
+ setSocketSendBuffer(socket, immutableConfig.d_socketUDPSendBuffer);
}
catch (const std::exception& e) {
warnlog(e.what());
}
}
- if (g_socketUDPRecvBuffer > 0) {
+ if (immutableConfig.d_socketUDPRecvBuffer > 0) {
try {
- setSocketReceiveBuffer(socket, g_socketUDPRecvBuffer);
+ setSocketReceiveBuffer(socket, immutableConfig.d_socketUDPRecvBuffer);
}
catch (const std::exception& e) {
warnlog(e.what());
}
}
-static void setUpLocalBind(std::unique_ptr<ClientState>& cstate)
+static void setUpLocalBind(ClientState& cstate)
{
/* skip some warnings if there is an identical UDP context */
- bool warn = !cstate->tcp || cstate->tlsFrontend != nullptr || cstate->dohFrontend != nullptr;
- int& descriptor = !cstate->tcp ? cstate->udpFD : cstate->tcpFD;
+ bool warn = !cstate.tcp || cstate.tlsFrontend != nullptr || cstate.dohFrontend != nullptr;
+ int& descriptor = !cstate.tcp ? cstate.udpFD : cstate.tcpFD;
(void)warn;
- setupLocalSocket(*cstate, cstate->local, descriptor, cstate->tcp, warn);
+ setupLocalSocket(cstate, cstate.local, descriptor, cstate.tcp, warn);
- for (auto& [addr, socket] : cstate->d_additionalAddresses) {
- setupLocalSocket(*cstate, addr, socket, true, false);
+ for (auto& [addr, socket] : cstate.d_additionalAddresses) {
+ setupLocalSocket(cstate, addr, socket, true, false);
}
- if (cstate->tlsFrontend != nullptr) {
- if (!cstate->tlsFrontend->setupTLS()) {
- errlog("Error while setting up TLS on local address '%s', exiting", cstate->local.toStringWithPort());
+ if (cstate.tlsFrontend != nullptr) {
+ if (!cstate.tlsFrontend->setupTLS()) {
+ errlog("Error while setting up TLS on local address '%s', exiting", cstate.local.toStringWithPort());
_exit(EXIT_FAILURE);
}
}
- if (cstate->dohFrontend != nullptr) {
- cstate->dohFrontend->setup();
+ if (cstate.dohFrontend != nullptr) {
+ cstate.dohFrontend->setup();
}
- if (cstate->doqFrontend != nullptr) {
- cstate->doqFrontend->setup();
+ if (cstate.doqFrontend != nullptr) {
+ cstate.doqFrontend->setup();
}
- if (cstate->doh3Frontend != nullptr) {
- cstate->doh3Frontend->setup();
+ if (cstate.doh3Frontend != nullptr) {
+ cstate.doh3Frontend->setup();
}
- cstate->ready = true;
+ cstate.ready = true;
}
-struct
+struct CommandLineParameters
{
vector<string> locals;
vector<string> remotes;
string config;
string uid;
string gid;
-} g_cmdLine;
-
-std::atomic<bool> g_configurationDone{false};
+};
static void usage()
{
{
/* when our coverage mode is enabled, we need to make sure
that the Lua objects are destroyed before the Lua contexts. */
- for (const auto& chain : dnsdist::rules::getRuleChains()) {
- chain.holder.setState({});
- }
- for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
- chain.holder.setState({});
- }
- g_dstates.setState({});
- g_policy.setState(ServerPolicy());
- g_pools.setState({});
- clearWebHandlers();
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_ruleChains = dnsdist::rules::RuleChains();
+ config.d_lbPolicy = std::make_shared<ServerPolicy>();
+ config.d_pools.clear();
+ config.d_backends.clear();
+ });
+ dnsdist::webserver::clearWebHandlers();
dnsdist::lua::hooks::clearMaintenanceHooks();
}
#endif /* defined(COVERAGE) || (defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE)) */
if (dnsdist::g_asyncHolder) {
dnsdist::g_asyncHolder->stop();
}
+
+ for (auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
+ backend->stop();
+ }
+
{
auto lock = g_lua.lock();
cleanupLuaObjects();
cout << "systemd";
#endif
cout << endl;
+// NOLINTBEGIN(cppcoreguidelines-macro-usage)
+#ifdef DNSDIST_CONFIG_ARGS
+#define double_escape(s) #s
+#define escape_quotes(s) double_escape(s)
+ // NOLINTEND(cppcoreguidelines-macro-usage)
+ cout << "Configured with: " << escape_quotes(DNSDIST_CONFIG_ARGS) << endl;
+#undef escape_quotes
+#undef double_escape
+#endif
}
-static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
+static void parseParameters(int argc, char** argv, CommandLineParameters& cmdLine, ComboAddress& clientAddress)
{
const std::array<struct option, 16> longopts{{{"acl", required_argument, nullptr, 'a'},
{"check-config", no_argument, nullptr, 1},
{nullptr, 0, nullptr, 0}}};
int longindex = 0;
string optstring;
+ dnsdist::configuration::RuntimeConfiguration newConfig;
+
while (true) {
// NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
int gotChar = getopt_long(argc, argv, "a:cC:e:g:hk:l:u:vV", longopts.data(), &longindex);
}
switch (gotChar) {
case 1:
- g_cmdLine.checkConfig = true;
+ cmdLine.checkConfig = true;
break;
case 2:
dnsdist::logging::LoggingConfiguration::setSyslog(false);
break;
case 3:
- g_cmdLine.beSupervised = true;
+ cmdLine.beSupervised = true;
break;
case 4:
dnsdist::logging::LoggingConfiguration::setLogTimestamps(true);
break;
case 'C':
- g_cmdLine.config = optarg;
+ cmdLine.config = optarg;
break;
case 'c':
- g_cmdLine.beClient = true;
+ cmdLine.beClient = true;
break;
case 'e':
- g_cmdLine.command = optarg;
+ cmdLine.command = optarg;
break;
case 'g':
- g_cmdLine.gid = optarg;
+ cmdLine.gid = optarg;
break;
case 'h':
cout << "dnsdist " << VERSION << endl;
break;
case 'a':
optstring = optarg;
- g_ACL.modify([optstring](NetmaskGroup& nmg) { nmg.addMask(optstring); });
+ newConfig.d_ACL.addMask(optstring);
break;
case 'k':
#if defined HAVE_LIBSODIUM || defined(HAVE_LIBCRYPTO)
- if (B64Decode(string(optarg), g_consoleKey) < 0) {
+ {
+ std::string consoleKey;
+ if (B64Decode(string(optarg), consoleKey) < 0) {
cerr << "Unable to decode key '" << optarg << "'." << endl;
// NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
exit(EXIT_FAILURE);
}
+ dnsdist::configuration::updateRuntimeConfiguration([&consoleKey](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_consoleKey = std::move(consoleKey);
+ });
+ }
#else
cerr << "dnsdist has been built without libsodium or libcrypto, -k/--setkey is unsupported." << endl;
// NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
exit(EXIT_FAILURE);
#endif
- break;
+ break;
case 'l':
- g_cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
+ cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
break;
case 'u':
- g_cmdLine.uid = optarg;
+ cmdLine.uid = optarg;
break;
case 'v':
- g_verbose = true;
+ newConfig.d_verbose = true;
break;
case 'V':
reportFeatures();
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): argv
for (const auto* ptr = argv; *ptr != nullptr; ++ptr) {
- if (g_cmdLine.beClient) {
+ if (cmdLine.beClient) {
clientAddress = ComboAddress(*ptr, 5199);
}
else {
- g_cmdLine.remotes.emplace_back(*ptr);
+ cmdLine.remotes.emplace_back(*ptr);
}
}
+
+ dnsdist::configuration::updateRuntimeConfiguration([&newConfig](dnsdist::configuration::RuntimeConfiguration& config) {
+ config = std::move(newConfig);
+ });
}
static void setupPools()
{
- auto pools = g_pools.getCopy();
- {
- bool precompute = false;
- if (g_policy.getLocal()->getName() == "chashed") {
- precompute = true;
- }
- else {
- for (const auto& entry : pools) {
- if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") {
- precompute = true;
- break;
- }
+ bool precompute = false;
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName() == "chashed") {
+ precompute = true;
+ }
+ else {
+ for (const auto& entry : dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools) {
+ if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") {
+ precompute = true;
+ break;
}
}
- if (precompute) {
- vinfolog("Pre-computing hashes for consistent hash load-balancing policy");
- // pre compute hashes
- auto backends = g_dstates.getLocal();
- for (const auto& backend : *backends) {
- if (backend->d_config.d_weight < 100) {
- vinfolog("Warning, the backend '%s' has a very low weight (%d), which will not yield a good distribution of queries with the 'chashed' policy. Please consider raising it to at least '100'.", backend->getName(), backend->d_config.d_weight);
- }
-
- backend->hash();
+ }
+ if (precompute) {
+ vinfolog("Pre-computing hashes for consistent hash load-balancing policy");
+ // pre compute hashes
+ for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
+ if (backend->d_config.d_weight < 100) {
+ vinfolog("Warning, the backend '%s' has a very low weight (%d), which will not yield a good distribution of queries with the 'chashed' policy. Please consider raising it to at least '100'.", backend->getName(), backend->d_config.d_weight);
}
+
+ backend->hash();
}
}
}
-static void dropPrivileges()
+static void dropPrivileges(const CommandLineParameters& cmdLine)
{
uid_t newgid = getegid();
gid_t newuid = geteuid();
- if (!g_cmdLine.gid.empty()) {
- newgid = strToGID(g_cmdLine.gid);
+ if (!cmdLine.gid.empty()) {
+ newgid = strToGID(cmdLine.gid);
}
- if (!g_cmdLine.uid.empty()) {
- newuid = strToUID(g_cmdLine.uid);
+ if (!cmdLine.uid.empty()) {
+ newuid = strToUID(cmdLine.uid);
}
bool retainedCapabilities = true;
- if (!g_capabilitiesToRetain.empty() && (getegid() != newgid || geteuid() != newuid)) {
+ if (!dnsdist::configuration::getImmutableConfiguration().d_capabilitiesToRetain.empty() && (getegid() != newgid || geteuid() != newuid)) {
retainedCapabilities = keepCapabilitiesAfterSwitchingIDs();
}
or as an unprivileged user with ambient
capabilities like CAP_NET_BIND_SERVICE.
*/
- dropCapabilities(g_capabilitiesToRetain);
+ dropCapabilities(dnsdist::configuration::getImmutableConfiguration().d_capabilitiesToRetain);
}
catch (const std::exception& e) {
warnlog("%s", e.what());
}
}
-static void initFrontends()
+static void initFrontends(const CommandLineParameters& cmdLine)
{
- if (!g_cmdLine.locals.empty()) {
- for (auto it = g_frontends.begin(); it != g_frontends.end();) {
+ auto frontends = dnsdist::configuration::getImmutableConfiguration().d_frontends;
+
+ if (!cmdLine.locals.empty()) {
+ for (auto it = frontends.begin(); it != frontends.end();) {
/* DoH, DoT and DNSCrypt frontends are separate */
if ((*it)->dohFrontend == nullptr && (*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr && (*it)->doqFrontend == nullptr && (*it)->doh3Frontend == nullptr) {
- it = g_frontends.erase(it);
+ it = frontends.erase(it);
}
else {
++it;
}
}
- for (const auto& loc : g_cmdLine.locals) {
+ for (const auto& loc : cmdLine.locals) {
/* UDP */
- g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}, true));
+ frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}, true));
/* TCP */
- g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}, true));
+ frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}, true));
}
}
- if (g_frontends.empty()) {
+ if (frontends.empty()) {
/* UDP */
- g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}, true));
+ frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}, true));
/* TCP */
- g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}, true));
+ frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}, true));
}
+
+ dnsdist::configuration::updateImmutableConfiguration([&frontends](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_frontends = std::move(frontends);
+ });
}
namespace dnsdist
std::vector<ClientState*> tcpStates;
std::vector<ClientState*> udpStates;
- for (auto& clientState : g_frontends) {
+ for (const auto& clientState : dnsdist::getFrontends()) {
#ifdef HAVE_XSK
if (clientState->xskInfo) {
dnsdist::xsk::addDestinationAddress(clientState->local);
}
}
+struct ListeningSockets
+{
+ Socket d_consoleSocket{-1};
+ Socket d_webServerSocket{-1};
+};
+
+static ListeningSockets initListeningSockets()
+{
+ ListeningSockets result;
+ const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+
+ if (currentConfig.d_consoleEnabled) {
+ const auto& local = currentConfig.d_consoleServerAddress;
+ try {
+ result.d_consoleSocket = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+ result.d_consoleSocket.bind(local, true);
+ result.d_consoleSocket.listen(5);
+ }
+ catch (const std::exception& exp) {
+ errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), exp.what());
+ }
+ }
+
+ if (currentConfig.d_webServerAddress) {
+ const auto& local = *currentConfig.d_webServerAddress;
+ try {
+ result.d_webServerSocket = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+ result.d_webServerSocket.bind(local, true);
+ result.d_webServerSocket.listen(5);
+ }
+ catch (const std::exception& exp) {
+ errlog("Unable to bind to web server socket on %s: %s", local.toStringWithPort(), exp.what());
+ }
+ }
+
+ return result;
+}
+
int main(int argc, char** argv)
{
try {
+ CommandLineParameters cmdLine{};
size_t udpBindsCount = 0;
size_t tcpBindsCount = 0;
-#ifdef HAVE_LIBEDIT
-#ifndef DISABLE_COMPLETION
- rl_attempted_completion_function = my_completion;
- rl_completion_append_character = 0;
-#endif /* DISABLE_COMPLETION */
-#endif /* HAVE_LIBEDIT */
+
+ dnsdist::console::setupCompletion();
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast): SIG_IGN macro
signal(SIGPIPE, SIG_IGN);
}
#endif
dnsdist::initRandom();
- g_hashperturb = dnsdist::getRandomValue(0xffffffff);
+ dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_hashPerturbation = dnsdist::getRandomValue(0xffffffff);
+ });
#ifdef HAVE_XSK
try {
#endif /* HAVE_XSK */
ComboAddress clientAddress = ComboAddress();
- g_cmdLine.config = SYSCONFDIR "/dnsdist.conf";
+ cmdLine.config = SYSCONFDIR "/dnsdist.conf";
- parseParameters(argc, argv, clientAddress);
+ parseParameters(argc, argv, cmdLine, clientAddress);
- ServerPolicy leastOutstandingPol{"leastOutstanding", leastOutstanding, false};
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::make_shared<ServerPolicy>("leastOutstanding", leastOutstanding, false);
+ });
- g_policy.setState(leastOutstandingPol);
- if (g_cmdLine.beClient || !g_cmdLine.command.empty()) {
- setupLua(*(g_lua.lock()), true, false, g_cmdLine.config);
+ if (cmdLine.beClient || !cmdLine.command.empty()) {
+ setupLua(*(g_lua.lock()), true, false, cmdLine.config);
if (clientAddress != ComboAddress()) {
- g_serverControl = clientAddress;
+ dnsdist::configuration::updateRuntimeConfiguration([&clientAddress](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_consoleServerAddress = clientAddress;
+ });
}
- doClient(g_serverControl, g_cmdLine.command);
+ dnsdist::console::doClient(cmdLine.command);
#ifdef COVERAGE
exit(EXIT_SUCCESS);
#else
#endif
}
- auto acl = g_ACL.getCopy();
- if (acl.empty()) {
- for (const auto& addr : {"127.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "169.254.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "::1/128", "fc00::/7", "fe80::/10"}) {
- acl.addMask(addr);
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ auto& acl = config.d_ACL;
+ if (acl.empty()) {
+ for (const auto& addr : {"127.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "169.254.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "::1/128", "fc00::/7", "fe80::/10"}) {
+ acl.addMask(addr);
+ }
}
- g_ACL.setState(acl);
- }
+ for (const auto& mask : {"127.0.0.1/8", "::1/128"}) {
+ config.d_consoleACL.addMask(mask);
+ }
+ config.d_webServerACL.toMasks("127.0.0.1, ::1");
+ });
- auto consoleACL = g_consoleACL.getCopy();
- for (const auto& mask : {"127.0.0.1/8", "::1/128"}) {
- consoleACL.addMask(mask);
- }
- g_consoleACL.setState(consoleACL);
- registerBuiltInWebHandlers();
+ dnsdist::webserver::registerBuiltInWebHandlers();
- if (g_cmdLine.checkConfig) {
- setupLua(*(g_lua.lock()), false, true, g_cmdLine.config);
+ if (cmdLine.checkConfig) {
+ setupLua(*(g_lua.lock()), false, true, cmdLine.config);
// No exception was thrown
- infolog("Configuration '%s' OK!", g_cmdLine.config);
+ infolog("Configuration '%s' OK!", cmdLine.config);
#ifdef COVERAGE
cleanupLuaObjects();
exit(EXIT_SUCCESS);
dnsdist::g_asyncHolder = std::make_unique<dnsdist::AsynchronousHolder>();
- auto todo = setupLua(*(g_lua.lock()), false, false, g_cmdLine.config);
-
- setupPools();
-
- initFrontends();
+ /* create the default pool no matter what */
+ createPoolIfNotExists("");
- g_configurationDone = true;
+ setupLua(*(g_lua.lock()), false, false, cmdLine.config);
- g_rings.init();
+ setupPools();
- for (auto& frontend : g_frontends) {
- setUpLocalBind(frontend);
+ initFrontends(cmdLine);
+ for (const auto& frontend : dnsdist::getFrontends()) {
if (!frontend->tcp) {
++udpBindsCount;
}
}
}
+ if (dnsdist::configuration::getImmutableConfiguration().d_maxTCPClientThreads == 0 && tcpBindsCount > 0) {
+ dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::ImmutableConfiguration& config) {
+ config.d_maxTCPClientThreads = static_cast<size_t>(10);
+ });
+ }
+
+ dnsdist::configuration::setImmutableConfigurationDone();
+
+ {
+ const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
+ setTCPDownstreamMaxIdleConnectionsPerBackend(immutableConfig.d_outgoingTCPMaxIdlePerBackend);
+ setTCPDownstreamMaxIdleTime(immutableConfig.d_outgoingTCPMaxIdleTime);
+ setTCPDownstreamCleanupInterval(immutableConfig.d_outgoingTCPCleanupInterval);
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ setDoHDownstreamMaxIdleConnectionsPerBackend(immutableConfig.d_outgoingDoHMaxIdlePerBackend);
+ setDoHDownstreamMaxIdleTime(immutableConfig.d_outgoingDoHMaxIdleTime);
+ setDoHDownstreamCleanupInterval(immutableConfig.d_outgoingDoHCleanupInterval);
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
+ }
+
+ {
+ const auto& config = dnsdist::configuration::getImmutableConfiguration();
+ g_rings.init(config.d_ringsCapacity, config.d_ringsNumberOfShards, config.d_ringsNbLockTries, config.d_ringsRecordQueries, config.d_ringsRecordResponses);
+ }
+
+ for (const auto& frontend : dnsdist::getFrontends()) {
+ setUpLocalBind(*frontend);
+ }
+
{
std::string acls;
- auto aclEntries = g_ACL.getLocal()->toStringVector();
+ auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.toStringVector();
for (const auto& aclEntry : aclEntries) {
if (!acls.empty()) {
acls += ", ";
}
{
std::string acls;
- auto aclEntries = g_consoleACL.getLocal()->toStringVector();
+ auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleACL.toStringVector();
for (const auto& entry : aclEntries) {
if (!acls.empty()) {
acls += ", ";
infolog("Console ACL allowing connections from: %s", acls.c_str());
}
+ auto listeningSockets = initListeningSockets();
+
#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
- if (g_consoleEnabled && g_consoleKey.empty()) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleEnabled && dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey.empty()) {
warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
}
#endif
- dropPrivileges();
+ dropPrivileges(cmdLine);
/* this need to be done _after_ dropping privileges */
#ifndef DISABLE_DELAY_PIPE
g_snmpAgent->run();
}
- if (!g_maxTCPClientThreads) {
- g_maxTCPClientThreads = static_cast<size_t>(10);
- }
- else if (*g_maxTCPClientThreads == 0 && tcpBindsCount > 0) {
- warnlog("setMaxTCPClientThreads() has been set to 0 while we are accepting TCP connections, raising to 1");
- g_maxTCPClientThreads = 1;
- }
-
/* we need to create the TCP worker threads before the
acceptor ones, otherwise we might crash when processing
the first TCP query */
#ifndef USE_SINGLE_ACCEPTOR_THREAD
- g_tcpclientthreads = std::make_unique<TCPClientCollection>(*g_maxTCPClientThreads, std::vector<ClientState*>());
+ const auto maxTCPClientThreads = dnsdist::configuration::getImmutableConfiguration().d_maxTCPClientThreads;
+ /* the limit is completely arbitrary: hopefully high enough not to trigger too many false positives
+ but low enough to be useful */
+ if (maxTCPClientThreads >= 50U) {
+ warnlog("setMaxTCPClientThreads(%d) might create a large number of TCP connections to backends, and is probably not needed, please consider lowering it", maxTCPClientThreads);
+ }
+ g_tcpclientthreads = std::make_unique<TCPClientCollection>(maxTCPClientThreads, std::vector<ClientState*>());
#endif
#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
initDoHWorkers();
#endif
- for (auto& todoItem : todo) {
- todoItem();
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleEnabled) {
+ std::thread consoleControlThread(dnsdist::console::controlThread, std::move(listeningSockets.d_consoleSocket));
+ consoleControlThread.detach();
+ }
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_webServerAddress) {
+ std::thread webServerThread(dnsdist::webserver::WebserverThread, std::move(listeningSockets.d_webServerSocket));
+ webServerThread.detach();
}
- auto localPools = g_pools.getCopy();
- /* create the default pool no matter what */
- createPoolIfNotExists(localPools, "");
- if (!g_cmdLine.remotes.empty()) {
- for (const auto& address : g_cmdLine.remotes) {
+ for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
+ if (backend->connected) {
+ backend->start();
+ }
+ }
+
+ if (!cmdLine.remotes.empty()) {
+ for (const auto& address : cmdLine.remotes) {
DownstreamState::Config config;
config.remote = ComboAddress(address, 53);
auto ret = std::make_shared<DownstreamState>(std::move(config), nullptr, true);
- addServerToPool(localPools, "", ret);
+ addServerToPool("", ret);
ret->start();
- g_dstates.modify([&ret](servers_t& servers) { servers.push_back(std::move(ret)); });
+ dnsdist::configuration::updateRuntimeConfiguration([&ret](dnsdist::configuration::RuntimeConfiguration& runtimeConfig) {
+ runtimeConfig.d_backends.push_back(std::move(ret));
+ });
}
}
- g_pools.setState(localPools);
- if (g_dstates.getLocal()->empty()) {
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends.empty()) {
errlog("No downstream servers defined: all packets will get dropped");
// you might define them later, but you need to know
}
checkFileDescriptorsLimits(udpBindsCount, tcpBindsCount);
{
- auto states = g_dstates.getCopy(); // it is a copy, but the internal shared_ptrs are the real deal
+ //coverity[auto_causes_copy]
+ const auto states = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends; // it is a copy, but the internal shared_ptrs are the real deal
auto mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(states.size()));
for (auto& dss : states) {
dnsdist::ServiceDiscovery::run();
#ifndef DISABLE_CARBON
- dnsdist::Carbon::run();
+ dnsdist::Carbon::run(dnsdist::configuration::getCurrentRuntimeConfiguration().d_carbonEndpoints);
#endif /* DISABLE_CARBON */
thread stattid(maintThread);
#endif /* DISABLE_DYNBLOCKS */
#ifndef DISABLE_SECPOLL
- if (!g_secPollSuffix.empty()) {
+ if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_secPollSuffix.empty()) {
thread secpollthread(secPollThread);
secpollthread.detach();
}
#endif /* DISABLE_SECPOLL */
- if (g_cmdLine.beSupervised) {
+ if (cmdLine.beSupervised) {
#ifdef HAVE_SYSTEMD
sd_notify(0, "READY=1");
#endif
}
else {
healththread.detach();
- doConsole();
+ dnsdist::console::doConsole();
}
#ifdef COVERAGE
cleanupLuaObjects();
#pragma once
#include "config.h"
-#include "ext/luawrapper/include/LuaContext.hpp"
#include <condition_variable>
#include <memory>
#include <unistd.h>
#include <unordered_map>
-#include <boost/variant.hpp>
-
+#include "bpf-filter.hh"
#include "circular_buffer.hh"
-#include "dnscrypt.hh"
-#include "dnsdist-cache.hh"
-#include "dnsdist-dynbpf.hh"
#include "dnsdist-idstate.hh"
#include "dnsdist-lbpolicies.hh"
#include "dnsdist-protocols.hh"
#include "misc.hh"
#include "mplexer.hh"
#include "noinitvector.hh"
-#include "sholder.hh"
-#include "tcpiohandler.hh"
#include "uuid-utils.hh"
#include "proxy-protocol.hh"
#include "stat_t.hh"
uint64_t uptimeOfProcess(const std::string& str);
-extern uint16_t g_ECSSourcePrefixV4;
-extern uint16_t g_ECSSourcePrefixV6;
-extern bool g_ECSOverride;
-
using QTag = std::unordered_map<string, string>;
class IncomingTCPConnectionState;
struct DNSQuestion
{
- DNSQuestion(InternalQueryState& ids_, PacketBuffer& data_) :
- data(data_), ids(ids_), ecsPrefixLength(ids.origRemote.sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), ecsOverride(g_ECSOverride)
- {
- }
+ DNSQuestion(InternalQueryState& ids_, PacketBuffer& data_);
DNSQuestion(const DNSQuestion&) = delete;
DNSQuestion& operator=(const DNSQuestion&) = delete;
DNSQuestion(DNSQuestion&&) = default;
const std::shared_ptr<DownstreamState>& d_downstream;
};
-/* so what could you do:
- drop,
- fake up nxdomain,
- provide actual answer,
- allow & and stop processing,
- continue processing,
- modify header: (servfail|refused|notimp), set TC=1,
- send to pool */
-
-class DNSAction
-{
-public:
- enum class Action : uint8_t
- {
- Drop,
- Nxdomain,
- Refused,
- Spoof,
- Allow,
- HeaderModify,
- Pool,
- Delay,
- Truncate,
- ServFail,
- None,
- NoOp,
- NoRecurse,
- SpoofRaw,
- SpoofPacket,
- SetTag,
- };
- static std::string typeToString(const Action& action)
- {
- switch (action) {
- case Action::Drop:
- return "Drop";
- case Action::Nxdomain:
- return "Send NXDomain";
- case Action::Refused:
- return "Send Refused";
- case Action::Spoof:
- return "Spoof an answer";
- case Action::SpoofPacket:
- return "Spoof a raw answer from bytes";
- case Action::SpoofRaw:
- return "Spoof an answer from raw bytes";
- case Action::Allow:
- return "Allow";
- case Action::HeaderModify:
- return "Modify the header";
- case Action::Pool:
- return "Route to a pool";
- case Action::Delay:
- return "Delay";
- case Action::Truncate:
- return "Truncate over UDP";
- case Action::ServFail:
- return "Send ServFail";
- case Action::SetTag:
- return "Set Tag";
- case Action::None:
- case Action::NoOp:
- return "Do nothing";
- case Action::NoRecurse:
- return "Set rd=0";
- }
-
- return "Unknown";
- }
-
- virtual Action operator()(DNSQuestion*, string* ruleresult) const = 0;
- virtual ~DNSAction()
- {
- }
- virtual string toString() const = 0;
- virtual std::map<string, double> getStats() const
- {
- return {{}};
- }
- virtual void reload()
- {
- }
-};
-
-class DNSResponseAction
-{
-public:
- enum class Action : uint8_t
- {
- Allow,
- Delay,
- Drop,
- HeaderModify,
- ServFail,
- Truncate,
- None
- };
- virtual Action operator()(DNSResponse*, string* ruleresult) const = 0;
- virtual ~DNSResponseAction()
- {
- }
- virtual string toString() const = 0;
- virtual void reload()
- {
- }
-};
-
-struct DynBlock
-{
- DynBlock()
- {
- until.tv_sec = 0;
- until.tv_nsec = 0;
- }
-
- DynBlock(const std::string& reason_, const struct timespec& until_, const DNSName& domain_, DNSAction::Action action_) :
- reason(reason_), domain(domain_), until(until_), action(action_)
- {
- }
-
- DynBlock(const DynBlock& rhs) :
- reason(rhs.reason), domain(rhs.domain), until(rhs.until), tagSettings(rhs.tagSettings), action(rhs.action), warning(rhs.warning), bpf(rhs.bpf)
- {
- blocks.store(rhs.blocks);
- }
-
- DynBlock(DynBlock&& rhs) :
- reason(std::move(rhs.reason)), domain(std::move(rhs.domain)), until(rhs.until), tagSettings(std::move(rhs.tagSettings)), action(rhs.action), warning(rhs.warning), bpf(rhs.bpf)
- {
- blocks.store(rhs.blocks);
- }
-
- DynBlock& operator=(const DynBlock& rhs)
- {
- reason = rhs.reason;
- until = rhs.until;
- domain = rhs.domain;
- action = rhs.action;
- blocks.store(rhs.blocks);
- warning = rhs.warning;
- bpf = rhs.bpf;
- tagSettings = rhs.tagSettings;
- return *this;
- }
-
- DynBlock& operator=(DynBlock&& rhs)
- {
- reason = std::move(rhs.reason);
- until = rhs.until;
- domain = std::move(rhs.domain);
- action = rhs.action;
- blocks.store(rhs.blocks);
- warning = rhs.warning;
- bpf = rhs.bpf;
- tagSettings = std::move(rhs.tagSettings);
- return *this;
- }
-
- struct TagSettings
- {
- std::string d_name;
- std::string d_value;
- };
-
- string reason;
- DNSName domain;
- timespec until{};
- std::shared_ptr<TagSettings> tagSettings{nullptr};
- mutable std::atomic<uint32_t> blocks{0};
- DNSAction::Action action{DNSAction::Action::None};
- bool warning{false};
- bool bpf{false};
-};
-
-extern GlobalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> g_dynblockNMG;
-
-extern vector<pair<struct timeval, std::string>> g_confDelta;
-
using pdns::stat_t;
class BasicQPSLimiter
bool d_passthrough{true};
};
-typedef std::unordered_map<string, unsigned int> QueryCountRecords;
-typedef std::function<std::tuple<bool, string>(const DNSQuestion* dq)> QueryCountFilter;
-struct QueryCount
-{
- QueryCount()
- {
- }
- ~QueryCount()
- {
- }
- SharedLockGuarded<QueryCountRecords> records;
- QueryCountFilter filter;
- bool enabled{false};
-};
-
-extern QueryCount g_qcount;
-
class XskPacket;
class XskSocket;
class XskWorker;
+class DNSCryptContext;
+
struct ClientState
{
ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_, bool enableProxyProtocol) :
stat_t tls12queries{0}; // valid DNS queries received via TLSv1.2
stat_t tls13queries{0}; // valid DNS queries received via TLSv1.3
stat_t tlsUnknownqueries{0}; // valid DNS queries received via unknown TLS version
- pdns::stat_t_trait<double> tcpAvgQueriesPerConnection{0.0};
+ pdns::stat_double_t tcpAvgQueriesPerConnection{0.0};
/* in ms */
- pdns::stat_t_trait<double> tcpAvgConnectionDuration{0.0};
+ pdns::stat_double_t tcpAvgConnectionDuration{0.0};
std::set<int> cpus;
std::string interface;
ComboAddress local;
std::shared_ptr<DOH3Frontend> doh3Frontend{nullptr};
std::shared_ptr<BPFFilter> d_filter{nullptr};
std::shared_ptr<XskWorker> xskInfo{nullptr};
+ std::shared_ptr<XskWorker> xskInfoResponder{nullptr};
size_t d_maxInFlightQueriesPerConn{1};
size_t d_tcpConcurrentConnectionsLimit{0};
int udpFD{-1};
};
struct CrossProtocolQuery;
+class FDMultiplexer;
struct DownstreamState : public std::enable_shared_from_this<DownstreamState>
{
stat_t tcpReusedConnections{0};
stat_t tcpNewConnections{0};
stat_t tlsResumptions{0};
- pdns::stat_t_trait<double> tcpAvgQueriesPerConnection{0.0};
+ pdns::stat_double_t tcpAvgQueriesPerConnection{0.0};
/* in ms */
- pdns::stat_t_trait<double> tcpAvgConnectionDuration{0.0};
- pdns::stat_t_trait<double> queryLoad{0.0};
- pdns::stat_t_trait<double> dropRate{0.0};
+ pdns::stat_double_t tcpAvgConnectionDuration{0.0};
+ pdns::stat_double_t queryLoad{0.0};
+ pdns::stat_double_t dropRate{0.0};
SharedLockGuarded<std::vector<unsigned int>> hashes;
LockGuarded<std::unique_ptr<FDMultiplexer>> mplexer{nullptr};
uint16_t currentCheckFailures{0};
std::atomic<bool> hashesComputed{false};
std::atomic<bool> connected{false};
- bool upStatus{false};
+ std::atomic<bool> upStatus{false};
private:
void handleUDPTimeout(IDState& ids);
else if (d_config.availability == Availability::Up) {
return true;
}
- return upStatus;
+ return upStatus.load(std::memory_order_relaxed);
}
void setUp()
void setUpStatus(bool newStatus)
{
- upStatus = newStatus;
- if (!upStatus) {
+ upStatus.store(newStatus);
+ if (!newStatus) {
latencyUsec = 0.0;
latencyUsecTCP = 0.0;
}
status = "DOWN";
}
else {
- status = (upStatus ? "up" : "down");
+ status = (upStatus.load(std::memory_order_relaxed) ? "up" : "down");
}
return status;
}
}
return latencyUsec;
}
-
- static int s_udpTimeout;
- static bool s_randomizeSockets;
- static bool s_randomizeIDs;
};
-using servers_t = vector<std::shared_ptr<DownstreamState>>;
void responderThread(std::shared_ptr<DownstreamState> dss);
-extern LockGuarded<LuaContext> g_lua;
-extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
+
+class DNSDistPacketCache;
class DNSRule
{
EDNS_HEADER_FLAG_DO = 32768
};
-extern GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
-extern DNSAction::Action g_dynBlockAction;
-
-extern GlobalStateHolder<ServerPolicy> g_policy;
-extern GlobalStateHolder<servers_t> g_dstates;
-extern GlobalStateHolder<pools_t> g_pools;
-extern GlobalStateHolder<NetmaskGroup> g_ACL;
-
-extern ComboAddress g_serverControl; // not changed during runtime
-
-extern std::vector<shared_ptr<TLSFrontend>> g_tlslocals;
-extern std::vector<shared_ptr<DOHFrontend>> g_dohlocals;
-extern std::vector<shared_ptr<DOQFrontend>> g_doqlocals;
-extern std::vector<shared_ptr<DOH3Frontend>> g_doh3locals;
-extern std::vector<std::unique_ptr<ClientState>> g_frontends;
-extern bool g_truncateTC;
-extern bool g_fixupCase;
-extern int g_tcpRecvTimeout;
-extern int g_tcpSendTimeout;
-extern uint16_t g_maxOutstanding;
-extern std::atomic<bool> g_configurationDone;
-extern boost::optional<uint64_t> g_maxTCPClientThreads;
-extern uint64_t g_maxTCPQueuedConnections;
-extern size_t g_maxTCPQueriesPerConn;
-extern size_t g_maxTCPConnectionDuration;
-extern size_t g_tcpInternalPipeBufferSize;
-extern pdns::stat16_t g_cacheCleaningDelay;
-extern pdns::stat16_t g_cacheCleaningPercentage;
-extern uint32_t g_staleCacheEntriesTTL;
-extern bool g_apiReadWrite;
-extern std::string g_apiConfigDirectory;
-extern bool g_servFailOnNoPolicy;
-extern size_t g_udpVectorSize;
-extern bool g_allowEmptyResponse;
-extern uint32_t g_socketUDPSendBuffer;
-extern uint32_t g_socketUDPRecvBuffer;
-
extern shared_ptr<BPFFilter> g_defaultBPFFilter;
-extern std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
void tcpAcceptorThread(const std::vector<ClientState*>& states);
bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
void resetLuaSideEffect(); // reset to indeterminate state
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote);
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse);
bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientState);
-extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
+class DNSCryptQuery;
+
bool handleDNSCryptQuery(PacketBuffer& packet, DNSCryptQuery& query, bool tcp, time_t now, PacketBuffer& response);
bool checkDNSCryptQuery(const ClientState& clientState, PacketBuffer& query, std::unique_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
-#include "dnsdist-snmp.hh"
-
-extern bool g_snmpEnabled;
-extern bool g_snmpTrapsEnabled;
-extern std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent;
-extern bool g_addEDNSToSelfGeneratedResponses;
-
-extern std::set<std::string> g_capabilitiesToRetain;
-static const uint16_t s_udpIncomingBufferSize{1500}; // don't accept UDP queries larger than this value
-
enum class ProcessQueryResult : uint8_t
{
Drop,
Asynchronous
};
+#include "dnsdist-actions.hh"
#include "dnsdist-rule-chains.hh"
-struct LocalHolders
-{
- LocalHolders() :
- acl(g_ACL.getLocal()), policy(g_policy.getLocal()), ruleactions(dnsdist::rules::getRuleChainHolder(dnsdist::rules::RuleChain::Rules).getLocal()), cacheMissRuleActions(dnsdist::rules::getRuleChainHolder(dnsdist::rules::RuleChain::CacheMissRules).getLocal()), cacheHitRespRuleactions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheHitResponseRules).getLocal()), cacheInsertedRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal()), selfAnsweredRespRuleactions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::SelfAnsweredResponseRules).getLocal()), servers(g_dstates.getLocal()), dynNMGBlock(g_dynblockNMG.getLocal()), dynSMTBlock(g_dynblockSMT.getLocal()), pools(g_pools.getLocal())
- {
- }
-
- LocalStateHolder<NetmaskGroup> acl;
- LocalStateHolder<ServerPolicy> policy;
- LocalStateHolder<vector<dnsdist::rules::RuleAction>> ruleactions;
- LocalStateHolder<vector<dnsdist::rules::RuleAction>> cacheMissRuleActions;
- LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> cacheHitRespRuleactions;
- LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> cacheInsertedRespRuleActions;
- LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> selfAnsweredRespRuleactions;
- LocalStateHolder<servers_t> servers;
- LocalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> dynNMGBlock;
- LocalStateHolder<SuffixMatchTree<DynBlock>> dynSMTBlock;
- LocalStateHolder<pools_t> pools;
-};
-
-ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend);
-ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend);
-bool processResponse(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted);
+ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend);
+ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend);
+bool processResponse(PacketBuffer& response, DNSResponse& dnsResponse, bool muted);
bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dnsQuestion, std::string& ruleresult, bool& drop);
-bool processResponseAfterRules(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted);
-bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& localRespRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids);
+bool processResponseAfterRules(PacketBuffer& response, DNSResponse& dnsResponse, bool muted);
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, InternalQueryState&& ids);
bool applyRulesToResponse(const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, DNSResponse& dnsResponse);
bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& downstream, uint16_t queryID, DNSQuestion& dnsQuestion, PacketBuffer& query, bool actuallySend = true);
# LimitMEMLOCK=infinity
# Sandboxing
-# Note: adding CAP_SYS_ADMIN (or CAP_BPF for Linux >= 5.8) is required to use eBPF support,
+# Note: adding CAP_SYS_ADMIN is required to use eBPF support,
# and CAP_NET_RAW to be able to set the source interface to contact a backend
# If an AppArmor policy is in use, it might have to be updated to allow dnsdist to keep the
-# capability: adding a 'capability bpf,' (for CAP_BPF) line to the policy is usually enough.
+# capability: adding a 'capability sys_admin,' line to the policy is usually enough.
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
LockPersonality=true
eBPF Socket Filtering
=====================
-:program:`dnsdist` can use `eBPF <http://www.brendangregg.com/ebpf.html>`_ socket filtering on recent Linux kernels (4.1+) built with eBPF support (``CONFIG_BPF``, ``CONFIG_BPF_SYSCALL``, ideally ``CONFIG_BPF_JIT``). It requires dnsdist to have the ``CAP_SYS_ADMIN`` capabilities at startup, or the more restrictive ``CAP_BPF`` one since Linux 5.8.
+:program:`dnsdist` can use `eBPF <http://www.brendangregg.com/ebpf.html>`_ socket filtering on recent Linux kernels (4.1+) built with eBPF support (``CONFIG_BPF``, ``CONFIG_BPF_SYSCALL``, ideally ``CONFIG_BPF_JIT``). It requires dnsdist to have the ``CAP_SYS_ADMIN`` capabilities at startup.
.. note::
- To retain the required capability, ``CAP_SYS_ADMIN`` or ``CAP_BPF`` depending on the Linux kernel version, it is necessary to call :func:`addCapabilitiesToRetain` during startup, as :program:`dnsdist` drops capabilities after startup.
+ To retain the required capability, ``CAP_SYS_ADMIN``, it is necessary to call :func:`addCapabilitiesToRetain` during startup, as :program:`dnsdist` drops capabilities after startup.
.. note::
- eBPF can be used by unprivileged users lacking the ``CAP_SYS_ADMIN`` (or ``CAP_BPF``) capability on some kernels, depending on the value of the ``kernel.unprivileged_bpf_disabled`` sysctl. Since 5.15 that kernel build setting ``BPF_UNPRIV_DEFAULT_OFF`` is enabled by default, which prevents unprivileged users from using eBPF.
+ eBPF can be used by unprivileged users lacking the ``CAP_SYS_ADMIN`` capability on some kernels, depending on the value of the ``kernel.unprivileged_bpf_disabled`` sysctl. Since 5.15 that kernel build setting ``BPF_UNPRIV_DEFAULT_OFF`` is enabled by default, which prevents unprivileged users from using eBPF.
.. note::
- ``AppArmor`` users might need to update their policy to allow dnsdist to keep the ``CAP_SYS_ADMIN`` (or ``CAP_BPF``) capability. Adding a ``capability bpf,`` (for ``CAP_BPF``) line to the policy file is usually enough.
+ ``AppArmor`` users might need to update their policy to allow dnsdist to keep the ``CAP_SYS_ADMIN`` capability. Adding a ``capability sys_admin,`` line to the policy file is usually enough.
.. note::
In addition to keeping the correct capability, large maps might require an increase of ``RLIMIT_MEMLOCK``, as mentioned below.
XDP programs are more powerful than eBPF socket filtering ones as they are not limited to accepting or denying a packet, but can immediately craft and send an answer. They are also executed a bit earlier in the kernel networking path so can provide better performance.
A sample program using the maps populated by dnsdist in an external XDP program can be found in the `contrib/ directory of our git repository <https://github.com/PowerDNS/pdns/tree/master/contrib>`__. That program supports answering with a TC=1 response instead of simply dropping the packet.
-
internal-design
asynchronous-processing
xsk
+ zero-scope
dnsdist, as a load-balancer, receives the UDP datagrams and terminates the TCP connections with the client. It therefore knows the source IP address and port of that client, as well as the original destination address, port, and protocol.
Very often the backend needs to know that information as well, to pass EDNS Client Subnet to an authoritative server, to do GeoIP-based processing or even custom filtering.
-There are several ways to pass that information using dnsdist: EDNS Client Subnet, X-Proxied-For and the Proxy Protocol.
+There are several ways to pass that information using dnsdist: the :ref:`Proxy Protocol` and :ref:`EDNS Client Subnet<EDNS Client Subnet>`.
+
+When the backend supports it (ISC Bind, Knot, Knot Resolver, PowerDNS Authoritative, PowerDNS Recursor, Unbound, HAProxy, nginx, postfix and many others do), the proxy protocol is the best option.
+
+.. note::
+ X-Proxied-For (XPF) was a third option but it has been deprecated for a while, and support has been removed in 2.0.0.
+
+.. _Proxy Protocol:
+
+Proxy Protocol
+--------------
+
+.. note:
+ The Proxy Protocol has been designed by the HAProxy folks for HTTP over TCP, but is generic enough to be used in other places, and is a de-facto standard with implementations in ISC Bind, Knot, Knot Resolver, PowerDNS Authoritative, PowerDNS Recursor, Unbound, HAProxy, nginx, postfix and many others.
+ It works by pre-pending a small header at the very beginning of a UDP datagram or TCP connection, which holds the initial source and destination addresses and ports, and can also contain several custom values in a Type-Length-Value format. More information about the Proxy Protocol can be found at https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt
+
+From dnsdist to its backend
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To enable the use of the Proxy Protocol between dnsdist and its backend, the ``useProxyProtocol`` parameter can be used when creating a :func:`new server <newServer>`:
+
+.. code-block:: lua
+
+ newServer{address="192.0.2.1:53", useProxyProtocol=true}
+
+This parameter indicates whether a Proxy Protocol version 2 (binary) header should be prepended to the query before forwarding it to the backend, over UDP or TCP.
+
+Both the PowerDNS Authoritative Server and the Recursor can parse PROXYv2 headers, if configured to do so with their `proxy-protocol-from` setting::
+
+ proxy-protocol-from=192.0.2.2
+
+For more information, see the `authoritative server's documentation <https://doc.powerdns.com/authoritative/settings.html#proxy-protocol-from>`_ or the `recursor's documentation <https://docs.powerdns.com/recursor/settings.html#proxy-protocol-from>`_.
+
+From clients to dnsdist
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Such a Proxy Protocol header can also be passed from the client to dnsdist, using :func:`setProxyProtocolACL` to specify which clients to accept it from:
+
+.. code-block:: lua
+
+ setProxyProtocolACL({'192.0.2.0/24'})
+
+Note that a Proxy Protocol payload will be required from these clients, regular DNS queries will no longer be accepted if they are not preceded by a Proxy Protocol payload.
+
+If :func:`setProxyProtocolApplyACLToProxiedClients` is set (default is false), the general ACL will be applied to the source IP address as seen by dnsdist first, but also to the source IP address provided in the Proxy Protocol header.
+
+Passing additional information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Custom values can be added to the header via :meth:`DNSQuestion:addProxyProtocolValue`, :meth:`DNSQuestion:setProxyProtocolValues`, :func:`SetAdditionalProxyProtocolValueAction` and :func:`SetProxyProtocolValuesAction`.
+
+Be careful that Proxy Protocol values are sent once at the beginning of the TCP connection for TCP and DoT queries.
+That means that values received on an incoming TCP connection will be inherited by subsequent queries received over the same incoming TCP connection, if any, but values set to a query will not be inherited by subsequent queries.
+
+Please also note that the maximum size of a Proxy Protocol header dnsdist is willing to accept is 512 bytes by default, although it can be set via :func:`setProxyProtocolMaximumPayloadSize`.
+
+.. _EDNS Client Subnet:
Using EDNS Client Subnet
------------------------
-EDNS Client Subnet (ECS) is a standardized EDNS option designed to pass a bit of information about the client from a resolver to authoritative servers. While it was not designed with our use-case in mind, it can be used by dnsdist to send the source IP, but only the source IP, to its backend.
+.. note:
+ EDNS Client Subnet (ECS) is a standardized EDNS option designed to pass a bit of information about the client from a resolver to authoritative servers. While it was not designed with our use-case in mind, it can be used by dnsdist to send the source IP, but only the source IP, to its backend.
+
+In order to provide the downstream server with the address of the real client, or at least the one talking to dnsdist, the ``useClientSubnet`` parameter can be used when creating a :func:`new server <newServer>`:
+
+.. code-block:: lua
+
+ newServer{address="192.0.2.1:53", useClientSubnet=true}
-In order to provide the downstream server with the address of the real client, or at least the one talking to dnsdist, the ``useClientSubnet`` parameter can be used when creating a :func:`new server <newServer>`. This parameter indicates whether an EDNS Client Subnet option should be added to the request.
+This parameter indicates whether an EDNS Client Subnet option should be added to the request.
The default source prefix-length is 24 for IPv4 and 56 for IPv6, meaning that for a query received from 192.0.2.42, the EDNS Client Subnet value sent to the backend will be 192.0.2.0.
-This can be changed with :func:`setECSSourcePrefixV4` and :func:`setECSSourcePrefixV6`.
+This can be changed with :func:`setECSSourcePrefixV4` and :func:`setECSSourcePrefixV6`:
+
+.. code-block:: lua
-If the incoming request already contains an EDNS Client Subnet value, it will not be overridden unless :func:`setECSOverride` is set to ``true``.
+ setECSSourcePrefixV4(32)
+ setECSSourcePrefixV6(128)
+
+If the incoming request already contains an EDNS Client Subnet value, it will not be overridden unless :func:`setECSOverride` is set to ``true``:
+
+.. code-block:: lua
+
+ setECSOverride(true)
+
+Advanced usage
+^^^^^^^^^^^^^^
In addition to the global settings, rules and Lua bindings can alter this behavior per query:
In effect this means that for the EDNS Client Subnet option to be added to the request, ``useClientSubnet`` should be set to ``true`` for the backend used (default to ``false``) and ECS should not have been disabled by calling :func:`SetDisableECSAction` or setting ``dq.useECS`` to ``false`` (default to true).
-Note that any trailing data present in the incoming query is removed when an OPT record has to be inserted.
+Drawbacks
+^^^^^^^^^
+
+.. warning::
+ Note that any trailing data present in the incoming query is removed when an OPT record has to be inserted.
In addition to the drawback that it can only pass the source IP address, and the fact that it needs to override any existing ECS option, adding that option requires parsing and editing the query, as well as parsing and editing the response in most cases.
| Response, EDNS with ECS | remove or edit the ECS option if needed |
+----------------------------+-------------------------------------------------+
-Proxy Protocol
---------------
-
-The Proxy Protocol has been designed by the HAProxy folks for HTTP over TCP, but is generic enough to be used in other places, and is a de-facto standard with implementations in nginx and postfix, for example.
-It works by pre-pending a small header at the very beginning of a UDP datagram or TCP connection, which holds the initial source and destination addresses and ports, and can also contain several custom values in a Type-Length-Value format. More information about the Proxy Protocol can be found at https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt
-
-In order to use it in dnsdist, the ``useProxyProtocol`` parameter can be used when creating a :func:`new server <newServer>`.
-This parameter indicates whether a Proxy Protocol version 2 (binary) header should be prepended to the query before forwarding it to the backend, over UDP or TCP.
-Such a Proxy Protocol header can also be passed from the client to dnsdist, using :func:`setProxyProtocolACL` to specify which clients to accept it from. Note that a proxy protocol payload will be required from these clients, regular DNS queries will no longer be accepted if they are not preceded by a proxy protocol payload.
-
-If :func:`setProxyProtocolApplyACLToProxiedClients` is set (default is false), the general ACL will be applied to the source IP address as seen by dnsdist first, but also to the source IP address provided in the Proxy Protocol header.
-
-Custom values can be added to the header via :meth:`DNSQuestion:addProxyProtocolValue`, :meth:`DNSQuestion:setProxyProtocolValues`, :func:`SetAdditionalProxyProtocolValueAction` and :func:`SetProxyProtocolValuesAction`.
-Be careful that Proxy Protocol values are sent once at the beginning of the TCP connection for TCP and DoT queries.
-That means that values received on an incoming TCP connection will be inherited by subsequent queries received over the same incoming TCP connection, if any, but values set to a query will not be inherited by subsequent queries.
-Please also note that the maximum size of a Proxy Protocol header dnsdist is willing to accept is 512 bytes by default, although it can be set via :func:`setProxyProtocolMaximumPayloadSize`.
-
-dnsdist 1.5.0 only supports outgoing Proxy Protocol. Support for parsing incoming Proxy Protocol headers has been implemented in 1.6.0, except for DoH where it does not make sense anyway, since HTTP headers already provide a mechanism for that.
-
-Both the PowerDNS Authoritative Server and the Recursor can parse PROXYv2 headers, if configured to do so with their `proxy-protocol-from` setting.
-
X-Proxied-For
-------------
addAction(RecordsTypeCountRule(DNSSection.Additional, 65280, 1, 65535), DropAction())
+.. _Influence on caching:
+
Influence on caching
--------------------
When dnsdist's packet cache is in use, it is important to note that the cache lookup is done **after** adding ECS, because it prevents serving the same response to clients from different subnets when ECS is passed to an authoritative server doing GeoIP, or to a backend doing custom filtering.
-However that means that passing a narrow ECS source will effectively kill dnsdist's cache ratio, since a given answer will only be a cache hit for clients in the same ECS subnet. Therefore, unless a broad ECS source (greater than 24, for example) is used, it's better to disable caching.
-
-One exception to that rule is the zero-scope feature, which allows dnsdist to detect that a response sent by the backend has a 0-scope ECS value, indicating that the answer is not ECS-specific and can be used for all clients. dnsdist will then store the answer in its packet cache using the initial query, before ECS has been added.
-For that feature to work, dnsdist will look up twice into the packet cache when a query arrives, first without and then with ECS. That way, when most of the responses sent by a backend are not ECS-specific and can be served to all clients, dnsdist will still be able to have a great cache-hit ratio for non ECS-specific entries.
-
-That feature is enabled by setting ``disableZeroScope=false`` on :func:`newServer` (default) and ``parseECS=true`` on :func:`newPacketCache` (not the default).
+However that means that passing a narrow ECS source will effectively kill dnsdist's cache ratio, since a given answer will only be a cache hit for clients in the same ECS subnet. Therefore, unless a broad ECS source (greater than 24, for example) is used, it's better to disable caching. The zero-scope feature can be enabled to mitigate this drawback, as described in :doc:`zero-scope`.
Things are different for the proxy protocol, because dnsdist then does the cache lookup **before** adding the payload. It means that caching can still be enabled as long as the response is not source-dependent, but should be disabled otherwise.
Note that this require ``SO_REUSEPORT`` support in the underlying operating system (added for example in Linux 3.9).
Please also be aware that doing so will increase lock contention and might not therefore scale linearly, as discussed below.
-Another possibility is to use the reuseport option to run several dnsdist processes in parallel on the same host, thus avoiding the lock contention issue at the cost of having to deal with the fact that the different processes will not share informations, like statistics or DDoS offenders.
+Another possibility is to use the reuseport option to run several dnsdist processes in parallel on the same host, thus avoiding the lock contention issue at the cost of having to deal with the fact that the different processes will not share information, like statistics or DDoS offenders.
The UDP threads handling the responses from the backends do not use a lot of CPU, but if needed it is also possible to add the same backend several times to the dnsdist configuration to distribute the load over several responder threads::
Note that before 1.6.0 the TCP worker threads were created at runtime, adding a new thread when the existing ones seemed to struggle with the load, until the maximum number of threads had been reached. Starting with 1.6.0 the configured number of worker threads are immediately created at startup.
The maximum number of threads in the TCP / DNS over TLS pool is controlled by the :func:`setMaxTCPClientThreads` directive, and defaults to 10.
-This number can be increased to handle a large number of simultaneous TCP / DNS over TLS connections.
+This number can be increased to handle a large number of simultaneous TCP / DNS over TLS connections, but the default value should already be enough for most setups.
If all the TCP threads are busy, new TCP connections are queued while they wait to be picked up. The maximum number of queued connections can be configured with :func:`setMaxTCPQueuedConnections` and defaults to 1000 (10000 on Linux since 1.6.0). Note that the size of the internal pipe used to distribute queries might need to be increased as well, using :func:`setTCPInternalPipeBufferSize`.
Any value larger than 0 will cause new connections to be dropped if there are already too many queued.
``AF_XDP`` / ``XSK``
====================
-Since 1.9.0, :program:`dnsdist` can use `AF_XDP <https://www.kernel.org/doc/html/v4.18/networking/af_xdp.html>`_ for high performance UDP packet processing recent Linux kernels (4.18+). It requires :program:`dnsdist` to have the ``CAP_NET_ADMIN`` and ``CAP_SYS_ADMIN`` capabilities at startup, and to have been compiled with the ``--with-xsk`` configure option.
+Since 1.9.0, :program:`dnsdist` can use `AF_XDP <https://www.kernel.org/doc/html/v4.18/networking/af_xdp.html>`_ for high performance UDP packet processing recent Linux kernels (4.18+). It requires :program:`dnsdist` to have the ``CAP_NET_ADMIN``, ``CAP_SYS_ADMIN`` and ``CAP_NET_RAW`` capabilities at startup, and to have been compiled with the ``--with-xsk`` configure option.
.. note::
To retain the required capabilities it is necessary to call :func:`addCapabilitiesToRetain` during startup, as :program:`dnsdist` drops capabilities after startup.
:alt: AF_XDP CPU
The first run handled roughly 1 million QPS, the second run 2.5 millions, with the CPU usage being much lower in the ``AF_XDP`` case.
+
+Running under systemd
+---------------------
+
+:program:`dnsdist` needs quite a few more additional permissions to use ``AF_XDP``:
+
+- to access the ``BPF`` maps directory, it needs to be able to go into the ``/sys/fs/bpf`` directory: one option is to ``chmod o+x /sys/fs/bpf``, a safer one is to restrict that to the ``dnsdist`` user instead via ``chgrp dnsdist /sys/fs/bpf && chmod g+x /sys/fs/bpf``
+- to read the ``BPF`` maps themselves, they need to be readable by the ``dnsdist`` user: ``chown -R dnsdist:dnsdist /sys/fs/bpf/dnsdist/``
+- to create ``AF_XDP`` sockets: add ``AF_XDP`` to ``RestrictAddressFamilies`` in the systemd unit file
+- to load a BPF program: add ``CAP_SYS_ADMIN`` to ``CapabilityBoundingSet`` and ``AmbientCapabilities`` in the systemd unit file
+- to create raw network sockets: add ``CAP_NET_RAW`` to ``CapabilityBoundingSet`` and ``AmbientCapabilities`` in the systemd unit file
+- and finally to lock enough memory: ensure that ``LimitMEMLOCK=infinity`` is set in the systemd unit file
--- /dev/null
+EDNS Client Subnet Zero Scope
+==================================
+
+As described in :doc:`Passing the source address to the backend <passing-source-address>`, :program:`dnsdist` can add an ``EDNS`` Client Subnet option to an incoming query to provide the downstream server with the address of the client talking to it. The downstream server can then potentially use this knowledge to reply with a response that has been tailored for this specific client, and should not be served to any other client. By default :program:`dnsdist` ensures that such a response is only served to intended client from its internal packet cache, including the added ``EDNS`` Client Subnet option in the data that is hashed to compute the cache key. This is the safest option, but is not optimal because some responses were not actually tied to a specific client subnet and could have been used for all of them. The downstream server can signal this by setting the scope in the ``EDNS`` Client Subnet option included in the response.
+
+This is where the zero-scope feature comes to play, allowing :program:`dnsdist` to parse and detect that a response sent by the backend has a scope value set to ``0``, indicating that the answer is not specific to a given client subnet and can be used for all of them. :program:`dnsdist` will then store the answer in its packet cache using the initial query as the key, before the ``EDNS`` Client Subnet option has been added.
+
+The second step needed for that feature to work properly is for :program:`dnsdist` to look up twice into the packet cache when a query arrives, first without and then with the ``EDNS`` Client Subnet option. That way, when most of the responses sent by a backend are not specific and can be served to all clients, :program:`dnsdist` will still be able to have a great cache-hit ratio for non specific entries.
+
+This feature is enabled when:
+
+* ``disableZeroScope=true`` is not set on :func:`newServer` (the default is ``false``)
+* and ``parseECS=true`` is set on :func:`newPacketCache` (which is not the default).
Changelog
=========
+.. changelog::
+ :version: 1.8.4
+ :released: 20th of September 2024
+
+ Please review the :doc:`Upgrade Guide <../upgrade_guide>` before upgrading from versions < 1.8.x.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14467
+
+ Fix a compilation issue with clang by switching to ``pdns::views::UnsignedCharView``
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14680
+ :tickets: 14562
+
+ Fix build with boost 1.86.0
+
+ .. change::
+ :tags: Bug Fixes, DNS over TLS
+ :pullreq: 14679
+
+ Prevent a data race in incoming DNS over TLS connections by storing the ``OpenSSLTLSIOCtx`` in the connection
+
+.. changelog::
+ :version: 1.9.6
+ :released: 16th of July 2024
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14436
+
+ Fix a race in the XSK/AF_XDP backend handling code
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14437
+
+ dns.cc: use pdns::views::UnsignedCharView
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14438
+
+ Make the logging functions available to all Lua environments
+
+ .. change::
+ :tags: Bug Fixes, Metrics
+ :pullreq: 14439
+ :tickets: 14395
+
+ Dedup Prometheus help and type lines for custom metrics with labels
+
+ .. change::
+ :tags: New Features
+ :pullreq: 14449
+
+ Add support for a callback when a new tickets key is added
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14450
+
+ Handle Quiche >= 0.22.0
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14452
+
+ Don't include openssl/engine.h if it's not going to be used (Sander Hoentjen)
+
+.. changelog::
+ :version: 1.9.5
+ :released: 20th of June 2024
+
+ .. change::
+ :tags: Bug Fixes, DNS over HTTPS
+ :pullreq: 14163
+
+ Reply to HTTP/2 PING frames immediately
+
+ .. change::
+ :tags: Bug Fixes, DNS over QUIC, DNS over HTTP3
+ :pullreq: 14166
+
+ Use the correct source IP for outgoing QUIC datagrams
+
+ .. change::
+ :tags: Bug Fixes, Webserver
+ :pullreq: 14170
+
+ Prevent a race when calling ``registerWebHandler`` at runtime
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14331
+
+ Syslog should be enabled by default
+
+ .. change::
+ :tags: Bug Fixes, DNS over HTTPS
+ :pullreq: 14332
+
+ Log the correct amount of bytes sent for DoH w/ nghttp2
+
+ .. change::
+ :tags: Bug Fixes, Webserver
+ :pullreq: 14333
+
+ Enforce a maximum number of HTTP request fields and a maximum HTTP request line size
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14334
+
+ Fix a warning when compiling the unit tests without XSK
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14335
+
+ autoconf: allow prerelease systemd versions (Chris Hofstaedtler)
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14336
+ :tickets: 14279
+
+ Edit the systemd unit file, ``CAP_BPF`` is no longer enough
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14337
+
+ Fix 'Error creating TCP worker' error message
+
+ .. change::
+ :tags: New Features
+ :pullreq: 14338
+
+ Add a Lua FFI function to set proxy protocol values
+
+ .. change::
+ :tags: New Features
+ :pullreq: 14339
+
+ Add Lua FFI bindings to generate SVC responses
+
+ .. change::
+ :tags: Bug Fixes, Webserver
+ :pullreq: 14342
+
+ Fix a race condition with custom Lua web handlers
+
.. changelog::
:version: 1.9.4
:released: 13th of May 2024
:tags: Improvements
:pullreq: 6637
- Don't copy unitialized values of SuffixMatchTree
+ Don't copy uninitialized values of SuffixMatchTree
.. change::
:tags: Improvements
.. versionadded:: 1.5.0
- Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+ Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
The ``function`` should return a :ref:`DNSAction`. If the Lua code fails, ServFail is returned.
.. versionadded:: 1.7.0
- Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+ Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
The ``function`` should return a :ref:`DNSAction`. If the Lua code fails, ServFail is returned.
.. versionadded:: 1.7.0
- Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+ Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
The ``function`` should return a :ref:`DNSResponseAction`. If the Lua code fails, ServFail is returned.
.. versionadded:: 1.5.0
- Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+ Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
The ``function`` should return a :ref:`DNSResponseAction`. If the Lua code fails, ServFail is returned.
.. versionadded:: 1.7.0
Accept a Linux capability as a string, or a list of these, to retain after startup so that privileged operations can still be performed at runtime.
- Keeping ``CAP_BPF`` on kernel 5.8+ for example allows loading eBPF programs and altering eBPF maps at runtime even if the ``kernel.unprivileged_bpf_disabled`` sysctl is set.
+ Keeping ``CAP_SYS_ADMIN`` on kernel 5.8+ for example allows loading eBPF programs and altering eBPF maps at runtime even if the ``kernel.unprivileged_bpf_disabled`` sysctl is set.
Note that this does not grant the capabilities to the process, doing so might be done by running it as root which we don't advise, or by adding capabilities via the systemd unit file, for example.
Please also be aware that switching to a different user via ``--uid`` will still drop all capabilities.
.. versionadded:: 1.7.0
Hash the supplied password using a random salt, and returns a string that can be used with :func:`setWebserverConfig`.
+ For example, to get a hashed version of the ``test`` password:
- :param string - password: The password to hash
- :param int - workFactor: The work factor to use for the hash function (currently scrypt), as a power of two. Default is 1024.
+ .. code-block:: sh
+
+ > hashPassword('test')
+ $scrypt$ln=10,p=1,r=8$RSYJ2QDmdlkNYMyqZF/FWw==$JQTftQCvAXR4Qtrg0lQmvrzgYEo3/PjEeuV4/2Oq1Vg=
+
+ The full string can then be used with :func:`setWebserverConfig`:
+
+ .. code-block:: lua
+
+ setWebserverConfig({password="$scrypt$ln=10,p=1,r=8$RSYJ2QDmdlkNYMyqZF/FWw==$JQTftQCvAXR4Qtrg0lQmvrzgYEo3/PjEeuV4/2Oq1Vg=",
+ apiKey="$scrypt$ln=10,p=1,r=8$RSYJ2QDmdlkNYMyqZF/FWw==$JQTftQCvAXR4Qtrg0lQmvrzgYEo3/PjEeuV4/2Oq1Vg=",
+ acl="127.0.0.1/32"})
+
+ :param string password: The password to hash
+ :param int workFactor: The work factor to use for the hash function (currently scrypt), as a power of two. Default is 1024.
.. function:: webserver(listen_address [, password[, apikey[, customHeaders[, acl]]]])
.. function:: setECSOverride(bool)
- When ``useClientSubnet`` in :func:`newServer` is set and dnsdist adds an EDNS Client Subnet Client option to the query, override an existing option already present in the query, if any.
+ When ``useClientSubnet`` in :func:`newServer` is set and dnsdist adds an EDNS Client Subnet Client option to the query, override an existing option already present in the query, if any. Please see :doc:`../advanced/passing-source-address` for more information.
Note that it's not recommended to enable ``setECSOverride`` in front of an authoritative server responding with EDNS Client Subnet information as mismatching data (ECS scopes) can confuse clients and lead to SERVFAIL responses on downstream nameservers.
:param bool: Whether to override an existing EDNS Client Subnet option present in the query. Defaults to false
``maxCheckFailures`` ``number`` "Allow ``number`` check failures before declaring the backend down, default: 1"
``checkInterval`` ``number`` "The time in seconds between health checks"
``mustResolve`` ``bool`` "Set to true when the health check MUST return a RCODE different from NXDomain, ServFail and Refused. Default is false, meaning that every RCODE except ServFail is considered valid"
- ``useClientSubnet`` ``bool`` "Add the client's IP address in the EDNS Client Subnet option when forwarding the query to this backend"
+ ``useClientSubnet`` ``bool`` "Add the client's IP address in the EDNS Client Subnet option when forwarding the query to this backend. Default is false. Please see :doc:`../advanced/passing-source-address` for more information"
``source`` ``string`` "The source address or interface to use for queries to this backend, by default this is left to the kernel's address selection.
The following formats are supported:
- interface name, e.g. ``""eth0""``
- address@interface, e.g. ``""192.0.2.2@eth0""`` "
``sockets`` ``number`` "Number of UDP sockets (and thus source ports) used toward the backend server, defaults to a single one. Note that for backends which are multithreaded, this setting will have an effect on the number of cores that will be used to process traffic from dnsdist. For example you may want to set 'sockets' to a number somewhat higher than the number of worker threads configured in the backend, particularly if the Linux kernel is being used to distribute traffic to multiple threads listening on the same socket (via `reuseport`). See also :func:`setRandomizedOutgoingSockets`."
- ``disableZeroScope`` ``bool`` "Disable the EDNS Client Subnet 'zero scope' feature, which does a cache lookup for an answer valid for all subnets (ECS scope of 0) before adding ECS information to the query and doing the regular lookup. This requires the ``parseECS`` option of the corresponding cache to be set to true"
+ ``disableZeroScope`` ``bool`` "Disable the EDNS Client Subnet :doc:`../advanced/zero-scope` feature, which does a cache lookup for an answer valid for all subnets (ECS scope of 0) before adding ECS information to the query and doing the regular lookup. Default is false. This requires the ``parseECS`` option of the corresponding cache to be set to true"
``rise`` ``number`` "Require ``number`` consecutive successful checks before declaring the backend up, default: 1"
``useProxyProtocol`` ``bool`` "Add a proxy protocol header to the query, passing along the client's IP address and port along with the original destination address and port. Default is disabled."
``reconnectOnUp`` ``bool`` "Close and reopen the sockets when a server transits from Down to Up. This helps when an interface is missing when dnsdist is started. Default is disabled."
* ``maxTTL=86400``: int - Cap the TTL for records to his number.
* ``minTTL=0``: int - Don't cache entries with a TTL lower than this.
* ``numberOfShards=20``: int - Number of shards to divide the cache into, to reduce lock contention. Used to be 1 (no shards) before 1.6.0, and is now 20.
- * ``parseECS=false``: bool - Whether any EDNS Client Subnet option present in the query should be extracted and stored to be able to detect hash collisions involving queries with the same qname, qtype and qclass but a different incoming ECS value. Enabling this option adds a parsing cost and only makes sense if at least one backend might send different responses based on the ECS value, so it's disabled by default. Enabling this option is required for the 'zero scope' option to work
+ * ``parseECS=false``: bool - Whether any EDNS Client Subnet option present in the query should be extracted and stored to be able to detect hash collisions involving queries with the same qname, qtype and qclass but a different incoming ECS value. Enabling this option adds a parsing cost and only makes sense if at least one backend might send different responses based on the ECS value, so it's disabled by default. Enabling this option is required for the :doc:`../advanced/zero-scope` option to work
* ``staleTTL=60``: int - When the backend servers are not reachable, and global configuration ``setStaleCacheEntriesTTL`` is set appropriately, TTL that will be used when a stale cache entry is returned.
* ``temporaryFailureTTL=60``: int - On a SERVFAIL or REFUSED from the backend, cache for this amount of seconds..
* ``cookieHashing=false``: bool - If true, EDNS Cookie values will be hashed, resulting in separate entries for different cookies in the packet cache. This is required if the backend is sending answers with EDNS Cookies, otherwise a client might receive an answer with the wrong cookie.
``options`` optional parameter added
This function shows all backend servers currently configured and some statistics.
- These statics have the following fields:
+ These statistics have the following fields:
* ``#`` - The number of the server, can be used as the argument for :func:`getServer`
- * ``UUID`` - The UUID of the backend. Can be set with the ``id`` option of :func:`newServer`
+ * ``Name`` - The name of the backend, if any
* ``Address`` - The IP address and port of the server
* ``State`` - The current state of the server
* ``Qps`` - Current number of queries per second
* ``Queries`` - Total amount of queries sent to this server
* ``Drops`` - Number of queries that were dropped by this server
* ``Drate`` - Number of queries dropped per second by this server
- * ``Lat`` - The latency of this server in milliseconds
+ * ``Lat`` - The latency of this server, for queries forwarded over UDP, in milliseconds
+ * ``Outstanding`` - The current number of in-flight queries
* ``Pools`` - The pools this server belongs to
+ * ``UUID`` - The UUID of the backend, only displayed when the ``showUUIDs`` option is set. Can be set with the ``id`` option of :func:`newServer`
+ * ``TCP`` - The latency of this server, for queries forwarded over TCP, in milliseconds
:param table options: A table with key: value pairs with display options.
.. function:: topSlow([num[, limit[, labels]]])
+ .. versionchanged:: 1.9.7
+ queries that timed out are no longer reported by ``topSlow``, see :func:`topTimeouts` instead
+
Print the ``num`` slowest queries that are slower than ``limit`` milliseconds.
Optionally grouped by the rightmost ``labels`` DNS labels.
:param int limit: Show queries slower than this amount of milliseconds, defaults to 2000
:param int label: Number of labels to cut down to
+.. function:: topTimeouts([num[, labels]])
+
+ .. versionadded:: 1.9.7
+
+ Print the ``num`` queries that timed out the most.
+ Optionally grouped by the rightmost ``labels`` DNS labels.
+
+ :param int num: Number to show, defaults to 10
+ :param int label: Number of labels to cut down to
+
.. _dynblocksref:
Dynamic Blocks
:param int clientIPMask: The network mask to apply to the address. Default is 32 for IPv4, 128 for IPv6.
:param int clientIPPortMask: The port mask to use to specify a range of ports to match, when the clients are behind a CG-NAT.
- Please see the documentation for :func:`setDynBlocksAction` to confirm which actions are supported by the action paramater.
+ Please see the documentation for :func:`setDynBlocksAction` to confirm which actions are supported by the action parameter.
.. function:: addDynBlocks(addresses, message[, seconds=10[, action]])
:param int seconds: The number of seconds this block to expire
:param int action: The action to take when the dynamic block matches, see :ref:`DNSAction <DNSAction>`. (default to DNSAction.None, meaning the one set with :func:`setDynBlocksAction` is used)
- Please see the documentation for :func:`setDynBlocksAction` to confirm which actions are supported by the action paramater.
+ Please see the documentation for :func:`setDynBlocksAction` to confirm which actions are supported by the action parameter.
.. function:: clearDynBlocks()
Code is supplied as a string, not as a function object.
Note that this function does nothing in 'client' or 'config-check' modes.
+.. function:: setTicketsKeyAddedHook(callback)
+
+ .. versionadded:: 1.9.6
+
+ Set a Lua function that will be called everytime a new tickets key is added. The function receives:
+
+ * the key content as a string
+ * the keylen as an integer
+
+ See :doc:`../advanced/tls-sessions-management` for more information.
+
.. function:: submitToMainThread(cmd, dict)
.. versionadded:: 1.8.0
* ``DNSAction.Pool``: use the specified pool to forward this query
* ``DNSAction.Refused``: return a response with a Refused rcode
* ``DNSAction.ServFail``: return a response with a ServFail rcode
- * ``DNSAction.SetTag``: set a tag, see :function:`SetTagAction` (only used for Dynamic Block actions, see meth:`DNSQuestion:setTag` to set a tag from Lua)
+ * ``DNSAction.SetTag``: set a tag, see :func:`SetTagAction` (only used for Dynamic Block actions, see meth:`DNSQuestion:setTag` to set a tag from Lua)
* ``DNSAction.Spoof``: spoof the response using the supplied IPv4 (A), IPv6 (AAAA) or string (CNAME) value. TTL will be 60 seconds.
* ``DNSAction.SpoofPacket``: spoof the response using the supplied raw packet
* ``DNSAction.SpoofRaw``: spoof the response using the supplied raw value as record data (see also :meth:`DNSQuestion:spoof` and :func:`dnsdist_ffi_dnsquestion_spoof_raw` to spoof multiple values)
:param string path: A local AF_UNIX socket path. Note that most platforms have a rather short limit on the length.
:param table options: A table with key: value pairs with options.
- The following options apply to the settings of the framestream library. Refer to the documentation of that
- library for the default and allowed values for these options, as well as their exact descriptions.
- For all these options, absence or a zero value has the effect of using the library-provided default value.
+ The following options apply to the settings of the `framestream library
+ <https://github.com/farsightsec/fstrm>`. Refer to the documentation of that library for the default and
+ allowed values for these options, as well as their exact descriptions. For all these options, absence or a
+ zero value has the effect of using the library-provided default value.
* ``bufferHint=0``: unsigned
* ``flushTimeout=0``: unsigned
:param string address: An IP:PORT combination where the logger will connect to.
:param table options: A table with key: value pairs with options.
- The following options apply to the settings of the framestream library. Refer to the documentation of that
- library for the default and allowed values for these options, as well as their exact descriptions.
- For all these options, absence or a zero value has the effect of using the library-provided default value.
+ The following options apply to the settings of the `framestream library
+ <https://github.com/farsightsec/fstrm>`. Refer to the documentation of that library for the default and
+ allowed values for these options, as well as their exact descriptions. For all these options, absence or a
+ zero value has the effect of using the library-provided default value.
* ``bufferHint=0``: unsigned
* ``flushTimeout=0``: unsigned
.. versionadded:: 1.7.0
- Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+ Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
The ``function`` should return true if the query matches, or false otherwise. If the Lua code fails, false is returned.
.. versionadded:: 1.5.0
- Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+ Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
The ``function`` should return true if the query matches, or false otherwise. If the Lua code fails, false is returned.
.. versionchanged:: 1.7.0
The default value has been set back to 10.
+ .. warning::
+
+ Be wary of using a too large value for this setting. :program:`dnsdist` keeps a per-thread cache of TCP connections to its backends so using a large value could, in addition to creating a lot of threads,
+ lead to a very high number of TCP connections to the backends. PowerDNS Recursor, for example, has a low default limit (128) for the number of incoming TCP connections it is willing to accept.
+
Set the maximum of TCP client threads, handling TCP connections. Before 1.4.0 a TCP thread could only handle a single incoming TCP connection at a time, while after 1.4.0 it can handle a larger number of them simultaneously.
Note that before 1.6.0 the TCP worker threads were created at runtime, adding a new thread when the existing ones seemed to struggle with the load, until the maximum number of threads had been reached. Starting with 1.6.0 the configured number of worker threads are immediately created at startup.
#
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --generate-hashes requirements.in
--hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
--hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
# via sphinx
-certifi==2024.2.2 \
- --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
- --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
+certifi==2024.7.4 \
+ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
+ --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
# via requests
changelog==0.5.8 \
--hash=sha256:43b21840874130666b7534b76b402bbb914f8c9c413d5ea9d45850ca4767dafb \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
# via fake-factory
-requests==2.31.0 \
- --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
- --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+requests==2.32.2 \
+ --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \
+ --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
# via sphinx
six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:4edf0223a0685a7c485ae5a156b6f529ba1ee481a1417817935b20bde1956232 \
--hash=sha256:6fc9287dfc823fe9aa432463edd6cea47fa9ebbf488d7f289b322ffcfca075c7
# via sphinx
-urllib3==2.2.0 \
- --hash=sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20 \
- --hash=sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224
+urllib3==2.2.2 \
+ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
+ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
# via requests
# WARNING: The following packages were not pinned, but pip requires them to be
DOHServerConfig& operator=(DOHServerConfig&&) = delete;
~DOHServerConfig() = default;
- LocalHolders holders;
std::set<std::string, std::less<>> paths;
h2o_globalconf_t h2o_config{};
h2o_context_t h2o_ctx{};
memcpy(&cleartextDH, dr.getHeader().get(), sizeof(cleartextDH));
if (!response.isAsync()) {
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
dr.ids.du = std::move(dohUnit);
- if (!processResponse(dynamic_cast<DOHUnit*>(dr.ids.du.get())->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dr, false)) {
+ if (!processResponse(dynamic_cast<DOHUnit*>(dr.ids.du.get())->response, dr, false)) {
if (dr.ids.du) {
dohUnit = getDUFromIDS(dr.ids);
dohUnit->status_code = 503;
remote = ids.origRemote;
DOHServerConfig* dsc = unit->dsc;
- auto& holders = dsc->holders;
ClientState& clientState = *dsc->clientState;
if (unit->query.size() < sizeof(dnsheader) || unit->query.size() > std::numeric_limits<uint16_t>::max()) {
ids.cs = &clientState;
dnsQuestion.sni = std::move(unit->sni);
ids.du = std::move(unit);
- auto result = processQuery(dnsQuestion, holders, downstream);
+ auto result = processQuery(dnsQuestion, downstream);
if (result == ProcessQueryResult::Drop) {
unit = getDUFromIDS(ids);
}
}
- auto& holders = dsc->holders;
- if (!holders.acl->match(remote)) {
+ if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
++dnsdist::metrics::g_stats.aclDrops;
vinfolog("Query from %s (DoH) dropped because of ACL", remote.toStringWithPort());
h2o_send_error_403(req, "Forbidden", "DoH query not allowed because of ACL", 0);
return;
}
- if (dsc->dohFrontend->d_earlyACLDrop && !dsc->dohFrontend->d_trustForwardedForHeader && !dsc->holders.acl->match(remote)) {
+ if (dsc->dohFrontend->d_earlyACLDrop && !dsc->dohFrontend->d_trustForwardedForHeader && !dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
++dnsdist::metrics::g_stats.aclDrops;
vinfolog("Dropping DoH connection from %s because of ACL", remote.toStringWithPort());
h2o_socket_close(sock);
}
}
if (!dohUnit->truncated) {
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
DNSResponse dnsResponse(dohUnit->ids, udpResponse, dohUnit->downstream);
dnsheader cleartextDH{};
memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
dnsResponse.ids.du = std::move(dohUnit);
- if (!processResponse(udpResponse, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+ if (!processResponse(udpResponse, dnsResponse, false)) {
if (dnsResponse.ids.du) {
dohUnit = getDUFromIDS(dnsResponse.ids);
dohUnit->status_code = 503;
+++ /dev/null
-../doh.hh
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "config.h"
+
+#ifdef HAVE_DNS_OVER_HTTPS
+#ifdef HAVE_LIBH2OEVLOOP
+
+#include <ctime>
+#include <memory>
+#include <string>
+
+struct CrossProtocolQuery;
+struct DNSQuestion;
+
+std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse);
+
+#include "dnsdist-doh-common.hh"
+
+struct H2ODOHFrontend : public DOHFrontend
+{
+public:
+ void setup() override;
+ void reloadCertificates() override;
+
+ void rotateTicketsKey(time_t now) override;
+ void loadTicketsKeys(const std::string& keyFile) override;
+ void handleTicketsKeyRotation() override;
+ std::string getNextTicketsKeyRotation() const override;
+ size_t getTicketsKeysCount() override;
+};
+
+void dohThread(ClientState* clientState);
+
+#endif /* HAVE_LIBH2OEVLOOP */
+#endif /* HAVE_DNS_OVER_HTTPS */
using ConnectionsMap = std::map<PacketBuffer, H3Connection>;
- LocalHolders holders;
ConnectionsMap d_connections;
QuicheConfig config;
QuicheHTTP3Config http3config;
if (!response.isAsync()) {
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
dnsResponse.ids.doh3u = std::move(unit);
- if (!processResponse(dnsResponse.ids.doh3u->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+ if (!processResponse(dnsResponse.ids.doh3u->response, dnsResponse, false)) {
if (dnsResponse.ids.doh3u) {
sendBackDOH3Unit(std::move(dnsResponse.ids.doh3u), "Response dropped by rules");
remote = unit->ids.origRemote;
DOH3ServerConfig* dsc = unit->dsc;
- auto& holders = dsc->holders;
ClientState& clientState = *dsc->clientState;
- if (!holders.acl->match(remote)) {
+ if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
vinfolog("Query from %s (DoH3) dropped because of ACL", remote.toStringWithPort());
++dnsdist::metrics::g_stats.aclDrops;
unit->response.clear();
});
unit->ids.cs = &clientState;
- auto result = processQuery(dnsQuestion, holders, downstream);
+ auto result = processQuery(dnsQuestion, downstream);
if (result == ProcessQueryResult::Drop) {
unit->status_code = 403;
handleImmediateResponse(std::move(unit), "DoH3 dropped query");
using ConnectionsMap = std::map<PacketBuffer, Connection>;
- LocalHolders holders;
ConnectionsMap d_connections;
QuicheConfig config;
ClientState* clientState{nullptr};
memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
if (!response.isAsync()) {
-
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
- static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
dnsResponse.ids.doqu = std::move(unit);
- if (!processResponse(dnsResponse.ids.doqu->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+ if (!processResponse(dnsResponse.ids.doqu->response, dnsResponse, false)) {
if (dnsResponse.ids.doqu) {
sendBackDOQUnit(std::move(dnsResponse.ids.doqu), "Response dropped by rules");
{
size_t pos = 0;
while (pos < response.size()) {
+#ifdef HAVE_QUICHE_STREAM_ERROR_CODES
+ uint64_t quicheErrorCode{0};
+ auto res = quiche_conn_stream_send(conn.d_conn.get(), streamID, &response.at(pos), response.size() - pos, true, &quicheErrorCode);
+#else
auto res = quiche_conn_stream_send(conn.d_conn.get(), streamID, &response.at(pos), response.size() - pos, true);
+#endif
if (res == QUICHE_ERR_DONE) {
response.erase(response.begin(), response.begin() + static_cast<ssize_t>(pos));
return false;
remote = unit->ids.origRemote;
DOQServerConfig* dsc = unit->dsc;
- auto& holders = dsc->holders;
ClientState& clientState = *dsc->clientState;
- if (!holders.acl->match(remote)) {
+ if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
vinfolog("Query from %s (DoQ) dropped because of ACL", remote.toStringWithPort());
++dnsdist::metrics::g_stats.aclDrops;
unit->response.clear();
});
unit->ids.cs = &clientState;
- auto result = processQuery(dnsQuestion, holders, downstream);
+ auto result = processQuery(dnsQuestion, downstream);
if (result == ProcessQueryResult::Drop) {
handleImmediateResponse(std::move(unit), "DoQ dropped query");
return;
bool fin = false;
auto existingLength = streamBuffer.size();
streamBuffer.resize(existingLength + 512);
+#ifdef HAVE_QUICHE_STREAM_ERROR_CODES
+ uint64_t quicheErrorCode{0};
+ auto received = quiche_conn_stream_recv(conn.d_conn.get(), streamID,
+ &streamBuffer.at(existingLength), 512,
+ &fin,
+ &quicheErrorCode);
+#else
auto received = quiche_conn_stream_recv(conn.d_conn.get(), streamID,
&streamBuffer.at(existingLength), 512,
&fin);
+#endif
if (received == 0 || received == QUICHE_ERR_DONE) {
streamBuffer.resize(existingLength);
return;
AS_IF([test "x$with_quiche" != "xno"], [
AS_IF([test "x$with_quiche" = "xyes" -o "x$with_quiche" = "xauto"], [
- PKG_CHECK_MODULES([QUICHE], [quiche >= 0.15.0], [
+ PKG_CHECK_MODULES([QUICHE], [quiche >= 0.22.0], [
[HAVE_QUICHE=1]
AC_DEFINE([HAVE_QUICHE], [1], [Define to 1 if you have quiche])
- ], [ : ])
+ AC_DEFINE([HAVE_QUICHE_STREAM_ERROR_CODES], [1], [Define to 1 if the Quiche API includes error code in quiche_conn_stream_recv and quiche_conn_stream_send])
+ ], [
+ # Quiche is older than 0.22.0, or no Quiche at all
+ PKG_CHECK_MODULES([QUICHE], [quiche >= 0.15.0], [
+ [HAVE_QUICHE=1]
+ AC_DEFINE([HAVE_QUICHE], [1], [Define to 1 if you have quiche])
+ ], [ : ])
+ ])
])
])
AM_CONDITIONAL([HAVE_QUICHE], [test "x$QUICHE_LIBS" != "x"])
#include "dolog.hh"
#include <unistd.h>
-bool g_verbose{false};
-
BOOST_AUTO_TEST_SUITE(test_dnscrypt_cc)
#ifdef HAVE_DNSCRYPT
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 3U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::A));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, newTarget);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::AAAA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, newTarget);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_type, static_cast<uint16_t>(QType::OPT));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_name, g_rootdnsname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::A));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, newTarget);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::AAAA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, newTarget);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_type, static_cast<uint16_t>(QType::OPT));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_name, g_rootdnsname);
}
{
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 3U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::A));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, newTarget);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::AAAA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, notTheTarget);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_type, static_cast<uint16_t>(QType::OPT));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_name, g_rootdnsname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::A));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, newTarget);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::AAAA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, notTheTarget);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_type, static_cast<uint16_t>(QType::OPT));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_name, g_rootdnsname);
}
{
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 3U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::CNAME));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, newTarget);
- auto content = getRR<UnknownRecordContent>(mdp.d_answers.at(0).first);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::CNAME));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, newTarget);
+ auto content = getRR<UnknownRecordContent>(mdp.d_answers.at(0));
BOOST_REQUIRE(content != nullptr);
BOOST_CHECK_EQUAL(content->getRawContent().size(), notTheTarget.getStorage().size());
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::A));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, notTheTarget);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_type, static_cast<uint16_t>(QType::OPT));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_name, g_rootdnsname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::A));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, notTheTarget);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_type, static_cast<uint16_t>(QType::OPT));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_name, g_rootdnsname);
}
{
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 7U);
for (const auto& answer : mdp.d_answers) {
- if (answer.first.d_type == QType::OPT) {
+ if (answer.d_type == QType::OPT) {
continue;
}
- BOOST_CHECK_EQUAL(answer.first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(answer.first.d_name, newTarget);
+ BOOST_CHECK_EQUAL(answer.d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(answer.d_name, newTarget);
}
}
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 8U);
for (const auto& answer : mdp.d_answers) {
- if (answer.first.d_type == QType::OPT) {
+ if (answer.d_type == QType::OPT) {
continue;
}
- BOOST_CHECK_EQUAL(answer.first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(answer.first.d_name, target);
+ BOOST_CHECK_EQUAL(answer.d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(answer.d_name, target);
}
}
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 8U);
for (const auto& answer : mdp.d_answers) {
- if (answer.first.d_type == QType::OPT) {
+ if (answer.d_type == QType::OPT) {
continue;
}
- BOOST_CHECK_EQUAL(answer.first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(answer.first.d_name, newTarget);
+ BOOST_CHECK_EQUAL(answer.d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(answer.d_name, newTarget);
}
}
}
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::ALIAS));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, target);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::ALIAS));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, target);
}
}
#include <boost/test/unit_test.hpp>
#include "dnsdist-lua-ffi.hh"
+#include "dnsdist-cache.hh"
+#include "dnsdist-configuration.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-web.hh"
#include "dnsparser.hh"
#include "dnswriter.hh"
-bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def)
+bool dnsdist::webserver::addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def)
{
return true;
}
}
{
- BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), g_ECSSourcePrefixV4);
+ BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV4);
dnsdist_ffi_dnsquestion_set_ecs_prefix_length(&lightDQ, 65535);
BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), 65535U);
}
{
BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_trailing_data(&lightDQ, nullptr), 0U);
-#if 0
- // DNSQuestion::setTrailingData() and DNSQuestion::getTrailingData() are currently stubs in the test runner
std::string garbage("thisissomegarbagetrailingdata");
BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_set_trailing_data(&lightDQ, garbage.data(), garbage.size()), true);
const char* buffer = nullptr;
BOOST_REQUIRE_EQUAL(dnsdist_ffi_dnsquestion_get_trailing_data(&lightDQ, &buffer), garbage.size());
BOOST_CHECK_EQUAL(garbage, std::string(buffer));
-#endif
}
{
testPool->packetCache = packetCache;
std::string poolWithNoCacheName("test-pool-without-cache");
auto testPoolWithNoCache = std::make_shared<ServerPool>();
- auto localPools = g_pools.getCopy();
- localPools.emplace(poolName, testPool);
- localPools.emplace(poolWithNoCacheName, testPoolWithNoCache);
- g_pools.setState(localPools);
+ dnsdist::configuration::updateRuntimeConfiguration([&poolName, &testPool, &poolWithNoCacheName, &testPoolWithNoCache](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_pools.emplace(poolName, testPool);
+ config.d_pools.emplace(poolWithNoCacheName, testPoolWithNoCache);
+ });
{
dnsdist_ffi_domain_list_t* list = nullptr;
}
}
+BOOST_AUTO_TEST_CASE(test_ProxyProtocolQuery)
+{
+ InternalQueryState ids;
+ ids.origRemote = ComboAddress("192.0.2.1:4242");
+ ids.origDest = ComboAddress("192.0.2.255:53");
+ ids.qtype = QType::A;
+ ids.qclass = QClass::IN;
+ ids.protocol = dnsdist::Protocol::DoUDP;
+ ids.qname = DNSName("www.powerdns.com.");
+ ids.queryRealTime.start();
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+ pwQ.getHeader()->id = htons(42);
+
+ DNSQuestion dnsQuestion(ids, query);
+ dnsdist_ffi_dnsquestion_t lightDQ(&dnsQuestion);
+
+ std::vector<dnsdist_ffi_proxy_protocol_value> values;
+ values.push_back({"test-value", 10U, 1U});
+
+ {
+ auto added = dnsdist_ffi_dnsquestion_add_proxy_protocol_values(nullptr, values.size(), values.data());
+ BOOST_CHECK_EQUAL(added, false);
+ }
+
+ {
+ auto added = dnsdist_ffi_dnsquestion_add_proxy_protocol_values(&lightDQ, 0, values.data());
+ BOOST_CHECK_EQUAL(added, false);
+ }
+
+ {
+ auto added = dnsdist_ffi_dnsquestion_add_proxy_protocol_values(&lightDQ, values.size(), nullptr);
+ BOOST_CHECK_EQUAL(added, false);
+ }
+
+ {
+ auto added = dnsdist_ffi_dnsquestion_add_proxy_protocol_values(&lightDQ, values.size(), values.data());
+ BOOST_CHECK_EQUAL(added, true);
+ BOOST_REQUIRE(dnsQuestion.proxyProtocolValues != nullptr);
+ BOOST_REQUIRE_EQUAL(dnsQuestion.proxyProtocolValues->size(), values.size());
+ BOOST_CHECK_EQUAL(dnsQuestion.proxyProtocolValues->at(0).type, values.at(0).type);
+ BOOST_REQUIRE_EQUAL(dnsQuestion.proxyProtocolValues->at(0).content.size(), values.at(0).size);
+ BOOST_CHECK_EQUAL(memcmp(dnsQuestion.proxyProtocolValues->at(0).content.data(), values.at(0).value, values.at(0).size), 0);
+ }
+}
+
BOOST_AUTO_TEST_CASE(test_PacketOverlay)
{
const DNSName target("powerdns.com.");
gettime(&now);
g_rings.reset();
- g_rings.init();
+ g_rings.init(10000, 10);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
}
}
+BOOST_AUTO_TEST_CASE(test_SVC_Generation)
+{
+ dnsdist_ffi_svc_record_parameters* parameters{nullptr};
+
+ {
+ /* invalid parameters */
+ BOOST_CHECK_EQUAL(dnsdist_ffi_svc_record_parameters_new(nullptr, 0, false, ¶meters), false);
+ BOOST_CHECK_EQUAL(dnsdist_ffi_svc_record_parameters_new("powerdns.com.", 0, false, nullptr), false);
+ }
+
+ BOOST_REQUIRE_EQUAL(dnsdist_ffi_svc_record_parameters_new("powerdns.com.", 1, true, ¶meters), true);
+ BOOST_REQUIRE(parameters != nullptr);
+
+ {
+ /* invalid parameters */
+ dnsdist_ffi_svc_record_parameters_set_port(nullptr, 0);
+ dnsdist_ffi_svc_record_parameters_set_ech(nullptr, "alpn", 4);
+ dnsdist_ffi_svc_record_parameters_set_additional_param(nullptr, 7, "/dns-query{?dns}", 16);
+ dnsdist_ffi_svc_record_parameters_set_additional_param(parameters, 7, nullptr, 0);
+ dnsdist_ffi_svc_record_parameters_add_mandatory_param(nullptr, 0);
+ dnsdist_ffi_svc_record_parameters_add_alpn(nullptr, "h2", 2);
+ dnsdist_ffi_svc_record_parameters_add_alpn(parameters, nullptr, 0);
+ dnsdist_ffi_svc_record_parameters_add_ipv4_hint(parameters, nullptr, 0);
+ dnsdist_ffi_svc_record_parameters_add_ipv4_hint(nullptr, nullptr, 0);
+ dnsdist_ffi_svc_record_parameters_add_ipv6_hint(parameters, nullptr, 0);
+ dnsdist_ffi_svc_record_parameters_add_ipv6_hint(nullptr, nullptr, 0);
+ dnsdist_ffi_dnsquestion_generate_svc_response(nullptr, nullptr, 0, 0);
+ }
+
+ dnsdist_ffi_svc_record_parameters_set_port(parameters, 443);
+ dnsdist_ffi_svc_record_parameters_set_ech(parameters, "binary", 6);
+ dnsdist_ffi_svc_record_parameters_set_additional_param(parameters, 7, "/dns-query{?dns}", 16);
+ dnsdist_ffi_svc_record_parameters_add_mandatory_param(parameters, 7);
+ dnsdist_ffi_svc_record_parameters_add_alpn(parameters, "h2", 2);
+ dnsdist_ffi_svc_record_parameters_add_ipv4_hint(parameters, "9.9.9.9", 8);
+ dnsdist_ffi_svc_record_parameters_add_ipv6_hint(parameters, "2620:fe::fe", 11);
+
+ {
+ InternalQueryState ids;
+ ids.origRemote = ComboAddress("192.0.2.1:4242");
+ ids.origDest = ComboAddress("192.0.2.255:53");
+ ids.qtype = QType::A;
+ ids.qclass = QClass::IN;
+ ids.protocol = dnsdist::Protocol::DoUDP;
+ ids.qname = DNSName("www.powerdns.com.");
+ ids.queryRealTime.start();
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+ pwQ.getHeader()->id = htons(42);
+
+ DNSQuestion dnsQuestion(ids, query);
+ dnsdist_ffi_dnsquestion_t lightDQ(&dnsQuestion);
+ std::array<const dnsdist_ffi_svc_record_parameters*, 1> list = {parameters};
+ BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_generate_svc_response(&lightDQ, list.data(), list.size(), 42), true);
+ }
+
+ dnsdist_ffi_svc_record_parameters_free(parameters);
+}
+
BOOST_AUTO_TEST_SUITE_END();
#include "dnsdist.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-internal-queries.hh"
+#include "dnsdist-snmp.hh"
#include "dnsdist-tcp.hh"
#include "dnsdist-xsk.hh"
#include "ednscookies.hh"
#include "ednssubnet.hh"
-ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
{
return ProcessQueryResult::Drop;
}
-bool processResponseAfterRules(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted)
+bool processResponseAfterRules(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
{
return false;
}
#ifdef HAVE_XSK
namespace dnsdist::xsk
{
-bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket& packet)
+bool XskProcessQuery(ClientState& clientState, XskPacket& packet)
{
return false;
}
}
#endif /* HAVE_XSK */
-bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& localRespRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids)
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, InternalQueryState&& ids)
{
return false;
}
auto dnsQuestion = DNSQuestion(ids, query);
- return getEDNSZ(dnsQuestion);
+ return dnsdist::getEDNSZ(dnsQuestion);
}
BOOST_AUTO_TEST_CASE(test_getEDNSZ)
}
}
+BOOST_AUTO_TEST_CASE(test_getEDNSVersion)
+{
+ const DNSName qname("www.powerdns.com.");
+ const uint16_t qtype = QType::A;
+ const uint16_t qclass = QClass::IN;
+ const GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+
+ auto getVersion = [&qname](PacketBuffer& query) {
+ InternalQueryState ids;
+ ids.protocol = dnsdist::Protocol::DoUDP;
+ ids.qname = qname;
+ ids.qtype = qtype;
+ ids.qclass = qclass;
+ ids.origDest = ComboAddress("127.0.0.1");
+ ids.origRemote = ComboAddress("127.0.0.1");
+ ids.queryRealTime.start();
+
+ auto dnsQuestion = DNSQuestion(ids, query);
+
+ return dnsdist::getEDNSVersion(dnsQuestion);
+ };
+
+ {
+ /* no EDNS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+ packetWriter.commit();
+
+ BOOST_CHECK(getVersion(query) == std::nullopt);
+ }
+
+ {
+ /* truncated EDNS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+ packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
+ packetWriter.commit();
+
+ query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* TTL */ 2));
+ BOOST_CHECK(getVersion(query) == std::nullopt);
+ }
+
+ {
+ /* valid EDNS, no options */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+ packetWriter.addOpt(512, 0, 0);
+ packetWriter.commit();
+
+ BOOST_CHECK_EQUAL(*getVersion(query), 0U);
+ }
+
+ {
+ /* EDNS version 255 */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+ packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts, 255U);
+ packetWriter.commit();
+
+ BOOST_CHECK_EQUAL(*getVersion(query), 255U);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_getEDNSExtendedRCode)
+{
+ const DNSName qname("www.powerdns.com.");
+ const uint16_t qtype = QType::A;
+ const uint16_t qclass = QClass::IN;
+
+ auto getExtendedRCode = [&qname](PacketBuffer& query) {
+ InternalQueryState ids;
+ ids.protocol = dnsdist::Protocol::DoUDP;
+ ids.qname = qname;
+ ids.qtype = qtype;
+ ids.qclass = qclass;
+ ids.origDest = ComboAddress("127.0.0.1");
+ ids.origRemote = ComboAddress("127.0.0.1");
+ ids.queryRealTime.start();
+
+ auto dnsQuestion = DNSQuestion(ids, query);
+
+ return dnsdist::getEDNSExtendedRCode(dnsQuestion);
+ };
+
+ {
+ /* no EDNS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+ packetWriter.commit();
+
+ BOOST_CHECK(getExtendedRCode(query) == std::nullopt);
+ }
+
+ {
+ /* truncated EDNS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+ packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
+ packetWriter.commit();
+
+ query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* TTL */ 2));
+ BOOST_CHECK(getExtendedRCode(query) == std::nullopt);
+ }
+
+ {
+ /* valid EDNS, no options */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+ packetWriter.addOpt(512, 0, 0);
+ packetWriter.commit();
+
+ BOOST_CHECK_EQUAL(*getExtendedRCode(query), 0U);
+ }
+
+ {
+ /* EDNS extended RCode 4095 (15 for the normal RCode, 255 for the EDNS part) */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+ packetWriter.addOpt(512, 4095U, EDNS_HEADER_FLAG_DO);
+ packetWriter.commit();
+
+ BOOST_CHECK_EQUAL(*getExtendedRCode(query), 255U);
+ }
+}
+
BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
{
InternalQueryState ids;
packetWriter.commit();
auto dnsQuestion = turnIntoResponse(ids, query);
- BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), 0);
+ BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
+ BOOST_CHECK(dnsdist::getEDNSVersion(dnsQuestion) == std::nullopt);
+ BOOST_CHECK(dnsdist::getEDNSExtendedRCode(dnsQuestion) == std::nullopt);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), false);
BOOST_CHECK_EQUAL(zValue, 0);
query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
auto dnsQuestion = turnIntoResponse(ids, query, false);
- BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), 0);
+ BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
+ BOOST_CHECK(dnsdist::getEDNSVersion(dnsQuestion) == std::nullopt);
+ BOOST_CHECK(dnsdist::getEDNSExtendedRCode(dnsQuestion) == std::nullopt);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), false);
BOOST_CHECK_EQUAL(zValue, 0);
packetWriter.commit();
auto dnsQuestion = turnIntoResponse(ids, query);
- BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), 0);
+ BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
+ BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
+ BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
BOOST_CHECK_EQUAL(zValue, 0);
- BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+ BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
}
{
packetWriter.commit();
auto dnsQuestion = turnIntoResponse(ids, query);
- BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
+ BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
+ BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
+ BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
- BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+ BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
}
{
packetWriter.commit();
auto dnsQuestion = turnIntoResponse(ids, query);
- BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), 0);
+ BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
+ BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
+ BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
BOOST_CHECK_EQUAL(zValue, 0);
- BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+ BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
}
{
packetWriter.commit();
auto dnsQuestion = turnIntoResponse(ids, query);
- BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
+ BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
+ BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
+ BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
- BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+ BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
}
}
packetWriter.getHeader()->rcode = RCode::NXDomain;
packetWriter.commit();
- int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+ int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, ENOENT);
/* truncated packet (should not matter) */
query.resize(query.size() - 1);
- res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+ res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, ENOENT);
}
packetWriter.addOpt(512, 0, 0);
packetWriter.commit();
- int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+ int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
/* truncated packet */
query.resize(query.size() - 1);
- res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+ res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, ENOENT);
}
packetWriter.addOpt(512, 0, 0, opts);
packetWriter.commit();
- int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+ int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
/* truncated options (should not matter for this test) */
query.resize(query.size() - 1);
- res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+ res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
BOOST_CHECK_EQUAL(remaining, query.size() - optRDExpectedOffset);
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
}
{
/* now with incoming EDNS */
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
}
/* test No Data */
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
}
{
/* now with incoming EDNS */
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
}
/* SOA in the authority section*/
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
}
{
/* now with incoming EDNS */
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
}
/* test No Data */
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
}
{
/* now with incoming EDNS */
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
}
}
BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::OPT));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, g_rootdnsname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::OPT));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, g_rootdnsname);
EDNS0Record edns0{};
BOOST_REQUIRE(getEDNS0Record(dnsQuestion.getData(), edns0));
BOOST_CHECK_EQUAL(edns0.version, 0U);
BOOST_CHECK_EQUAL(edns0.extRCode, 0U);
- BOOST_CHECK_EQUAL(edns0.extFlags, EDNS_HEADER_FLAG_DO);
+ BOOST_CHECK_EQUAL(ntohs(edns0.extFlags), EDNS_HEADER_FLAG_DO);
BOOST_REQUIRE(parseEDNSOptions(dnsQuestion));
BOOST_REQUIRE(dnsQuestion.ednsOptions != nullptr);
// the event should be triggered after 10 ms, but we have seen
// many spurious failures on our CI, likely because the box is
// overloaded, so sleep for up to 100 ms to be sure
- for (size_t counter = 0; !holder->empty() && counter < 10; counter++) {
+ for (size_t counter = 0; counter < 10; counter++) {
+ if (holder->empty() && sender->errorRaised.load()) {
+ break;
+ }
usleep(10000);
}
// but we have seen many spurious failures on our CI,
// likely because the box is overloaded, so sleep for up to
// 100 ms to be sure
- for (size_t counter = 0; !holder->empty() && counter < 10; counter++) {
+ for (size_t counter = 0; counter < 10; counter++) {
+ if (holder->empty() && sender->errorRaised.load()) {
+ break;
+ }
usleep(10000);
}
TestFixture()
{
g_rings.reset();
- g_rings.init();
+ g_rings.init(10000, 10);
}
~TestFixture()
{
size_t numberOfQueries = 45 * numberOfSeconds;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
size_t numberOfQueries = (50 * numberOfSeconds) + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
/* clear the rings and dynamic blocks */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
/* Insert 100 qps from a given client in the last 10s
this should trigger the rule */
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries * numberOfSeconds);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
/* now we clean up the dynamic blocks, simulating an admin removing the block */
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
/* we apply the rules again, but as if we were 20s in the future.
Since we have a time windows of 10s nothing should be added,
regardless of the number of queries
struct timespec later = now;
later.tv_sec += 20;
dbrg.apply(later);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
/* just in case */
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
/* we apply the rules again, this tile as if we were 5s in the future.
Since we have a time windows of 10s, and 100 qps over 5s then 0 qps over 5s
later = now;
later.tv_sec += 5;
dbrg.apply(later);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
/* clean up */
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
/* we apply the rules again, this tile as if we were 6s in the future.
Since we have a time windows of 10s, and 100 qps over 4s then 0 qps over 6s
later = now;
later.tv_sec += 6;
dbrg.apply(later);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
}
}
size_t numberOfQueries = 45 * numberOfSeconds;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(requestor1, 128, 16)) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(requestor1, 128, 16)) == nullptr);
}
{
size_t numberOfQueries = (50 * numberOfSeconds) + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
ComboAddress requestor("2001:db8::" + std::to_string(idx));
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
{
/* beginning of the range should be blocked */
- const auto& block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(requestor1, 128, 16))->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(requestor1, 128, 16))->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
{
/* end of the range should be blocked as well */
ComboAddress end("2001:0db8:0000:0000:ffff:ffff:ffff:ffff");
- const auto& block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(end, 128, 16))->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(end, 128, 16))->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
{
/* outside of the range should NOT */
ComboAddress out("2001:0db8:0000:0001::0");
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(out, 128, 16)) == nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(out, 128, 16)) == nullptr);
}
}
}
size_t numberOfQueries = 45 * numberOfSeconds;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(requestor1, 128, 16)) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(requestor1, 128, 16)) == nullptr);
}
{
size_t numberOfQueries = (50 * numberOfSeconds) + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
ComboAddress requestor("192.0.2.1:" + std::to_string(idx));
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
{
/* beginning of the port range should be blocked */
- const auto& block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16))->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16))->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
{
/* end of the range should be blocked as well */
- const auto& block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16383"), 32, 16))->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16383"), 32, 16))->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
{
/* outside of the range should not */
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16384"), 32, 16)) == nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16384"), 32, 16)) == nullptr);
}
/* we (again) insert just above 50 qps from several clients the same IPv4 port range, this should update the block which will
check by looking at the blocked counter */
{
- auto block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16));
+ auto* block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16));
BOOST_REQUIRE(block != nullptr);
BOOST_CHECK_EQUAL(block->second.blocks, 0U);
block->second.blocks = 42U;
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
{
/* previous address/port should still be blocked */
- auto block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16));
+ auto* block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16));
BOOST_REQUIRE(block != nullptr);
BOOST_CHECK_EQUAL(block->second.blocks, 42U);
}
/* but not a different one */
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16384"), 32, 16)) == nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16384"), 32, 16)) == nullptr);
}
}
/* 100k entries, one shard */
g_rings.reset();
- g_rings.setCapacity(1000000, 1);
- g_rings.init();
+ g_rings.init(1000000, 1);
size_t numberOfSeconds = 10;
size_t blockDuration = 60;
size_t numberOfQueries = 45;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t timeIdx = 0; timeIdx < 100; timeIdx++) {
struct timespec when = now;
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries * 100);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
}
size_t numberOfQueries = 45 * numberOfSeconds;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
size_t numberOfQueries = 50 * numberOfSeconds + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, QType::A, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
size_t numberOfQueries = 50 * numberOfSeconds + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
size_t numberOfResponses = 45 * numberOfSeconds;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
size_t numberOfResponses = 50 * numberOfSeconds + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = RCode::FormErr;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
size_t numberOfResponses = 50 * numberOfSeconds + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
this should not trigger the rule */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < 20; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
/* insert just 50 FormErrs and nothing else, from a given client in the last 10s */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = RCode::FormErr;
for (size_t idx = 0; idx < 50; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
this should trigger the rule this time */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < 21; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_REQUIRE(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_REQUIRE(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(block.until.tv_sec, now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
this should NOT trigger the rule since we don't have more than 50 queries */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < 11; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
}
size_t numberOfResponses = 99 * numberOfSeconds;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
size_t numberOfResponses = 100 * numberOfSeconds + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
this should not trigger the rule */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < 20; idx++) {
g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
this should trigger the rule this time */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < 51; idx++) {
g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_REQUIRE(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_REQUIRE(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(block.until.tv_sec, now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
this should NOT trigger the rule since we don't have more than 50 queries */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < 40; idx++) {
g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
/* the global cache-hit rate is too low, should not trigger */
/* insert 51 cache misses and 49 hits from a given client in the last 10s */
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < 51; idx++) {
g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_REQUIRE(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_REQUIRE(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
}
size_t numberOfQueries = 20 * numberOfSeconds;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
}
{
size_t numberOfQueries = 20 * numberOfSeconds + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
{
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
{
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
{
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
/* should have been updated */
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
size_t numberOfQueries = 50 * numberOfSeconds + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
{
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
size_t numberOfQueries = 50 * numberOfSeconds + 1;
g_rings.clear();
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
for (size_t idx = 0; idx < numberOfQueries; idx++) {
g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries * 2);
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
- BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+ BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
BOOST_CHECK_EQUAL(block.reason, reason);
BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
BOOST_CHECK(block.domain.empty());
g_rings.reset();
/* 10M entries, only one shard */
- g_rings.setCapacity(10000000, 1);
- g_rings.init();
+ g_rings.init(10000000, 1);
{
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
g_rings.clear();
- g_dynblockNMG.setState(emptyNMG);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
{
/* block above 0 qps for numberOfSeconds seconds, no warning */
/* we apply the rules, all clients should be blocked */
dbrg.apply(now);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 256U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 256U);
for (size_t idx = 0; idx < 256; idx++) {
const ComboAddress requestor("192.0.2." + std::to_string(idx));
- const auto& block = g_dynblockNMG.getLocal()->lookup(requestor)->second;
+ const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor)->second;
/* simulate that:
- .1 does 1 query
...
struct timespec expired = now;
expired.tv_sec += blockDuration + 1;
DynBlockMaintenance::purgeExpired(expired);
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
}
{
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
g_rings.clear();
- g_dynblockNMG.setState(emptyNMG);
- g_dynblockSMT.setState(emptySMT);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+ dnsdist::DynamicBlocks::clearSuffixDynamicRules();
{
DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
for (size_t idx = 0; idx < 256; idx++) {
const DNSName name(DNSName(std::to_string(idx)) + qname);
- const auto* block = g_dynblockSMT.getLocal()->lookup(name);
+ const auto* block = dnsdist::DynamicBlocks::getSuffixDynamicRules().lookup(name);
BOOST_REQUIRE(block != nullptr);
BOOST_REQUIRE(block->action == action);
/* simulate that:
struct timespec expired = now;
expired.tv_sec += blockDuration + 1;
DynBlockMaintenance::purgeExpired(expired);
- BOOST_CHECK(g_dynblockSMT.getLocal()->getNodes().empty());
+ BOOST_CHECK(dnsdist::DynamicBlocks::getSuffixDynamicRules().getNodes().empty());
}
{
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
g_rings.clear();
- g_dynblockNMG.setState(emptyNMG);
- g_dynblockSMT.setState(emptySMT);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+ dnsdist::DynamicBlocks::clearSuffixDynamicRules();
{
DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
for (size_t idx = 0; idx < 256; idx++) {
const DNSName name(DNSName(std::to_string(idx)) + qname);
- const auto* block = g_dynblockSMT.getLocal()->lookup(name);
+ const auto* block = dnsdist::DynamicBlocks::getSuffixDynamicRules().lookup(name);
BOOST_REQUIRE(block != nullptr);
BOOST_REQUIRE(block->action == DNSAction::Action::Truncate);
/* simulate that:
struct timespec expired = now;
expired.tv_sec += blockDuration + 1;
DynBlockMaintenance::purgeExpired(expired);
- BOOST_CHECK(g_dynblockSMT.getLocal()->getNodes().empty());
+ BOOST_CHECK(dnsdist::DynamicBlocks::getSuffixDynamicRules().getNodes().empty());
}
#ifdef BENCH_DYNBLOCKS
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
g_rings.clear();
- g_dynblockNMG.setState(emptyNMG);
- g_dynblockSMT.setState(emptySMT);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+ dnsdist::DynamicBlocks::clearSuffixDynamicRules();
{
DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
sw.start();
DynBlockMaintenance::purgeExpired(expired);
cerr<<"removed 1000000 entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
- BOOST_CHECK_EQUAL(g_dynblockSMT.getLocal()->getNodes().size(), 0U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getSuffixDynamicRules().getNodes().size(), 0U);
}
#endif
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
g_rings.clear();
- g_dynblockNMG.setState(emptyNMG);
- g_dynblockSMT.setState(emptySMT);
+ dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+ dnsdist::DynamicBlocks::clearSuffixDynamicRules();
{
DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
dbrg.setQueryRate(std::move(rule));
StopWatch sw;
sw.start();
dbrg.apply(now);
- cerr<<"added "<<g_dynblockNMG.getLocal()->size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1000000U);
+ cerr<<"added "<<dnsdist::DynamicBlocks::getClientAddressDynamicRules().size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1000000U);
sw.start();
auto top = DynBlockMaintenance::getTopNetmasks(20);
- cerr<<"scanned "<<g_dynblockNMG.getLocal()->size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
+ cerr<<"scanned "<<dnsdist::DynamicBlocks::getClientAddressDynamicRules().size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
struct timespec expired = now;
expired.tv_sec += blockDuration + 1;
sw.start();
DynBlockMaintenance::purgeExpired(expired);
cerr<<"removed 1000000 entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
- BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+ BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
}
#endif
}
#include "dnsdist.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-lua-ffi.hh"
+#include "dnsdist-snmp.hh"
#include "dolog.hh"
-uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
-
#include "ext/luawrapper/include/LuaContext.hpp"
-LockGuarded<LuaContext> g_lua{LuaContext()};
+RecursiveLockGuarded<LuaContext> g_lua{LuaContext()};
-bool g_snmpEnabled{false};
-bool g_snmpTrapsEnabled{false};
std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent{nullptr};
#if BENCH_POLICIES
-bool g_verbose{true};
#include "dnsdist-rings.hh"
Rings g_rings;
-GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
-GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
#endif /* BENCH_POLICIES */
-GlobalStateHolder<pools_t> g_pools;
-std::vector<std::unique_ptr<ClientState>> g_frontends;
-
/* add stub implementations, we don't want to include the corresponding object files
and their dependencies */
return true;
}
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
-std::string DNSQuestion::getTrailingData() const
-{
- return "";
-}
-
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
-bool DNSQuestion::setTrailingData(const std::string& tail)
-{
- return false;
-}
-
// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dnsQuestion, const std::string& reason)
{
}
string g_outputBuffer;
-std::atomic<bool> g_configurationDone{false};
static DNSQuestion getDQ(const DNSName* providedName = nullptr)
{
static void benchPolicy(const ServerPolicy& pol)
{
#if BENCH_POLICIES
- bool existingVerboseValue = g_verbose;
- g_verbose = false;
-
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
}
}
cerr << pol.name << " took " << std::to_string(sw.udiff()) << " us for " << names.size() << endl;
-
- g_verbose = existingVerboseValue;
#endif /* BENCH_POLICIES */
}
{
/* we need to reset this before cleaning the Lua state because the server policy might holds
a reference to a Lua function (Lua policies) */
- g_policy.setState(ServerPolicy("leastOutstanding", leastOutstanding, false));
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::make_shared<ServerPolicy>("leastOutstanding", leastOutstanding, false);
+ });
+ /* we actually need this line to clear the cached state for this thread */
+ BOOST_REQUIRE_EQUAL(dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName(), "leastOutstanding");
*(g_lua.lock()) = LuaContext();
}
BOOST_AUTO_TEST_SUITE(dnsdistlbpolicies)
+#if 0
BOOST_AUTO_TEST_CASE(test_firstAvailable)
{
auto dnsQuestion = getDQ();
ServerPolicy::NumberedServerVector servers;
/* selecting a server on an empty server list */
- g_roundrobinFailOnNoServer = false;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_roundrobinFailOnNoServer = false;
+ });
auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server == nullptr);
servers.emplace_back(1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")));
- /* servers start as 'down' but the RR policy returns a server unless g_roundrobinFailOnNoServer is set */
- g_roundrobinFailOnNoServer = true;
+ /* servers start as 'down' but the RR policy returns a server unless d_roundrobinFailOnNoServer is set */
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_roundrobinFailOnNoServer = true;
+ });
server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server == nullptr);
- g_roundrobinFailOnNoServer = false;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_roundrobinFailOnNoServer = false;
+ });
server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server != nullptr);
BOOST_AUTO_TEST_CASE(test_chashed)
{
- bool existingVerboseValue = g_verbose;
- g_verbose = false;
+ bool existingVerboseValue = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_verbose = false;
+ });
std::vector<DNSName> names;
names.reserve(1000);
BOOST_CHECK_GT(got, expected / 2);
BOOST_CHECK_LT(got, expected * 2);
- g_verbose = existingVerboseValue;
+ dnsdist::configuration::updateRuntimeConfiguration([existingVerboseValue](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_verbose = existingVerboseValue;
+ });
}
+#endif
BOOST_AUTO_TEST_CASE(test_lua)
{
)foo";
resetLuaContext();
g_lua.lock()->writeFunction("setServerPolicyLua", [](const string& name, const ServerPolicy::policyfunc_t& policy) {
- g_policy.setState(ServerPolicy{name, policy, true});
+ auto pol = std::make_shared<ServerPolicy>(name, policy, true);
+ dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(pol);
+ });
});
g_lua.lock()->executeCode(policySetupStr);
{
- ServerPolicy pol = g_policy.getCopy();
+ const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+ BOOST_REQUIRE(pol != nullptr);
+ BOOST_REQUIRE(pol != nullptr);
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
for (const auto& name : names) {
auto dnsQuestion = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dnsQuestion);
+ auto server = pol->getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
}
BOOST_CHECK_EQUAL(total, names.size());
- benchPolicy(pol);
+ benchPolicy(*pol);
}
resetLuaContext();
}
-
+#if 0
#ifdef LUAJIT_VERSION
BOOST_AUTO_TEST_CASE(test_lua_ffi_rr)
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
- g_policy.setState(ServerPolicy(name, policy));
+ auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+ dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(pol);
+ });
});
g_lua.lock()->executeCode(policySetupStr);
{
- ServerPolicy pol = g_policy.getCopy();
+ const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+ BOOST_REQUIRE(pol != nullptr);
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
for (const auto& name : names) {
auto dnsQuestion = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dnsQuestion);
+ auto server = pol->getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
}
BOOST_CHECK_EQUAL(total, names.size());
- benchPolicy(pol);
+ benchPolicy(*pol);
}
resetLuaContext();
}
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& policyName, ServerPolicy::ffipolicyfunc_t policy) {
- g_policy.setState(ServerPolicy(policyName, std::move(policy)));
+ auto pol = std::make_shared<ServerPolicy>(policyName, std::move(policy));
+ dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(pol);
+ });
});
g_lua.lock()->executeCode(policySetupStr);
{
- ServerPolicy pol = g_policy.getCopy();
+ const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+ BOOST_REQUIRE(pol != nullptr);
ServerPolicy::NumberedServerVector servers;
for (size_t idx = 1; idx <= 10; idx++) {
servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
BOOST_REQUIRE_EQUAL(servers.size(), 10U);
auto dnsQuestion = getDQ(&dnsName);
- auto server = pol.getSelectedBackend(servers, dnsQuestion);
+ auto server = pol->getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server == nullptr);
}
resetLuaContext();
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
- g_policy.setState(ServerPolicy(name, policy));
+ auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+ dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(pol);
+ });
});
g_lua.lock()->executeCode(policySetupStr);
{
- ServerPolicy pol = g_policy.getCopy();
+ const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+ BOOST_REQUIRE(pol != nullptr);
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
for (const auto& name : names) {
auto dnsQuestion = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dnsQuestion);
+ auto server = pol->getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
}
BOOST_CHECK_EQUAL(total, names.size());
- benchPolicy(pol);
+ benchPolicy(*pol);
}
resetLuaContext();
}
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
- g_policy.setState(ServerPolicy(name, policy));
+ auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+ dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(pol);
+ });
});
g_lua.lock()->executeCode(policySetupStr);
{
- ServerPolicy pol = g_policy.getCopy();
+ const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+ BOOST_REQUIRE(pol != nullptr);
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
for (const auto& name : names) {
auto dnsQuestion = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dnsQuestion);
+ auto server = pol->getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
}
BOOST_CHECK_EQUAL(total, names.size());
- benchPolicy(pol);
+ benchPolicy(*pol);
}
resetLuaContext();
}
BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed)
{
- bool existingVerboseValue = g_verbose;
- g_verbose = false;
-
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
- g_policy.setState(ServerPolicy(name, policy));
+ auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+ dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_lbPolicy = std::move(pol);
+ });
});
g_lua.lock()->executeCode(policySetupStr);
{
- ServerPolicy pol = g_policy.getCopy();
+ const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+ BOOST_REQUIRE(pol != nullptr);
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
for (const auto& name : names) {
auto dnsQuestion = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dnsQuestion);
+ auto server = pol->getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
}
BOOST_CHECK_EQUAL(total, names.size());
- benchPolicy(pol);
+ benchPolicy(*pol);
}
- g_verbose = existingVerboseValue;
resetLuaContext();
}
#endif /* LUAJIT_VERSION */
-
+#endif
BOOST_AUTO_TEST_SUITE_END()
/* we _NEED_ to set this function to empty otherwise we might get what was set
by the last test, and we might not like it at all */
s_processQuery = nullptr;
- g_proxyProtocolACL.clear();
}
};
}
}
-AtomicCounter g_missing;
+static std::atomic<uint64_t> s_missing{0};
static void threadReader(unsigned int offset)
{
DNSQuestion dnsQuestion(ids, query);
bool found = s_localCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
if (!found) {
- g_missing++;
+ s_missing++;
}
}
}
thr.join();
}
- BOOST_CHECK((s_localCache.getDeferredInserts() + s_localCache.getDeferredLookups() + s_localCache.getInsertCollisions()) >= g_missing);
+ BOOST_CHECK((s_localCache.getDeferredInserts() + s_localCache.getDeferredLookups() + s_localCache.getInsertCollisions()) >= s_missing.load());
}
catch (const PDNSException& e) {
cerr << "Had error: " << e.reason << endl;
static void test_ring(size_t maxEntries, size_t numberOfShards, size_t nbLockTries)
{
- Rings rings(maxEntries, numberOfShards, nbLockTries);
- rings.init();
+ Rings rings;
+ rings.init(maxEntries, numberOfShards, nbLockTries);
size_t entriesPerShard = maxEntries / numberOfShards;
BOOST_CHECK_EQUAL(rings.getNumberOfShards(), numberOfShards);
dnsdist::Protocol protocol = dnsdist::Protocol::DoUDP;
dnsdist::Protocol outgoingProtocol = dnsdist::Protocol::DoUDP;
- Rings rings(numberOfEntries, numberOfShards, lockAttempts, true);
- rings.init();
+ Rings rings;
+ rings.init(numberOfEntries, numberOfShards, lockAttempts, true);
#if defined(DNSDIST_RINGS_WITH_MACADDRESS)
Rings::Query query({requestor, qname, now, dh, size, qtype, protocol, dnsdist::MacAddress(), false});
#else
#include "dnsdist-rules.hh"
-void checkParameterBound(const std::string& parameter, uint64_t value, size_t max);
void checkParameterBound(const std::string& parameter, uint64_t value, size_t max)
{
if (value > max) {
BOOST_CHECK_EQUAL(sp.poolLoad(), 400U + 30U);
- auto localPool = g_pools.getCopy();
- addServerToPool(localPool, "test", ds1);
- addServerToPool(localPool, "test", ds2);
- g_pools.setState(localPool);
+ addServerToPool("test", ds1);
+ addServerToPool("test", ds2);
PoolOutstandingRule pOR1("test", 10);
BOOST_CHECK_EQUAL(pOR1.matches(&dq), true);
#include "dnsdist-tcp-downstream.hh"
#include "dnsdist-tcp-upstream.hh"
-GlobalStateHolder<NetmaskGroup> g_ACL;
-GlobalStateHolder<servers_t> g_dstates;
-
-QueryCount g_qcount;
-
const bool TCPIOHandler::s_disableConnectForUnitTests = true;
bool checkDNSCryptQuery(const ClientState& cs, PacketBuffer& query, std::unique_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp)
std::function<ProcessQueryResult(DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend)> s_processQuery;
-ProcessQueryResult processQuery(DNSQuestion& dq, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
{
if (s_processQuery) {
- return s_processQuery(dq, selectedBackend);
+ return s_processQuery(dnsQuestion, selectedBackend);
}
return ProcessQueryResult::Drop;
}
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse)
{
return true;
}
static std::function<bool(PacketBuffer& response, DNSResponse& dr, bool muted)> s_processResponse;
-bool processResponse(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted)
+bool processResponse(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
{
if (s_processResponse) {
return s_processResponse(response, dnsResponse, muted);
s_backendReadBuffer.clear();
s_backendWriteBuffer.clear();
- g_proxyProtocolACL.clear();
- g_verbose = false;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_proxyProtocolACL.clear();
+ });
IncomingTCPConnectionState::clearAllDownstreamConnections();
/* we _NEED_ to set this function to empty otherwise we might get what was set
BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
{
+ const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
auto local = getBackendAddress("1", 80);
ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
state->handleIO();
BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
struct timeval later = now;
- later.tv_sec += g_tcpRecvTimeout + 1;
+ later.tv_sec += tcpRecvTimeout + 1;
auto expiredReadConns = threadData.mplexer->getTimeouts(later, false);
for (const auto& cbData : expiredReadConns) {
BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
state->handleIO();
BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
struct timeval later = now;
- later.tv_sec += g_tcpRecvTimeout + 1;
+ later.tv_sec += tcpRecvTimeout + 1;
auto expiredWriteConns = threadData.mplexer->getTimeouts(later, true);
for (const auto& cbData : expiredWriteConns) {
BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, TestFixture)
{
+ const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
auto local = getBackendAddress("1", 80);
ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
{
TEST_INIT("=> reading PP");
- g_proxyProtocolACL.addMask("0.0.0.0/0");
- g_proxyProtocolACL.addMask("::0/0");
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+ config.d_proxyProtocolACL.addMask("::0/0");
+ });
auto proxyPayload = makeProxyHeader(true, ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2"), {});
BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
{
TEST_INIT("=> Invalid PP");
- g_proxyProtocolACL.addMask("0.0.0.0/0");
- g_proxyProtocolACL.addMask("::0/0");
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+ config.d_proxyProtocolACL.addMask("::0/0");
+ });
+
auto proxyPayload = std::vector<uint8_t>(s_proxyProtocolMinimumHeaderSize);
std::fill(proxyPayload.begin(), proxyPayload.end(), 0);
{
TEST_INIT("=> timeout while reading PP");
- g_proxyProtocolACL.addMask("0.0.0.0/0");
- g_proxyProtocolACL.addMask("::0/0");
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+ config.d_proxyProtocolACL.addMask("::0/0");
+ });
+
auto proxyPayload = makeProxyHeader(true, ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2"), {});
BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
s_readBuffer = query;
state->handleIO();
BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
struct timeval later = now;
- later.tv_sec += g_tcpRecvTimeout + 1;
+ later.tv_sec += tcpRecvTimeout + 1;
auto expiredReadConns = threadData.mplexer->getTimeouts(later, false);
for (const auto& cbData : expiredReadConns) {
BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
/* 101 queries on the same connection, check that the maximum number of queries kicks in */
TEST_INIT("=> 101 queries on the same connection");
- g_maxTCPQueriesPerConn = 100;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_maxTCPQueriesPerConn = 100;
+ });
size_t count = 101;
/* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
IncomingTCPConnectionState::clearAllDownstreamConnections();
- g_maxTCPQueriesPerConn = 0;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_maxTCPQueriesPerConn = 0;
+ });
#endif
}
}
}
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
{
+ const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
auto local = getBackendAddress("1", 80);
ClientState localCS(local, true, false, 0, "", {}, true);
/* enable out-of-order on the front side */
TEST_INIT("=> 3 queries sent to the backend, 1 self-answered, 1 new query sent to the backend which responds to the first query right away, then to the last one, then the connection to the backend times out");
// increase the client timeout for that test, we want the backend to timeout first
- g_tcpRecvTimeout = 5;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_tcpRecvTimeout = 5;
+ });
PacketBuffer expectedWriteBuffer;
PacketBuffer expectedBackendWriteBuffer;
IncomingTCPConnectionState::clearAllDownstreamConnections();
// restore the client timeout
- g_tcpRecvTimeout = 2;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_tcpRecvTimeout = 2;
+ });
}
{
}
struct timeval later = now;
- later.tv_sec += g_tcpRecvTimeout + 1;
+ later.tv_sec += tcpRecvTimeout + 1;
auto expiredConns = threadData.mplexer->getTimeouts(later, false);
BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
for (const auto& cbData : expiredConns) {
}
struct timeval later = now;
- later.tv_sec += g_tcpRecvTimeout + 1;
+ later.tv_sec += tcpRecvTimeout + 1;
auto expiredConns = threadData.mplexer->getTimeouts(later, false);
BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
for (const auto& cbData : expiredConns) {
}
later = now;
- later.tv_sec += g_tcpRecvTimeout + 1;
+ later.tv_sec += tcpRecvTimeout + 1;
expiredConns = threadData.mplexer->getTimeouts(later, false);
BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
for (const auto& cbData : expiredConns) {
/* make sure that the backend's timeout is shorter than the client's */
backend->d_config.tcpConnectTimeout = 1;
- g_tcpRecvTimeout = 5;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_tcpRecvTimeout = 5;
+ });
bool timeout = false;
s_steps = {
/* restore */
backend->d_config.tcpSendTimeout = 30;
- g_tcpRecvTimeout = 2;
+ dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+ config.d_tcpRecvTimeout = 2;
+ });
/* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
/* we have no connection to clear, because there was a timeout! */
}
struct timeval later = now;
- later.tv_sec += g_tcpRecvTimeout + 1;
+ later.tv_sec += tcpRecvTimeout + 1;
auto expiredConns = threadData.mplexer->getTimeouts(later);
BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
for (const auto& cbData : expiredConns) {
BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR, TestFixture)
{
+ const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
auto local = getBackendAddress("1", 80);
ClientState localCS(local, true, false, 0, "", {}, true);
/* enable out-of-order on the front side */
}
struct timeval later = now;
- later.tv_sec += g_tcpRecvTimeout + 1;
+ later.tv_sec += tcpRecvTimeout + 1;
auto expiredConns = threadData.mplexer->getTimeouts(later);
BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
for (const auto& cbData : expiredConns) {
--- /dev/null
+../test-sholder_hh.cc
\ No newline at end of file
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
+#define BOOST_TEST_NO_MAIN
+
#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif
#endif
#include <boost/test/unit_test.hpp>
+// entry point:
+int main(int argc, char* argv[])
+{
+ setenv("BOOST_TEST_RANDOM", "1", 1); // NOLINT(concurrency-mt-unsafe)
+ return boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
+}
+++ /dev/null
-../xsk.cc
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_XSK
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <fcntl.h>
+#include <iterator>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <stdexcept>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <vector>
+
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+extern "C"
+{
+#include <xdp/libxdp.h>
+}
+
+#include "gettime.hh"
+#include "xsk.hh"
+
+/* we need to include the linux specific headers AFTER the regular
+ ones, because it then detects that some types have already been
+ defined (sockaddr_in6 for example) and does not attempt to
+ re-define them, which otherwise breaks the C++ One Definition Rule
+*/
+#include <linux/bpf.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_xdp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/udp.h>
+
+#ifdef DEBUG_UMEM
+namespace
+{
+struct UmemEntryStatus
+{
+ enum class Status : uint8_t
+ {
+ Free,
+ FillQueue,
+ Received,
+ TXQueue
+ };
+ Status status{Status::Free};
+};
+
+LockGuarded<std::map<std::pair<void*, uint64_t>, UmemEntryStatus>> s_umems;
+
+void checkUmemIntegrity(const char* function, int line, std::shared_ptr<LockGuarded<vector<uint64_t>>> vect, uint64_t offset, const std::set<UmemEntryStatus::Status>& validStatuses, UmemEntryStatus::Status newStatus)
+{
+ auto umems = s_umems.lock();
+ auto& umemState = umems->at({vect.get(), offset});
+ if (validStatuses.count(umemState.status) == 0) {
+ std::cerr << "UMEM integrity check failed at " << function << ": " << line << ": status of " << (void*)vect.get() << ", " << offset << " is " << static_cast<int>(umemState.status) << ", expected: ";
+ for (const auto status : validStatuses) {
+ std::cerr << static_cast<int>(status) << " ";
+ }
+ std::cerr << std::endl;
+ abort();
+ }
+ umemState.status = newStatus;
+}
+}
+#endif /* DEBUG_UMEM */
+
+constexpr bool XskSocket::isPowOfTwo(uint32_t value) noexcept
+{
+ return value != 0 && (value & (value - 1)) == 0;
+}
+
+int XskSocket::firstTimeout()
+{
+ if (waitForDelay.empty()) {
+ return -1;
+ }
+ timespec now{};
+ gettime(&now);
+ const auto& firstTime = waitForDelay.top().getSendTime();
+ const auto res = timeDifference(now, firstTime);
+ if (res <= 0) {
+ return 0;
+ }
+ return res;
+}
+
+XskSocket::XskSocket(size_t frameNum_, std::string ifName_, uint32_t queue_id, const std::string& xskMapPath) :
+ frameNum(frameNum_), ifName(std::move(ifName_)), socket(nullptr, xsk_socket__delete), sharedEmptyFrameOffset(std::make_shared<LockGuarded<vector<uint64_t>>>())
+{
+ if (!isPowOfTwo(frameNum_) || !isPowOfTwo(frameSize)
+ || !isPowOfTwo(fqCapacity) || !isPowOfTwo(cqCapacity) || !isPowOfTwo(rxCapacity) || !isPowOfTwo(txCapacity)) {
+ throw std::runtime_error("The number of frame , the size of frame and the capacity of rings must is a pow of 2");
+ }
+ getMACFromIfName();
+
+ memset(&cq, 0, sizeof(cq));
+ memset(&fq, 0, sizeof(fq));
+ memset(&tx, 0, sizeof(tx));
+ memset(&rx, 0, sizeof(rx));
+
+ xsk_umem_config umemCfg{};
+ umemCfg.fill_size = fqCapacity;
+ umemCfg.comp_size = cqCapacity;
+ umemCfg.frame_size = frameSize;
+ umemCfg.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
+ umemCfg.flags = 0;
+ umem.umemInit(frameNum_ * frameSize, &cq, &fq, &umemCfg);
+
+ {
+ xsk_socket_config socketCfg{};
+ socketCfg.rx_size = rxCapacity;
+ socketCfg.tx_size = txCapacity;
+ socketCfg.bind_flags = XDP_USE_NEED_WAKEUP;
+ socketCfg.xdp_flags = XDP_FLAGS_SKB_MODE;
+ socketCfg.libxdp_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
+ xsk_socket* tmp = nullptr;
+ auto ret = xsk_socket__create(&tmp, ifName.c_str(), queue_id, umem.umem, &rx, &tx, &socketCfg);
+ if (ret != 0) {
+ throw std::runtime_error("Error creating a xsk socket of if_name " + ifName + ": " + stringerror(ret));
+ }
+ socket = std::unique_ptr<xsk_socket, decltype(&xsk_socket__delete)>(tmp, xsk_socket__delete);
+ }
+
+ uniqueEmptyFrameOffset.reserve(frameNum);
+ {
+ for (uint64_t idx = 0; idx < frameNum; idx++) {
+ uniqueEmptyFrameOffset.push_back(idx * frameSize + XDP_PACKET_HEADROOM);
+#ifdef DEBUG_UMEM
+ {
+ auto umems = s_umems.lock();
+ (*umems)[{sharedEmptyFrameOffset.get(), idx * frameSize + XDP_PACKET_HEADROOM}] = UmemEntryStatus();
+ }
+#endif /* DEBUG_UMEM */
+ }
+ }
+
+ fillFq(fqCapacity);
+
+ const auto xskfd = xskFd();
+ fds.push_back(pollfd{
+ .fd = xskfd,
+ .events = POLLIN,
+ .revents = 0});
+
+ const auto xskMapFd = FDWrapper(bpf_obj_get(xskMapPath.c_str()));
+
+ if (xskMapFd.getHandle() < 0) {
+ throw std::runtime_error("Error getting BPF map from path '" + xskMapPath + "'");
+ }
+
+ auto ret = bpf_map_update_elem(xskMapFd.getHandle(), &queue_id, &xskfd, 0);
+ if (ret != 0) {
+ throw std::runtime_error("Error inserting into xsk_map '" + xskMapPath + "': " + std::to_string(ret));
+ }
+}
+
+// see xdp.h in contrib/
+struct IPv4AndPort
+{
+ uint32_t addr;
+ uint16_t port;
+};
+struct IPv6AndPort
+{
+ struct in6_addr addr;
+ uint16_t port;
+};
+
+static FDWrapper getDestinationMap(const std::string& mapPath)
+{
+ auto destMapFd = FDWrapper(bpf_obj_get(mapPath.c_str()));
+ if (destMapFd.getHandle() < 0) {
+ throw std::runtime_error("Error getting the XSK destination addresses map path '" + mapPath + "'");
+ }
+ return destMapFd;
+}
+
+void XskSocket::clearDestinationMap(const std::string& mapPath, bool isV6)
+{
+ auto destMapFd = getDestinationMap(mapPath);
+ if (!isV6) {
+ IPv4AndPort prevKey{};
+ IPv4AndPort key{};
+ while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
+ bpf_map_delete_elem(destMapFd.getHandle(), &key);
+ prevKey = key;
+ }
+ }
+ else {
+ IPv6AndPort prevKey{};
+ IPv6AndPort key{};
+ while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
+ bpf_map_delete_elem(destMapFd.getHandle(), &key);
+ prevKey = key;
+ }
+ }
+}
+
+void XskSocket::addDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
+{
+ auto destMapFd = getDestinationMap(mapPath);
+ bool value = true;
+ if (destination.isIPv4()) {
+ IPv4AndPort key{};
+ key.addr = destination.sin4.sin_addr.s_addr;
+ key.port = destination.sin4.sin_port;
+ auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
+ if (ret != 0) {
+ throw std::runtime_error("Error inserting into xsk_map '" + mapPath + "': " + std::to_string(ret));
+ }
+ }
+ else {
+ IPv6AndPort key{};
+ key.addr = destination.sin6.sin6_addr;
+ key.port = destination.sin6.sin6_port;
+ auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
+ if (ret != 0) {
+ throw std::runtime_error("Error inserting into XSK destination addresses map '" + mapPath + "': " + std::to_string(ret));
+ }
+ }
+}
+
+void XskSocket::removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
+{
+ auto destMapFd = getDestinationMap(mapPath);
+ if (destination.isIPv4()) {
+ IPv4AndPort key{};
+ key.addr = destination.sin4.sin_addr.s_addr;
+ key.port = destination.sin4.sin_port;
+ bpf_map_delete_elem(destMapFd.getHandle(), &key);
+ }
+ else {
+ IPv6AndPort key{};
+ key.addr = destination.sin6.sin6_addr;
+ key.port = destination.sin6.sin6_port;
+ bpf_map_delete_elem(destMapFd.getHandle(), &key);
+ }
+}
+
+void XskSocket::fillFq(uint32_t fillSize) noexcept
+{
+ if (uniqueEmptyFrameOffset.size() < fillSize) {
+ auto frames = sharedEmptyFrameOffset->lock();
+ const auto moveSize = std::min(static_cast<size_t>(fillSize), frames->size());
+ if (moveSize > 0) {
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+ uniqueEmptyFrameOffset.insert(uniqueEmptyFrameOffset.end(), std::make_move_iterator(frames->end() - moveSize), std::make_move_iterator(frames->end()));
+ frames->resize(frames->size() - moveSize);
+ }
+ }
+ else if (uniqueEmptyFrameOffset.size() > (10 * fillSize)) {
+ // if we have less than holdThreshold frames in the shared queue (which might be an issue
+ // when the XskWorker needs empty frames), move frames from the unique container into the
+ // shared one. This might not be optimal right now.
+ auto frames = sharedEmptyFrameOffset->lock();
+ if (frames->size() < holdThreshold) {
+ const auto moveSize = std::min(holdThreshold - frames->size(), uniqueEmptyFrameOffset.size());
+ if (moveSize > 0) {
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+ frames->insert(frames->end(), std::make_move_iterator(uniqueEmptyFrameOffset.end() - moveSize), std::make_move_iterator(uniqueEmptyFrameOffset.end()));
+ uniqueEmptyFrameOffset.resize(uniqueEmptyFrameOffset.size() - moveSize);
+ }
+ }
+ }
+
+ fillSize = std::min(fillSize, static_cast<uint32_t>(uniqueEmptyFrameOffset.size()));
+ if (fillSize == 0) {
+ auto frames = sharedEmptyFrameOffset->lock();
+ return;
+ }
+
+ uint32_t idx{0};
+ auto toFill = xsk_ring_prod__reserve(&fq, fillSize, &idx);
+ if (toFill == 0) {
+ return;
+ }
+ uint32_t processed = 0;
+ for (; processed < toFill; processed++) {
+ *xsk_ring_prod__fill_addr(&fq, idx++) = uniqueEmptyFrameOffset.back();
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Free}, UmemEntryStatus::Status::FillQueue);
+#endif /* DEBUG_UMEM */
+ uniqueEmptyFrameOffset.pop_back();
+ }
+
+ xsk_ring_prod__submit(&fq, processed);
+}
+
+int XskSocket::wait(int timeout)
+{
+ auto waitAtMost = std::min(timeout, firstTimeout());
+ return poll(fds.data(), fds.size(), waitAtMost);
+}
+
+[[nodiscard]] uint64_t XskSocket::frameOffset(const XskPacket& packet) const noexcept
+{
+ return packet.getFrameOffsetFrom(umem.bufBase);
+}
+
+[[nodiscard]] int XskSocket::xskFd() const noexcept
+{
+ return xsk_socket__fd(socket.get());
+}
+
+void XskSocket::send(std::vector<XskPacket>& packets)
+{
+ while (!packets.empty()) {
+ auto packetSize = packets.size();
+ if (packetSize > std::numeric_limits<uint32_t>::max()) {
+ packetSize = std::numeric_limits<uint32_t>::max();
+ }
+ size_t toSend = std::min(static_cast<uint32_t>(packetSize), txCapacity);
+ uint32_t idx{0};
+ auto toFill = xsk_ring_prod__reserve(&tx, toSend, &idx);
+ if (toFill == 0) {
+ return;
+ }
+
+ size_t queued = 0;
+ for (const auto& packet : packets) {
+ if (queued == toFill) {
+ break;
+ }
+ *xsk_ring_prod__tx_desc(&tx, idx++) = {
+ .addr = frameOffset(packet),
+ .len = packet.getFrameLen(),
+ .options = 0};
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, frameOffset(packet), {UmemEntryStatus::Status::Free, UmemEntryStatus::Status::Received}, UmemEntryStatus::Status::TXQueue);
+#endif /* DEBUG_UMEM */
+ queued++;
+ }
+ xsk_ring_prod__submit(&tx, toFill);
+ packets.erase(packets.begin(), packets.begin() + toFill);
+ }
+}
+
+std::vector<XskPacket> XskSocket::recv(uint32_t recvSizeMax, uint32_t* failedCount)
+{
+ uint32_t idx{0};
+ std::vector<XskPacket> res;
+ // how many descriptors to packets have been filled
+ const auto recvSize = xsk_ring_cons__peek(&rx, recvSizeMax, &idx);
+ if (recvSize == 0) {
+ return res;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const auto baseAddr = reinterpret_cast<uint64_t>(umem.bufBase);
+ uint32_t failed = 0;
+ uint32_t processed = 0;
+ res.reserve(recvSize);
+ for (; processed < recvSize; processed++) {
+ try {
+ const auto* desc = xsk_ring_cons__rx_desc(&rx, idx++);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr)
+ XskPacket packet = XskPacket(reinterpret_cast<uint8_t*>(desc->addr + baseAddr), desc->len, frameSize);
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, frameOffset(packet), {UmemEntryStatus::Status::FillQueue}, UmemEntryStatus::Status::Received);
+#endif /* DEBUG_UMEM */
+
+ if (!packet.parse(false)) {
+ ++failed;
+ markAsFree(packet);
+ }
+ else {
+ res.push_back(packet);
+ }
+ }
+ catch (const std::exception& exp) {
+ ++failed;
+ ++processed;
+ break;
+ }
+ catch (...) {
+ ++failed;
+ ++processed;
+ break;
+ }
+ }
+
+ // this releases the descriptor, but not the packet (umem entries)
+ // which will only be made available again when pushed into the fill
+ // queue
+ xsk_ring_cons__release(&rx, processed);
+ if (failedCount != nullptr) {
+ *failedCount = failed;
+ }
+
+ return res;
+}
+
+void XskSocket::pickUpReadyPacket(std::vector<XskPacket>& packets)
+{
+ timespec now{};
+ gettime(&now);
+ while (!waitForDelay.empty() && timeDifference(now, waitForDelay.top().getSendTime()) <= 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto& top = const_cast<XskPacket&>(waitForDelay.top());
+ packets.push_back(top);
+ waitForDelay.pop();
+ }
+}
+
+void XskSocket::recycle(size_t size) noexcept
+{
+ uint32_t idx{0};
+ const auto completeSize = xsk_ring_cons__peek(&cq, size, &idx);
+ if (completeSize == 0) {
+ return;
+ }
+ uniqueEmptyFrameOffset.reserve(uniqueEmptyFrameOffset.size() + completeSize);
+ uint32_t processed = 0;
+ for (; processed < completeSize; ++processed) {
+ uniqueEmptyFrameOffset.push_back(*xsk_ring_cons__comp_addr(&cq, idx++));
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+ }
+ xsk_ring_cons__release(&cq, processed);
+}
+
+void XskSocket::XskUmem::umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config)
+{
+ size = memSize;
+ bufBase = static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ if (bufBase == MAP_FAILED) {
+ throw std::runtime_error("mmap failed");
+ }
+ auto ret = xsk_umem__create(&umem, bufBase, size, fillQueue, completionQueue, config);
+ if (ret != 0) {
+ munmap(bufBase, size);
+ throw std::runtime_error("Error creating a umem of size " + std::to_string(size) + ": " + stringerror(ret));
+ }
+}
+
+std::string XskSocket::getMetrics() const
+{
+ xdp_statistics stats{};
+ socklen_t optlen = sizeof(stats);
+ int err = getsockopt(xskFd(), SOL_XDP, XDP_STATISTICS, &stats, &optlen);
+ if (err != 0) {
+ return "";
+ }
+ if (optlen != sizeof(struct xdp_statistics)) {
+ return "";
+ }
+
+ ostringstream ret;
+ ret << "RX dropped: " << std::to_string(stats.rx_dropped) << std::endl;
+ ret << "RX invalid descs: " << std::to_string(stats.rx_invalid_descs) << std::endl;
+ ret << "TX invalid descs: " << std::to_string(stats.tx_invalid_descs) << std::endl;
+ ret << "RX ring full: " << std::to_string(stats.rx_ring_full) << std::endl;
+ ret << "RX fill ring empty descs: " << std::to_string(stats.rx_fill_ring_empty_descs) << std::endl;
+ ret << "TX ring empty descs: " << std::to_string(stats.tx_ring_empty_descs) << std::endl;
+ return ret.str();
+}
+
+[[nodiscard]] std::string XskSocket::getXDPMode() const
+{
+#ifdef HAVE_BPF_XDP_QUERY
+ unsigned int itfIdx = if_nametoindex(ifName.c_str());
+ if (itfIdx == 0) {
+ return "unable to get interface index";
+ }
+ bpf_xdp_query_opts info{};
+ info.sz = sizeof(info);
+ int ret = bpf_xdp_query(static_cast<int>(itfIdx), 0, &info);
+ if (ret != 0) {
+ return {};
+ }
+ switch (info.attach_mode) {
+ case XDP_ATTACHED_DRV:
+ case XDP_ATTACHED_HW:
+ return "native";
+ case XDP_ATTACHED_SKB:
+ return "emulated";
+ default:
+ return "unknown";
+ }
+#else /* HAVE_BPF_XDP_QUERY */
+ return "undetected";
+#endif /* HAVE_BPF_XDP_QUERY */
+}
+
+void XskSocket::markAsFree(const XskPacket& packet)
+{
+ auto offset = frameOffset(packet);
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+ uniqueEmptyFrameOffset.push_back(offset);
+}
+
+XskSocket::XskUmem::~XskUmem()
+{
+ if (umem != nullptr) {
+ xsk_umem__delete(umem);
+ }
+ if (bufBase != nullptr) {
+ munmap(bufBase, size);
+ }
+}
+
+[[nodiscard]] size_t XskPacket::getL4HeaderOffset() const noexcept
+{
+ return sizeof(ethhdr) + (v6 ? (sizeof(ipv6hdr)) : sizeof(iphdr));
+}
+
+[[nodiscard]] size_t XskPacket::getDataOffset() const noexcept
+{
+ return getL4HeaderOffset() + sizeof(udphdr);
+}
+
+[[nodiscard]] size_t XskPacket::getDataSize() const noexcept
+{
+ return frameLength - getDataOffset();
+}
+
+[[nodiscard]] ethhdr XskPacket::getEthernetHeader() const noexcept
+{
+ ethhdr ethHeader{};
+ if (frameLength >= sizeof(ethHeader)) {
+ memcpy(ðHeader, frame, sizeof(ethHeader));
+ }
+ return ethHeader;
+}
+
+void XskPacket::setEthernetHeader(const ethhdr& ethHeader) noexcept
+{
+ if (frameLength < sizeof(ethHeader)) {
+ frameLength = sizeof(ethHeader);
+ }
+ memcpy(frame, ðHeader, sizeof(ethHeader));
+}
+
+[[nodiscard]] iphdr XskPacket::getIPv4Header() const noexcept
+{
+ iphdr ipv4Header{};
+ assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv4Header)));
+ assert(!v6);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&ipv4Header, frame + sizeof(ethhdr), sizeof(ipv4Header));
+ return ipv4Header;
+}
+
+void XskPacket::setIPv4Header(const iphdr& ipv4Header) noexcept
+{
+ assert(frameLength >= (sizeof(ethhdr) + sizeof(iphdr)));
+ assert(!v6);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(frame + sizeof(ethhdr), &ipv4Header, sizeof(ipv4Header));
+}
+
+[[nodiscard]] ipv6hdr XskPacket::getIPv6Header() const noexcept
+{
+ ipv6hdr ipv6Header{};
+ assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
+ assert(v6);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&ipv6Header, frame + sizeof(ethhdr), sizeof(ipv6Header));
+ return ipv6Header;
+}
+
+void XskPacket::setIPv6Header(const ipv6hdr& ipv6Header) noexcept
+{
+ assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
+ assert(v6);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(frame + sizeof(ethhdr), &ipv6Header, sizeof(ipv6Header));
+}
+
+[[nodiscard]] udphdr XskPacket::getUDPHeader() const noexcept
+{
+ udphdr udpHeader{};
+ assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&udpHeader, frame + getL4HeaderOffset(), sizeof(udpHeader));
+ return udpHeader;
+}
+
+void XskPacket::setUDPHeader(const udphdr& udpHeader) noexcept
+{
+ assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(frame + getL4HeaderOffset(), &udpHeader, sizeof(udpHeader));
+}
+
+bool XskPacket::parse(bool fromSetHeader)
+{
+ if (frameLength <= sizeof(ethhdr)) {
+ return false;
+ }
+
+ auto ethHeader = getEthernetHeader();
+ uint8_t l4Protocol{0};
+ if (ethHeader.h_proto == htons(ETH_P_IP)) {
+ if (frameLength < (sizeof(ethhdr) + sizeof(iphdr) + sizeof(udphdr))) {
+ return false;
+ }
+ v6 = false;
+ auto ipHeader = getIPv4Header();
+ if (ipHeader.ihl != (static_cast<uint8_t>(sizeof(iphdr) / 4))) {
+ // ip options is not supported now!
+ return false;
+ }
+ // check ip.check == ipv4Checksum() is not needed!
+ // We check it in BPF program
+ // we don't, actually.
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ from = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ to = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
+ l4Protocol = ipHeader.protocol;
+ if (!fromSetHeader && (frameLength - sizeof(ethhdr)) != ntohs(ipHeader.tot_len)) {
+ // too small, or too large (trailing data), go away
+ return false;
+ }
+ }
+ else if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
+ if (frameLength < (sizeof(ethhdr) + sizeof(ipv6hdr) + sizeof(udphdr))) {
+ return false;
+ }
+ v6 = true;
+ auto ipHeader = getIPv6Header();
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ from = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ to = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
+ l4Protocol = ipHeader.nexthdr;
+ if (!fromSetHeader && (frameLength - (sizeof(ethhdr) + sizeof(ipv6hdr))) != ntohs(ipHeader.payload_len)) {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+
+ if (l4Protocol != IPPROTO_UDP) {
+ return false;
+ }
+
+ // check udp.check == ipv4Checksum() is not needed!
+ // We check it in BPF program
+ // we don't, actually.
+ auto udpHeader = getUDPHeader();
+ if (!fromSetHeader) {
+ // Because of XskPacket::setHeader
+ if (getDataOffset() > frameLength) {
+ return false;
+ }
+
+ if (getDataSize() + sizeof(udphdr) != ntohs(udpHeader.len)) {
+ return false;
+ }
+ }
+
+ from.setPort(ntohs(udpHeader.source));
+ to.setPort(ntohs(udpHeader.dest));
+ return true;
+}
+
+uint32_t XskPacket::getDataLen() const noexcept
+{
+ return getDataSize();
+}
+
+uint32_t XskPacket::getFrameLen() const noexcept
+{
+ return frameLength;
+}
+
+size_t XskPacket::getCapacity() const noexcept
+{
+ return frameSize;
+}
+
+void XskPacket::changeDirectAndUpdateChecksum() noexcept
+{
+ auto ethHeader = getEthernetHeader();
+ {
+ std::array<uint8_t, ETH_ALEN> tmp{};
+ static_assert(tmp.size() == sizeof(ethHeader.h_dest), "Size Error");
+ static_assert(tmp.size() == sizeof(ethHeader.h_source), "Size Error");
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(tmp.data(), ethHeader.h_dest, tmp.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(ethHeader.h_dest, ethHeader.h_source, tmp.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(ethHeader.h_source, tmp.data(), tmp.size());
+ }
+ if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
+ // IPV6
+ auto ipv6 = getIPv6Header();
+ std::swap(ipv6.daddr, ipv6.saddr);
+ ipv6.nexthdr = IPPROTO_UDP;
+
+ auto udp = getUDPHeader();
+ std::swap(udp.dest, udp.source);
+ udp.len = htons(getDataSize() + sizeof(udp));
+ udp.check = 0;
+ /* needed to get the correct checksum */
+ setIPv6Header(ipv6);
+ setUDPHeader(udp);
+ // do not bother setting the UDP checksum: 0 is a valid value and most AF_XDP
+ // implementations do the same
+ // udp.check = tcp_udp_v6_checksum(&ipv6);
+ rewriteIpv6Header(&ipv6, getFrameLen());
+ setIPv6Header(ipv6);
+ setUDPHeader(udp);
+ }
+ else if (ethHeader.h_proto == htons(ETH_P_IP)) {
+ // IPV4
+ auto ipv4 = getIPv4Header();
+ std::swap(ipv4.daddr, ipv4.saddr);
+ ipv4.protocol = IPPROTO_UDP;
+
+ auto udp = getUDPHeader();
+ std::swap(udp.dest, udp.source);
+ udp.len = htons(getDataSize() + sizeof(udp));
+ udp.check = 0;
+ /* needed to get the correct checksum */
+ setIPv4Header(ipv4);
+ setUDPHeader(udp);
+ // do not bother setting the UDP checksum: 0 is a valid value and most AF_XDP
+ // implementations do the same
+ // udp.check = tcp_udp_v4_checksum(&ipv4);
+ rewriteIpv4Header(&ipv4, getFrameLen());
+ setIPv4Header(ipv4);
+ setUDPHeader(udp);
+ }
+ setEthernetHeader(ethHeader);
+}
+
+void XskPacket::rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept
+{
+ ipv4header->version = 4;
+ ipv4header->ihl = sizeof(iphdr) / 4;
+ ipv4header->tos = 0;
+ ipv4header->tot_len = htons(frameLen - sizeof(ethhdr));
+ ipv4header->id = 0;
+ ipv4header->frag_off = 0;
+ ipv4header->ttl = DefaultTTL;
+ ipv4header->check = 0;
+ ipv4header->check = ipv4Checksum(ipv4header);
+}
+
+void XskPacket::rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept
+{
+ ipv6header->version = 6;
+ ipv6header->priority = 0;
+ ipv6header->payload_len = htons(frameLen - sizeof(ethhdr) - sizeof(ipv6hdr));
+ ipv6header->hop_limit = DefaultTTL;
+ memset(&ipv6header->flow_lbl, 0, sizeof(ipv6header->flow_lbl));
+}
+
+bool XskPacket::isIPV6() const noexcept
+{
+ return v6;
+}
+
+XskPacket::XskPacket(uint8_t* frame_, size_t dataSize, size_t frameSize_) :
+ frame(frame_), frameLength(dataSize), frameSize(frameSize_ - XDP_PACKET_HEADROOM)
+{
+}
+
+PacketBuffer XskPacket::clonePacketBuffer() const
+{
+ const auto size = getDataSize();
+ PacketBuffer tmp(size);
+ if (size > 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(tmp.data(), frame + getDataOffset(), size);
+ }
+ return tmp;
+}
+
+bool XskPacket::setPayload(const PacketBuffer& buf)
+{
+ const auto bufSize = buf.size();
+ const auto currentCapacity = getCapacity();
+ if (bufSize == 0 || bufSize > currentCapacity) {
+ return false;
+ }
+ flags |= UPDATE;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(frame + getDataOffset(), buf.data(), bufSize);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ frameLength = getDataOffset() + bufSize;
+ return true;
+}
+
+void XskPacket::addDelay(const int relativeMilliseconds) noexcept
+{
+ gettime(&sendTime);
+ sendTime.tv_nsec += static_cast<int64_t>(relativeMilliseconds) * 1000000L;
+ sendTime.tv_sec += sendTime.tv_nsec / 1000000000L;
+ sendTime.tv_nsec %= 1000000000L;
+}
+
+bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept
+{
+ return lhs.getSendTime() < rhs.getSendTime();
+}
+
+const ComboAddress& XskPacket::getFromAddr() const noexcept
+{
+ return from;
+}
+
+const ComboAddress& XskPacket::getToAddr() const noexcept
+{
+ return to;
+}
+
+void XskWorker::notify(int desc)
+{
+ uint64_t value = 1;
+ ssize_t res = 0;
+ while ((res = write(desc, &value, sizeof(value))) == EINTR) {
+ }
+ if (res != sizeof(value)) {
+ throw runtime_error("Unable Wake Up XskSocket Failed");
+ }
+}
+
+XskWorker::XskWorker(XskWorker::Type type, const std::shared_ptr<LockGuarded<std::vector<uint64_t>>>& frames) :
+ d_sharedEmptyFrameOffset(frames), d_type(type), workerWaker(createEventfd()), xskSocketWaker(createEventfd())
+{
+}
+
+void XskWorker::pushToProcessingQueue(XskPacket& packet)
+{
+ if (d_type == Type::OutgoingOnly) {
+ throw std::runtime_error("Trying to push an incoming packet into an outgoing-only XSK Worker");
+ }
+ if (!d_incomingPacketsQueue.push(packet)) {
+ markAsFree(packet);
+ }
+}
+
+void XskWorker::pushToSendQueue(XskPacket& packet)
+{
+ if (!d_outgoingPacketsQueue.push(packet)) {
+ markAsFree(packet);
+ }
+}
+
+const void* XskPacket::getPayloadData() const
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ return frame + getDataOffset();
+}
+
+void XskPacket::setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept
+{
+ auto ethHeader = getEthernetHeader();
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(ethHeader.h_dest, toMAC.data(), toMAC.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(ethHeader.h_source, fromMAC.data(), fromMAC.size());
+ setEthernetHeader(ethHeader);
+ to = to_;
+ from = from_;
+ v6 = !to.isIPv4();
+ flags = 0;
+}
+
+void XskPacket::rewrite() noexcept
+{
+ flags |= REWRITE;
+ auto ethHeader = getEthernetHeader();
+ if (!v6) {
+ ethHeader.h_proto = htons(ETH_P_IP);
+
+ auto ipHeader = getIPv4Header();
+ ipHeader.daddr = to.sin4.sin_addr.s_addr;
+ ipHeader.saddr = from.sin4.sin_addr.s_addr;
+ ipHeader.protocol = IPPROTO_UDP;
+
+ auto udpHeader = getUDPHeader();
+ udpHeader.source = from.sin4.sin_port;
+ udpHeader.dest = to.sin4.sin_port;
+ udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
+ udpHeader.check = 0;
+ /* needed to get the correct checksum */
+ setIPv4Header(ipHeader);
+ setUDPHeader(udpHeader);
+ // do not bother setting the UDP checksum: 0 is a valid value and most AF_XDP
+ // implementations do the same
+ // udpHeader.check = tcp_udp_v4_checksum(&ipHeader);
+ rewriteIpv4Header(&ipHeader, getFrameLen());
+ setIPv4Header(ipHeader);
+ setUDPHeader(udpHeader);
+ }
+ else {
+ ethHeader.h_proto = htons(ETH_P_IPV6);
+
+ auto ipHeader = getIPv6Header();
+ memcpy(&ipHeader.daddr, &to.sin6.sin6_addr, sizeof(ipHeader.daddr));
+ memcpy(&ipHeader.saddr, &from.sin6.sin6_addr, sizeof(ipHeader.saddr));
+ ipHeader.nexthdr = IPPROTO_UDP;
+
+ auto udpHeader = getUDPHeader();
+ udpHeader.source = from.sin6.sin6_port;
+ udpHeader.dest = to.sin6.sin6_port;
+ udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
+ udpHeader.check = 0;
+ /* needed to get the correct checksum */
+ setIPv6Header(ipHeader);
+ setUDPHeader(udpHeader);
+ // do not bother setting the UDP checksum: 0 is a valid value and most AF_XDP
+ // implementations do the same
+ // udpHeader.check = tcp_udp_v6_checksum(&ipHeader);
+ setIPv6Header(ipHeader);
+ setUDPHeader(udpHeader);
+ }
+
+ setEthernetHeader(ethHeader);
+}
+
+[[nodiscard]] __be16 XskPacket::ipv4Checksum(const struct iphdr* ipHeader) noexcept
+{
+ auto partial = ip_checksum_partial(ipHeader, sizeof(iphdr), 0);
+ return ip_checksum_fold(partial);
+}
+
+[[nodiscard]] __be16 XskPacket::tcp_udp_v4_checksum(const struct iphdr* ipHeader) const noexcept
+{
+ // ip options is not supported !!!
+ const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
+ auto sum = tcp_udp_v4_header_checksum_partial(ipHeader->saddr, ipHeader->daddr, ipHeader->protocol, l4Length);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
+ return ip_checksum_fold(sum);
+}
+
+[[nodiscard]] __be16 XskPacket::tcp_udp_v6_checksum(const struct ipv6hdr* ipv6) const noexcept
+{
+ const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
+ uint64_t sum = tcp_udp_v6_header_checksum_partial(&ipv6->saddr, &ipv6->daddr, ipv6->nexthdr, l4Length);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
+ return ip_checksum_fold(sum);
+}
+
+[[nodiscard]] uint64_t XskPacket::ip_checksum_partial(const void* ptr, const size_t len, uint64_t sum) noexcept
+{
+ size_t position{0};
+ /* Main loop: 32 bits at a time */
+ for (position = 0; position < len; position += sizeof(uint32_t)) {
+ uint32_t value{};
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
+ sum += value;
+ }
+
+ /* Handle un-32bit-aligned trailing bytes */
+ if ((len - position) >= 2) {
+ uint16_t value{};
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
+ sum += value;
+ position += sizeof(value);
+ }
+
+ if ((len - position) > 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ const auto* ptr8 = static_cast<const uint8_t*>(ptr) + position;
+ sum += ntohs(*ptr8 << 8); /* RFC says pad last byte */
+ }
+
+ return sum;
+}
+
+[[nodiscard]] __be16 XskPacket::ip_checksum_fold(uint64_t sum) noexcept
+{
+ while ((sum & ~0xffffffffULL) != 0U) {
+ sum = (sum >> 32) + (sum & 0xffffffffULL);
+ }
+ while ((sum & 0xffff0000ULL) != 0U) {
+ sum = (sum >> 16) + (sum & 0xffffULL);
+ }
+
+ return static_cast<__be16>(~sum);
+}
+
+#ifndef __packed
+#define packed_attribute __attribute__((packed))
+#else
+#define packed_attribute __packed
+#endif
+
+// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
+[[nodiscard]] uint64_t XskPacket::tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept
+{
+ struct header
+ {
+ __be32 src_ip;
+ __be32 dst_ip;
+ __uint8_t mbz;
+ __uint8_t protocol;
+ __be16 length;
+ };
+ /* The IPv4 pseudo-header is defined in RFC 793, Section 3.1. */
+ struct ipv4_pseudo_header_t
+ {
+ /* We use a union here to avoid aliasing issues with gcc -O2 */
+ union
+ {
+ header packed_attribute fields;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+ uint32_t words[3];
+ };
+ };
+ ipv4_pseudo_header_t pseudo_header{};
+ static_assert(sizeof(pseudo_header) == 12, "IPv4 pseudo-header size is incorrect");
+
+ /* Fill in the pseudo-header. */
+ pseudo_header.fields.src_ip = src_ip;
+ pseudo_header.fields.dst_ip = dst_ip;
+ pseudo_header.fields.mbz = 0;
+ pseudo_header.fields.protocol = protocol;
+ pseudo_header.fields.length = htons(len);
+ return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
+}
+
+[[nodiscard]] uint64_t XskPacket::tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept
+{
+ struct header
+ {
+ struct in6_addr src_ip;
+ struct in6_addr dst_ip;
+ __be32 length;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+ __uint8_t mbz[3];
+ __uint8_t next_header;
+ };
+ /* The IPv6 pseudo-header is defined in RFC 2460, Section 8.1. */
+ struct ipv6_pseudo_header_t
+ {
+ /* We use a union here to avoid aliasing issues with gcc -O2 */
+ union
+ {
+ header packed_attribute fields;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+ uint32_t words[10];
+ };
+ };
+ ipv6_pseudo_header_t pseudo_header{};
+ static_assert(sizeof(pseudo_header) == 40, "IPv6 pseudo-header size is incorrect");
+
+ /* Fill in the pseudo-header. */
+ pseudo_header.fields.src_ip = *src_ip;
+ pseudo_header.fields.dst_ip = *dst_ip;
+ pseudo_header.fields.length = htonl(len);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memset(pseudo_header.fields.mbz, 0, sizeof(pseudo_header.fields.mbz));
+ pseudo_header.fields.next_header = protocol;
+ return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
+}
+
+void XskPacket::setHeader(PacketBuffer& buf)
+{
+ memcpy(frame, buf.data(), buf.size());
+ frameLength = buf.size();
+ buf.clear();
+ flags = 0;
+ if (!parse(true)) {
+ throw std::runtime_error("Error setting the XSK frame header");
+ }
+}
+
+PacketBuffer XskPacket::cloneHeaderToPacketBuffer() const
+{
+ const auto size = getFrameLen() - getDataSize();
+ PacketBuffer tmp(size);
+ memcpy(tmp.data(), frame, size);
+ return tmp;
+}
+
+int XskWorker::createEventfd()
+{
+ auto desc = ::eventfd(0, EFD_CLOEXEC);
+ if (desc < 0) {
+ throw runtime_error("Unable create eventfd");
+ }
+ return desc;
+}
+
+void XskWorker::waitForXskSocket() const noexcept
+{
+ uint64_t value = read(workerWaker, &value, sizeof(value));
+}
+
+void XskWorker::notifyXskSocket() const
+{
+ notify(xskSocketWaker);
+}
+
+std::shared_ptr<XskWorker> XskWorker::create(Type type, const std::shared_ptr<LockGuarded<std::vector<uint64_t>>>& frames)
+{
+ return std::make_shared<XskWorker>(type, frames);
+}
+
+void XskSocket::addWorker(std::shared_ptr<XskWorker> worker)
+{
+ const auto socketWaker = worker->xskSocketWaker.getHandle();
+ worker->setUmemBufBase(umem.bufBase);
+ d_workers.insert({socketWaker, std::move(worker)});
+ fds.push_back(pollfd{
+ .fd = socketWaker,
+ .events = POLLIN,
+ .revents = 0});
+};
+
+void XskSocket::addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest)
+{
+ d_workerRoutes.lock()->insert({dest, worker});
+}
+
+void XskSocket::removeWorkerRoute(const ComboAddress& dest)
+{
+ d_workerRoutes.lock()->erase(dest);
+}
+
+void XskWorker::setUmemBufBase(uint8_t* base)
+{
+ d_umemBufBase = base;
+}
+
+uint64_t XskWorker::frameOffset(const XskPacket& packet) const noexcept
+{
+ return packet.getFrameOffsetFrom(d_umemBufBase);
+}
+
+void XskWorker::notifyWorker() const
+{
+ notify(workerWaker);
+}
+
+bool XskWorker::hasIncomingFrames()
+{
+ if (d_type == Type::OutgoingOnly) {
+ throw std::runtime_error("Looking for incoming packets in an outgoing-only XSK Worker");
+ }
+
+ return d_incomingPacketsQueue.read_available() != 0U;
+}
+
+void XskWorker::processIncomingFrames(const std::function<void(XskPacket& packet)>& callback)
+{
+ if (d_type == Type::OutgoingOnly) {
+ throw std::runtime_error("Looking for incoming packets in an outgoing-only XSK Worker");
+ }
+
+ d_incomingPacketsQueue.consume_all(callback);
+}
+
+void XskWorker::processOutgoingFrames(const std::function<void(XskPacket& packet)>& callback)
+{
+ d_outgoingPacketsQueue.consume_all(callback);
+}
+
+void XskSocket::getMACFromIfName()
+{
+ ifreq ifr{};
+ auto desc = FDWrapper(::socket(AF_INET, SOCK_DGRAM, 0));
+ if (desc < 0) {
+ throw std::runtime_error("Error creating a socket to get the MAC address of interface " + ifName);
+ }
+
+ if (ifName.size() >= IFNAMSIZ) {
+ throw std::runtime_error("Unable to get MAC address for interface " + ifName + ": name too long");
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ strncpy(ifr.ifr_name, ifName.c_str(), ifName.length() + 1);
+ if (ioctl(desc.getHandle(), SIOCGIFHWADDR, &ifr) < 0 || ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ throw std::runtime_error("Error getting MAC address for interface " + ifName);
+ }
+ static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= std::tuple_size<decltype(source)>{}, "The size of an ARPHRD_ETHER MAC address is smaller than expected");
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(source.data(), ifr.ifr_hwaddr.sa_data, source.size());
+}
+
+[[nodiscard]] int XskSocket::timeDifference(const timespec& lhs, const timespec& rhs) noexcept
+{
+ const auto res = lhs.tv_sec * 1000 + lhs.tv_nsec / 1000000L - (rhs.tv_sec * 1000 + rhs.tv_nsec / 1000000L);
+ return static_cast<int>(res);
+}
+
+void XskWorker::cleanWorkerNotification() const noexcept
+{
+ uint64_t value = read(xskSocketWaker, &value, sizeof(value));
+}
+
+void XskWorker::cleanSocketNotification() const noexcept
+{
+ uint64_t value = read(workerWaker, &value, sizeof(value));
+}
+
+std::vector<pollfd> getPollFdsForWorker(XskWorker& info)
+{
+ std::vector<pollfd> fds;
+ int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+ if (timerfd < 0) {
+ throw std::runtime_error("create_timerfd failed");
+ }
+ fds.push_back(pollfd{
+ .fd = info.workerWaker,
+ .events = POLLIN,
+ .revents = 0,
+ });
+ fds.push_back(pollfd{
+ .fd = timerfd,
+ .events = POLLIN,
+ .revents = 0,
+ });
+ return fds;
+}
+
+std::optional<XskPacket> XskWorker::getEmptyFrame()
+{
+ auto frames = d_sharedEmptyFrameOffset->lock();
+ if (frames->empty()) {
+ return std::nullopt;
+ }
+ auto offset = frames->back();
+ frames->pop_back();
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ return XskPacket(offset + d_umemBufBase, 0, d_frameSize);
+}
+
+void XskWorker::markAsFree(const XskPacket& packet)
+{
+ auto offset = frameOffset(packet);
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, d_sharedEmptyFrameOffset, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+ {
+ auto frames = d_sharedEmptyFrameOffset->lock();
+ frames->push_back(offset);
+ }
+}
+
+uint32_t XskPacket::getFlags() const noexcept
+{
+ return flags;
+}
+
+void XskPacket::updatePacket() noexcept
+{
+ if ((flags & UPDATE) == 0U) {
+ return;
+ }
+ if ((flags & REWRITE) == 0U) {
+ changeDirectAndUpdateChecksum();
+ }
+}
+#endif /* HAVE_XSK */
+++ /dev/null
-../xsk.hh
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+#include "config.h"
+
+#ifdef HAVE_XSK
+#include <array>
+#include <bits/types/struct_timespec.h>
+#include <boost/lockfree/spsc_queue.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/member.hpp>
+#include <cstdint>
+#include <memory>
+#include <poll.h>
+#include <queue>
+#include <stdexcept>
+#include <string>
+#include <unistd.h>
+#include <unordered_map>
+#include <vector>
+
+#include <xdp/xsk.h>
+
+#include "iputils.hh"
+#include "lock.hh"
+#include "misc.hh"
+#include "noinitvector.hh"
+
+class XskPacket;
+class XskWorker;
+class XskSocket;
+
+using MACAddr = std::array<uint8_t, 6>;
+
+// We use an XskSocket to manage an AF_XDP Socket corresponding to a NIC queue.
+// The XDP program running in the kernel redirects the data to the XskSocket in userspace.
+// We allocate frames that are placed into the descriptors in the fill queue, allowing the kernel to put incoming packets into the frames and place descriptors into the rx queue.
+// Once we have read the descriptors from the rx queue we release them, but we own the frames.
+// After we are done with the frame, we place them into descriptors of either the fill queue (empty frames) or tx queues (packets to be sent).
+// Once the kernel is done, it places descriptors referencing these frames into the cq where we can recycle them (packets destined to the tx queue or empty frame to the fill queue).
+
+// XskSocket routes packets to multiple worker threads registered on XskSocket via XskSocket::addWorker based on the destination port number of the packet.
+// The kernel and the worker thread holding XskWorker will wake up the XskSocket through XskFd and the Eventfd corresponding to each worker thread, respectively.
+
+class XskSocket
+{
+ struct XskUmem
+ {
+ xsk_umem* umem{nullptr};
+ uint8_t* bufBase{nullptr};
+ size_t size{0};
+ void umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config);
+ ~XskUmem();
+ XskUmem() = default;
+ };
+ using WorkerContainer = std::unordered_map<int, std::shared_ptr<XskWorker>>;
+ WorkerContainer d_workers;
+ using WorkerRoutesMap = std::unordered_map<ComboAddress, std::shared_ptr<XskWorker>, ComboAddress::addressPortOnlyHash>;
+ // it might be better to move to a StateHolder for performance
+ LockGuarded<WorkerRoutesMap> d_workerRoutes;
+ // number of frames to keep in sharedEmptyFrameOffset
+ static constexpr size_t holdThreshold = 256;
+ // number of frames to insert into the fill queue
+ static constexpr size_t fillThreshold = 128;
+ static constexpr size_t frameSize = 2048;
+ // number of entries (frames) in the umem
+ const size_t frameNum;
+ // responses that have been delayed
+ std::priority_queue<XskPacket> waitForDelay;
+ MACAddr source{};
+ const std::string ifName;
+ // AF_XDP socket then worker waker sockets
+ vector<pollfd> fds;
+ // list of frames, aka (indexes of) umem entries that can be reused to fill fq,
+ // collected from packets that we could not route (unknown destination),
+ // could not parse, were dropped during processing (!UPDATE), or
+ // simply recycled from cq after being processed by the kernel
+ vector<uint64_t> uniqueEmptyFrameOffset;
+ // completion ring: queue where sent packets are stored by the kernel
+ xsk_ring_cons cq{};
+ // rx ring: queue where the incoming packets are stored, read by XskRouter
+ xsk_ring_cons rx{};
+ // fill ring: queue where umem entries available to be filled (put into rx) are stored
+ xsk_ring_prod fq{};
+ // tx ring: queue where outgoing packets are stored
+ xsk_ring_prod tx{};
+ std::unique_ptr<xsk_socket, void (*)(xsk_socket*)> socket;
+ XskUmem umem;
+
+ static constexpr uint32_t fqCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 4;
+ static constexpr uint32_t cqCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 4;
+ static constexpr uint32_t rxCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 2;
+ static constexpr uint32_t txCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 2;
+
+ constexpr static bool isPowOfTwo(uint32_t value) noexcept;
+ [[nodiscard]] static int timeDifference(const timespec& lhs, const timespec& rhs) noexcept;
+
+ [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
+ [[nodiscard]] int firstTimeout();
+ void getMACFromIfName();
+
+public:
+ static void clearDestinationMap(const std::string& mapPath, bool isV6);
+ static void addDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
+ static void removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
+ static constexpr size_t getFrameSize()
+ {
+ return frameSize;
+ }
+ // list of free umem entries that can be reused
+ std::shared_ptr<LockGuarded<vector<uint64_t>>> sharedEmptyFrameOffset;
+ XskSocket(size_t frameNum, std::string ifName, uint32_t queue_id, const std::string& xskMapPath);
+ [[nodiscard]] int xskFd() const noexcept;
+ // wait until one event has occurred
+ [[nodiscard]] int wait(int timeout);
+ // add as many packets as possible to the rx queue for sending */
+ void send(std::vector<XskPacket>& packets);
+ // look at incoming packets in rx, return them if parsing succeeeded
+ [[nodiscard]] std::vector<XskPacket> recv(uint32_t recvSizeMax, uint32_t* failedCount);
+ void addWorker(std::shared_ptr<XskWorker> worker);
+ void addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest);
+ void removeWorkerRoute(const ComboAddress& dest);
+ [[nodiscard]] std::string getMetrics() const;
+ [[nodiscard]] std::string getXDPMode() const;
+ void markAsFree(const XskPacket& packet);
+ [[nodiscard]] const std::shared_ptr<XskWorker>& getWorkerByDescriptor(int desc) const
+ {
+ return d_workers.at(desc);
+ }
+ [[nodiscard]] std::shared_ptr<XskWorker> getWorkerByDestination(const ComboAddress& destination)
+ {
+ auto routes = d_workerRoutes.lock();
+ auto workerIt = routes->find(destination);
+ if (workerIt == routes->end()) {
+ return nullptr;
+ }
+ return workerIt->second;
+ }
+ [[nodiscard]] const std::vector<pollfd>& getDescriptors() const
+ {
+ return fds;
+ }
+ [[nodiscard]] MACAddr getSourceMACAddress() const
+ {
+ return source;
+ }
+ [[nodiscard]] const std::string& getInterfaceName() const
+ {
+ return ifName;
+ }
+ // pick ups available frames from uniqueEmptyFrameOffset
+ // insert entries from uniqueEmptyFrameOffset into fq
+ void fillFq(uint32_t fillSize = fillThreshold) noexcept;
+ // picks up entries that have been processed (sent) from cq and push them into uniqueEmptyFrameOffset
+ void recycle(size_t size) noexcept;
+ // look at delayed packets, and send the ones that are ready
+ void pickUpReadyPacket(std::vector<XskPacket>& packets);
+ void pushDelayed(XskPacket& packet)
+ {
+ waitForDelay.push(packet);
+ }
+};
+
+struct ethhdr;
+struct iphdr;
+struct ipv6hdr;
+struct udphdr;
+
+class XskPacket
+{
+public:
+ enum Flags : uint32_t
+ {
+ /* whether the payload has been modified */
+ UPDATE = 1 << 0,
+ DELAY = 1 << 1,
+ /* whether the headers have already been updated */
+ REWRITE = 1 << 2
+ };
+
+private:
+ ComboAddress from;
+ ComboAddress to;
+ timespec sendTime{};
+ uint8_t* frame{nullptr};
+ size_t frameLength{0};
+ size_t frameSize{0};
+ uint32_t flags{0};
+ bool v6{false};
+
+ // You must set ipHeader.check = 0 before calling this method
+ [[nodiscard]] static __be16 ipv4Checksum(const struct iphdr*) noexcept;
+ [[nodiscard]] static uint64_t ip_checksum_partial(const void* p, size_t len, uint64_t sum) noexcept;
+ [[nodiscard]] static __be16 ip_checksum_fold(uint64_t sum) noexcept;
+ [[nodiscard]] static uint64_t tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept;
+ [[nodiscard]] static uint64_t tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept;
+ static void rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept;
+ static void rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept;
+
+ // You must set l4Header.check = 0 before calling this method
+ // ip options is not supported
+ [[nodiscard]] __be16 tcp_udp_v4_checksum(const struct iphdr*) const noexcept;
+ // You must set l4Header.check = 0 before calling this method
+ [[nodiscard]] __be16 tcp_udp_v6_checksum(const struct ipv6hdr*) const noexcept;
+ /* offset of the L4 (udphdr) header (after ethhdr and iphdr/ipv6hdr) */
+ [[nodiscard]] size_t getL4HeaderOffset() const noexcept;
+ /* offset of the data after the UDP header */
+ [[nodiscard]] size_t getDataOffset() const noexcept;
+ [[nodiscard]] size_t getDataSize() const noexcept;
+ [[nodiscard]] ethhdr getEthernetHeader() const noexcept;
+ void setEthernetHeader(const ethhdr& ethHeader) noexcept;
+ [[nodiscard]] iphdr getIPv4Header() const noexcept;
+ void setIPv4Header(const iphdr& ipv4Header) noexcept;
+ [[nodiscard]] ipv6hdr getIPv6Header() const noexcept;
+ void setIPv6Header(const ipv6hdr& ipv6Header) noexcept;
+ [[nodiscard]] udphdr getUDPHeader() const noexcept;
+ void setUDPHeader(const udphdr& udpHeader) noexcept;
+ /* exchange the source and destination addresses (ethernet and IP) */
+ void changeDirectAndUpdateChecksum() noexcept;
+
+ constexpr static uint8_t DefaultTTL = 64;
+
+public:
+ [[nodiscard]] const ComboAddress& getFromAddr() const noexcept;
+ [[nodiscard]] const ComboAddress& getToAddr() const noexcept;
+ [[nodiscard]] const void* getPayloadData() const;
+ [[nodiscard]] bool isIPV6() const noexcept;
+ [[nodiscard]] size_t getCapacity() const noexcept;
+ [[nodiscard]] uint32_t getDataLen() const noexcept;
+ [[nodiscard]] uint32_t getFrameLen() const noexcept;
+ [[nodiscard]] PacketBuffer clonePacketBuffer() const;
+ [[nodiscard]] PacketBuffer cloneHeaderToPacketBuffer() const;
+ void setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept;
+ bool setPayload(const PacketBuffer& buf);
+ /* rewrite the headers, usually after setAddr() and setPayload() have been called */
+ void rewrite() noexcept;
+ void setHeader(PacketBuffer& buf);
+ XskPacket(uint8_t* frame, size_t dataSize, size_t frameSize);
+ void addDelay(int relativeMilliseconds) noexcept;
+ /* if the payload have been updated, and the headers have not been rewritten, exchange the source
+ and destination addresses (ethernet and IP) and rewrite the headers */
+ void updatePacket() noexcept;
+ // parse IP and UDP payloads
+ bool parse(bool fromSetHeader);
+ [[nodiscard]] uint32_t getFlags() const noexcept;
+ [[nodiscard]] timespec getSendTime() const noexcept
+ {
+ return sendTime;
+ }
+ [[nodiscard]] uint64_t getFrameOffsetFrom(const uint8_t* base) const noexcept
+ {
+ return frame - base;
+ }
+};
+bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept;
+
+// XskWorker obtains XskPackets of specific ports in the NIC from XskSocket through cq.
+// After finishing processing the packet, XskWorker puts the packet into sq so that XskSocket decides whether to send it through the network card according to XskPacket::flags.
+// XskWorker wakes up XskSocket via xskSocketWaker after putting the packets in sq.
+class XskWorker
+{
+public:
+ enum class Type : uint8_t
+ {
+ OutgoingOnly,
+ Bidirectional
+ };
+
+private:
+ using XskPacketRing = boost::lockfree::spsc_queue<XskPacket, boost::lockfree::capacity<XSK_RING_CONS__DEFAULT_NUM_DESCS * 2>>;
+ // queue of packets to be processed by this worker
+ XskPacketRing d_incomingPacketsQueue;
+ // queue of packets processed by this worker (to be sent, or discarded)
+ XskPacketRing d_outgoingPacketsQueue;
+ // list of frames that are shared with the XskRouter
+ std::shared_ptr<LockGuarded<vector<uint64_t>>> d_sharedEmptyFrameOffset;
+ uint8_t* d_umemBufBase{nullptr};
+ const size_t d_frameSize{XskSocket::getFrameSize()};
+ Type d_type;
+
+public:
+ FDWrapper workerWaker;
+ FDWrapper xskSocketWaker;
+
+ static int createEventfd();
+ static void notify(int desc);
+ static std::shared_ptr<XskWorker> create(Type type, const std::shared_ptr<LockGuarded<std::vector<uint64_t>>>& frames);
+
+ XskWorker(Type type, const std::shared_ptr<LockGuarded<std::vector<uint64_t>>>& frames);
+ void setUmemBufBase(uint8_t* base);
+ void pushToProcessingQueue(XskPacket& packet);
+ void pushToSendQueue(XskPacket& packet);
+ bool hasIncomingFrames();
+ void processIncomingFrames(const std::function<void(XskPacket& packet)>& callback);
+ void processOutgoingFrames(const std::function<void(XskPacket& packet)>& callback);
+ void markAsFree(const XskPacket& packet);
+ // notify worker that at least one packet is available for processing
+ void notifyWorker() const;
+ // notify the router that packets are ready to be sent
+ void notifyXskSocket() const;
+ void waitForXskSocket() const noexcept;
+ void cleanWorkerNotification() const noexcept;
+ void cleanSocketNotification() const noexcept;
+ [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
+ // get an empty umem entry from sharedEmptyFrameOffset
+ std::optional<XskPacket> getEmptyFrame();
+};
+std::vector<pollfd> getPollFdsForWorker(XskWorker& info);
+#else
+class XskSocket
+{
+};
+class XskPacket
+{
+};
+class XskWorker
+{
+};
+
+#endif /* HAVE_XSK */
* This file describes the message format used by the protobuf logging feature in PowerDNS and dnsdist.
*
* MIT License
- *
+ *
* Copyright (c) 2016-now PowerDNS.COM B.V. and its contributors.
- *
+ *
* 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
optional string custom = 8; // The name of the event for custom events
}
repeated Event trace = 23;
+
optional HTTPVersion httpVersion = 24; // HTTP version used for DNS over HTTP
+ optional uint64 workerId = 25; // Thread id
+ optional bool packetCacheHit = 26; // Was it a packet cache hit?
+ optional uint32 outgoingQueries = 27; // Number of outgoing queries used to answer the query
}
message PBDNSMessageList {
#include <string_view>
#include <boost/version.hpp>
-
-#if BOOST_VERSION >= 105300
#include <boost/container/string.hpp>
-#endif
inline bool dns_isspace(char c)
{
inline bool canonCompare(const DNSName& rhs) const;
bool slowCanonCompare(const DNSName& rhs) const;
-#if BOOST_VERSION >= 105300
typedef boost::container::string string_t;
-#else
- typedef std::string string_t;
-#endif
+
const string_t& getStorage() const {
return d_storage;
}
ComboAddress DNSPacket::getInnerRemote() const
{
- if (d_inner_remote)
- return *d_inner_remote;
- return d_remote;
+ return d_inner_remote ? *d_inner_remote : d_remote;
}
uint16_t DNSPacket::getRemotePort() const
pos->dr.getContent()->toPacket(pw);
if(pw.size() + optsize > (d_tcp ? 65535 : getMaxReplyLen())) {
if (throwsOnTruncation) {
- throw PDNSException("attempt to write an oversized chunk");
+ throw PDNSException("attempt to write an oversized chunk, see https://docs.powerdns.com/authoritative/settings.html#workaround-11804");
}
pw.rollback();
pw.truncate();
bool gotit=false;
for(const auto & answer : mdp.d_answers) {
- if(answer.first.d_type == QType::TSIG && answer.first.d_class == QType::ANY) {
+ if(answer.d_type == QType::TSIG && answer.d_class == QType::ANY) {
// cast can fail, f.e. if d_content is an UnknownRecordContent.
- auto content = getRR<TSIGRecordContent>(answer.first);
+ auto content = getRR<TSIGRecordContent>(answer);
if (!content) {
g_log<<Logger::Error<<"TSIG record has no or invalid content (invalid packet)"<<endl;
return false;
}
*trc = *content;
- *keyname = answer.first.d_name;
+ *keyname = answer.d_name;
gotit=true;
}
}
return false;
}
- if(answer.first.d_type == QType::TKEY) {
+ if(answer.d_type == QType::TKEY) {
// cast can fail, f.e. if d_content is an UnknownRecordContent.
- auto content = getRR<TKEYRecordContent>(answer.first);
+ auto content = getRR<TKEYRecordContent>(answer);
if (!content) {
g_log<<Logger::Error<<"TKEY record has no or invalid content (invalid packet)"<<endl;
return false;
}
*tr = *content;
- *keyname = answer.first.d_name;
+ *keyname = answer.d_name;
gotit=true;
}
}
return d_ednscookievalid;
}
+void DNSPacket::setRealRemote(const Netmask& netmask) {
+ d_eso.source = netmask;
+ d_haveednssubnet = true;
+}
+
Netmask DNSPacket::getRealRemote() const
{
- if(d_haveednssubnet)
- return d_eso.source;
- return Netmask(getInnerRemote());
+ return d_haveednssubnet ? d_eso.source : Netmask{getInnerRemote()};
}
void DNSPacket::setSocket(Utility::sock_t sock)
{
- d_socket=sock;
+ d_socket = sock;
}
void DNSPacket::commitD()
ComboAddress getRemote() const;
ComboAddress getInnerRemote() const; // for proxy protocol
Netmask getRealRemote() const;
+ void setRealRemote(const Netmask& netmask);
ComboAddress getLocal() const
{
ComboAddress ca;
void clearRecords(); //!< when building a packet, wipe all previously added records (clears 'rrs')
- /** Add a DNSZoneRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions,
+ /** Add a DNSZoneRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions,
Answers, Authority and Additional. See RFC 1034 and 1035 for details. You can specify where a record needs to go in the
DNSZoneRecord d_place field */
void addRecord(DNSZoneRecord&&); // adds to 'rrs'
vector<DNSZoneRecord>& getRRS() { return d_rrs; }
bool checkForCorrectTSIG(UeberBackend* B, DNSName* keyname, string* secret, TSIGRecordContent* trc) const;
- static uint16_t s_udpTruncationThreshold;
+ static uint16_t s_udpTruncationThreshold;
static bool s_doEDNSSubnetProcessing;
static bool s_doEDNSCookieProcessing;
static string s_EDNSCookieKey;
d_tsigPos = recordStartPos;
}
- d_answers.emplace_back(std::move(dr), pr.getPosition() - sizeof(dnsheader));
+ d_answers.emplace_back(std::move(dr));
}
#if 0
}
for (const auto& record : d_answers) {
- if (record.first.d_place == DNSResourceRecord::ADDITIONAL && record.first.d_type == QType::OPT) {
+ if (record.d_place == DNSResourceRecord::ADDITIONAL && record.d_type == QType::OPT) {
return true;
}
}
return s.str();
}
+ [[nodiscard]] std::string toString() const
+ {
+ std::string ret(d_name.toLogString());
+ ret += '|';
+ ret += QType(d_type).toString();
+ ret += '|';
+ ret += getContent()->getZoneRepresentation();
+ return ret;
+ }
+
void setContent(const std::shared_ptr<const DNSRecordContent>& content)
{
d_content = content;
DNSName d_qname;
uint16_t d_qclass, d_qtype;
- //uint8_t d_rcode;
dnsheader d_header;
- typedef vector<pair<DNSRecord, uint16_t > > answers_t;
+ using answers_t = vector<DNSRecord>;
//! All answers contained in this packet (everything *but* the question section)
answers_t d_answers;
#include "ednsoptions.hh"
#include "ednssubnet.hh"
+#include <boost/uuid/uuid_io.hpp>
+
extern StatBag S;
-DNSProxy::DNSProxy(const string& remote) :
+DNSProxy::DNSProxy(const string& remote, const string& udpPortRange) :
d_xor(dns_random_uint16())
{
d_resanswers = S.getPointer("recursing-answers");
stringtok(addresses, remote, " ,\t");
d_remote = ComboAddress(addresses[0], 53);
+ vector<string> parts;
+ stringtok(parts, udpPortRange, " ");
+ if (parts.size() != 2) {
+ throw PDNSException("DNS Proxy UDP port range must contain exactly one lower and one upper bound");
+ }
+ unsigned long portRangeLow = std::stoul(parts.at(0));
+ unsigned long portRangeHigh = std::stoul(parts.at(1));
+ if (portRangeLow < 1 || portRangeHigh > 65535) {
+ throw PDNSException("DNS Proxy UDP port range values out of valid port bounds (1 to 65535)");
+ }
+ if (portRangeLow >= portRangeHigh) {
+ throw PDNSException("DNS Proxy UDP port range upper bound " + std::to_string(portRangeHigh) + " must be higher than lower bound (" + std::to_string(portRangeLow) + ")");
+ }
+
if ((d_sock = socket(d_remote.sin4.sin_family, SOCK_DGRAM, 0)) < 0) {
throw PDNSException(string("socket: ") + stringerror());
}
unsigned int attempts = 0;
for (; attempts < 10; attempts++) {
- local.sin4.sin_port = htons(10000 + dns_random(50000));
+ local.sin4.sin_port = htons(portRangeLow + dns_random(portRangeHigh - portRangeLow));
if (::bind(d_sock, (struct sockaddr*)&local, local.getSocklen()) >= 0) { // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
break;
proxythread.detach();
}
-//! look up qname target with r->qtype, plonk it in the answer section of 'r' with name aname
+//! look up qname 'target' with reply->qtype, plonk it in the answer section of 'reply' with name 'aname'
bool DNSProxy::completePacket(std::unique_ptr<DNSPacket>& reply, const DNSName& target, const DNSName& aname, const uint8_t scopeMask)
{
string ECSOptionStr;
if (mdp.d_header.rcode == RCode::NoError) {
for (const auto& answer : mdp.d_answers) {
- if (answer.first.d_place == DNSResourceRecord::ANSWER || (answer.first.d_place == DNSResourceRecord::AUTHORITY && answer.first.d_type == QType::SOA)) {
+ if (answer.d_place == DNSResourceRecord::ANSWER || (answer.d_place == DNSResourceRecord::AUTHORITY && answer.d_type == QType::SOA)) {
- if (answer.first.d_type == iter->second.qtype || (iter->second.qtype == QType::ANY && (answer.first.d_type == QType::A || answer.first.d_type == QType::AAAA))) {
+ if (answer.d_type == iter->second.qtype || (iter->second.qtype == QType::ANY && (answer.d_type == QType::A || answer.d_type == QType::AAAA))) {
DNSZoneRecord dzr;
dzr.dr.d_name = iter->second.aname;
- dzr.dr.d_type = answer.first.d_type;
- dzr.dr.d_ttl = answer.first.d_ttl;
- dzr.dr.d_place = answer.first.d_place;
- dzr.dr.setContent(answer.first.getContent());
+ dzr.dr.d_type = answer.d_type;
+ dzr.dr.d_ttl = answer.d_ttl;
+ dzr.dr.d_place = answer.d_place;
+ dzr.dr.setContent(answer.getContent());
iter->second.complete->addRecord(std::move(dzr));
}
}
class DNSProxy
{
public:
- DNSProxy(const string& remote); //!< creates socket
+ DNSProxy(const string& remote, const string& udpPortRange); //!< creates socket
~DNSProxy(); //<! dtor for DNSProxy
void go(); //!< launches the actual thread
bool completePacket(std::unique_ptr<DNSPacket>& reply, const DNSName& target, const DNSName& aname, uint8_t scopeMask);
eo->d_extFlags=0;
if(mdp.d_header.arcount && !mdp.d_answers.empty()) {
for(const MOADNSParser::answers_t::value_type& val : mdp.d_answers) {
- if(val.first.d_place == DNSResourceRecord::ADDITIONAL && val.first.d_type == QType::OPT) {
- eo->d_packetsize=val.first.d_class;
+ if(val.d_place == DNSResourceRecord::ADDITIONAL && val.d_type == QType::OPT) {
+ eo->d_packetsize=val.d_class;
EDNS0Record stuff;
- uint32_t ttl=ntohl(val.first.d_ttl);
+ uint32_t ttl=ntohl(val.d_ttl);
static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
memcpy(&stuff, &ttl, sizeof(stuff));
eo->d_extRCode=stuff.extRCode;
eo->d_version=stuff.version;
eo->d_extFlags = ntohs(stuff.extFlags);
- auto orc = getRR<OPTRecordContent>(val.first);
+ auto orc = getRR<OPTRecordContent>(val);
if(orc == nullptr)
return false;
orc->getData(eo->d_options);
static void compactAnswerSet(MOADNSParser::answers_t orig, set<DNSRecord>& compacted)
{
- for(MOADNSParser::answers_t::const_iterator i=orig.begin(); i != orig.end(); ++i)
- if(i->first.d_place==DNSResourceRecord::ANSWER)
- compacted.insert(i->first);
+ for (const auto& rec : orig) {
+ if (rec.d_place == DNSResourceRecord::ANSWER) {
+ compacted.insert(rec);
+ }
+ }
}
static bool isRcodeOk(int rcode)
bool ok=true;
for(MOADNSParser::answers_t::const_iterator iter = answers.begin(); iter != answers.end(); ++iter) {
- // cerr<<(int)iter->first.d_place<<", "<<iter->first.d_name<<" "<<iter->first.d_type<<", # "<<answers.size()<<endl;
- if(iter->first.d_place!=2)
- ok=false;
- if(!iter->first.d_name.isRoot() || iter->first.d_type!=QType::NS)
- ok=false;
+ // cerr<<(int)iter->d_place<<", "<<iter->d_name<<" "<<iter->d_type<<", # "<<answers.size()<<endl;
+ if (iter->d_place != 2) {
+ ok = false;
+ }
+ if (!iter->d_name.isRoot() || iter->d_type != QType::NS) {
+ ok = false;
+ }
}
return ok;
}
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#ifdef HAVE_BOOST_GE_148
-#include "histog.hh"
-#endif
+#include "histog.hh"
#include "statbag.hh"
#include "dnspcap.hh"
#include "dnsparser.hh"
("rd", po::value<bool>(), "If set to true, only process RD packets, to false only non-RD, unset: both")
("ipv4", po::value<bool>()->default_value(true), "Process IPv4 packets")
("ipv6", po::value<bool>()->default_value(true), "Process IPv6 packets")
-#ifdef HAVE_BOOST_GE_148
("log-histogram", "Write a log-histogram to file 'log-histogram'")
("full-histogram", po::value<double>(), "Write a log-histogram to file 'full-histogram' with this millisecond bin size")
-#endif
("filter-name,f", po::value<string>(), "Do statistics only for queries within this domain")
("load-stats,l", po::value<string>()->default_value(""), "if set, emit per-second load statistics (questions, answers, outstanding)")
("no-servfail-stats", "Don't include servfails in response time stats")
cout.precision(4);
sum=0;
-#ifdef HAVE_BOOST_GE_148
if(g_vm.count("log-histogram")) {
string fname = g_vm["stats-dir"].as<string>()+"/log-histogram";
ofstream loglog(fname);
throw runtime_error("Unable to write statistics to "+fname);
writeFullHistogramFile(cumul, g_vm["full-histogram"].as<double>(), loglog);
}
-#endif
-
sum=0;
double lastperc=0, perc=0;
*/
#pragma once
#include "dnsrecords.hh"
+#include "dnspacket.hh"
#include <string>
#include <vector>
void incrementHash(std::string& raw);
void decrementHash(std::string& raw);
-void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set<DNSName>& authMap, vector<DNSZoneRecord>& rrs);
+void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set<DNSName>& authSet, vector<DNSZoneRecord>& rrs, DNSPacket* packet=nullptr);
void addTSIG(DNSPacketWriter& pw, TSIGRecordContent& trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly);
bool validateTSIG(const std::string& packet, size_t sigPos, const TSIGTriplet& tt, const TSIGRecordContent& trc, const std::string& previousMAC, const std::string& theirMAC, bool timersOnly, unsigned int dnsHeaderOffset=0);
#include <boost/multi_index/sequenced_index.hpp>
#include "dnssecinfra.hh"
#include "dnsrecords.hh"
+#include "dnspacket.hh"
#include "ueberbackend.hh"
#include "lock.hh"
bool checkNSEC3PARAM(const NSEC3PARAMRecordContent& ns3p, string& msg);
bool setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& n3p, const bool& narrow=false);
bool unsetNSEC3PARAM(const DNSName& zname);
- void getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL);
+ void getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL, DNSPacket* p=nullptr);
bool isPresigned(const DNSName& zname, bool useCache=true);
bool setPresigned(const DNSName& zname);
bool unsetPresigned(const DNSName& zname);
static size_t s_maxEntries;
};
-class DNSPacket;
uint32_t localtime_format_YYYYMMDDSS(time_t t, uint32_t seq);
// for SOA-EDIT
uint32_t calculateEditSOA(uint32_t old_serial, DNSSECKeeper& dk, const DNSName& zonename);
// this is the entrypoint from DNSPacket
static void addSignature(DNSSECKeeper& dk, UeberBackend& db, const DNSName& signer, const DNSName& signQName, const DNSName& wildcardname, uint16_t signQType,
uint32_t signTTL, DNSResourceRecord::Place signPlace,
- sortedRecords_t& toSign, vector<DNSZoneRecord>& outsigned, uint32_t origTTL)
+ sortedRecords_t& toSign, vector<DNSZoneRecord>& outsigned, uint32_t origTTL, DNSPacket* packet)
{
//cerr<<"Asked to sign '"<<signQName<<"'|"<<DNSRecordContent::NumberToType(signQType)<<", "<<toSign.size()<<" records\n";
if(toSign.empty())
vector<RRSIGRecordContent> rrcs;
if(dk.isPresigned(signer)) {
//cerr<<"Doing presignatures"<<endl;
- dk.getPreRRSIGs(db, outsigned, origTTL); // does it all
+ dk.getPreRRSIGs(db, outsigned, origTTL, packet); // does it all
}
else {
if(getRRSIGsForRRSET(dk, signer, wildcardname.countLabels() ? wildcardname : signQName, signQType, signTTL, toSign, rrcs) < 0) {
return false;
}
-void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const set<DNSName>& authSet, vector<DNSZoneRecord>& rrs)
+void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const set<DNSName>& authSet, vector<DNSZoneRecord>& rrs, DNSPacket* packet)
{
stable_sort(rrs.begin(), rrs.end(), rrsigncomp);
for(auto pos = rrs.cbegin(); pos != rrs.cend(); ++pos) {
if(pos != rrs.cbegin() && (signQType != pos->dr.d_type || signQName != pos->dr.d_name)) {
if (getBestAuthFromSet(authSet, authQName, signer))
- addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL);
+ addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL, packet);
}
signedRecords.push_back(*pos);
signQName = pos->dr.d_name.makeLowerCase();
}
}
if (getBestAuthFromSet(authSet, authQName, signer))
- addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL);
+ addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL, packet);
rrs.swap(signedRecords);
}
*/
unsigned int bestpos=0;
*matchLen=0;
-#if BOOST_VERSION >= 105400
- boost::container::static_vector<uint16_t, 34> nvect, pvect;
-#else
- vector<uint16_t> nvect, pvect;
-#endif
+ boost::container::static_vector<uint16_t, 34> nvect;
+ boost::container::static_vector<uint16_t, 34> pvect;
try {
for(auto riter= raw.cbegin(); riter < raw.cend(); ) {
errlog("Unable to bind to %s: %s", ca.toStringWithPort(), strerr(errno));
Will log to stdout. Will syslog in any case with LOG_INFO,
- LOG_WARNING, LOG_ERR respectively. If g_verbose=false, vinfolog is a noop.
+ LOG_WARNING, LOG_ERR respectively. If verbose=false, vinfolog is a noop.
More generically, dolog(someiostream, "Hello %s", stream) will log to someiostream
This will happily print a string to %d! Doesn't do further format processing.
}
#if !defined(RECURSOR)
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
-extern bool g_verbose;
-
#ifdef DNSDIST
namespace dnsdist::logging
{
ISO8601
};
- static void setVerbose(bool value = true)
- {
- g_verbose = value;
- }
static void setSyslog(bool value = true)
{
s_syslog = value;
{
s_verboseStream = std::move(stream);
}
- static bool getVerbose()
- {
- return g_verbose;
- }
static bool getSyslog()
{
return s_syslog;
#endif /* DNSDIST */
}
-#define vinfolog \
- if (g_verbose) \
+#ifdef DNSDIST
+#include "dnsdist-configuration.hh"
+
+#define vinfolog \
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) \
verboselog
+#else
+#define vinfolog \
+ infolog
+#endif
template <typename... Args>
void infolog(const char* formatStr, const Args&... args)
}
#else // RECURSOR
-#define g_verbose 0
#define vinfolog \
- if (g_verbose) \
+ if (false) \
infolog
template <typename... Args>
}
uint8_t* frame = (uint8_t*)malloc(data.length()); // NOLINT: it's the API
if (frame == nullptr) {
- ++d_queueFullDrops; // XXX separate count?
+ ++d_tooLargeCount;
return Result::TooLarge;
}
memcpy(frame, data.c_str(), data.length());
{
return Stats{.d_queued = d_framesSent,
.d_pipeFull = d_queueFullDrops,
- .d_tooLarge = 0,
+ .d_tooLarge = d_tooLargeCount,
.d_otherError = d_permanentFailures};
}
struct fstrm_iothr* d_iothr{nullptr};
std::atomic<uint64_t> d_framesSent{0};
std::atomic<uint64_t> d_queueFullDrops{0};
+ std::atomic<uint64_t> d_tooLargeCount{0};
std::atomic<uint64_t> d_permanentFailures{0};
void cleanup();
// create new tree node for the new key and
// attach the new node under our former parent
- auto new_child = make_unique<TreeNode>(key);
- auto* new_node = new_child.get();
- new_node->d_bits = bits;
- std::swap(parent_ref, new_child); // hereafter new_child points to "this"
- new_node->parent = parent;
+ auto new_intermediate_node = make_unique<TreeNode>(key);
+ new_intermediate_node->d_bits = bits;
+ new_intermediate_node->parent = parent;
+ auto* new_intermediate_node_raw = new_intermediate_node.get();
+
+ // hereafter new_intermediate points to "this"
+ // ie the child of the new intermediate node
+ std::swap(parent_ref, new_intermediate_node);
+ // and we now assign this to current_node so
+ // it's clear it no longer refers to the new
+ // intermediate node
+ std::unique_ptr<TreeNode> current_node = std::move(new_intermediate_node);
// attach "this" node below the new node
// (left or right depending on bit)
- new_child->parent = new_node;
- if (new_child->node.first.getBit(-1 - bits)) {
- std::swap(new_node->right, new_child);
+ // technically the raw pointer escapes the duration of the
+ // unique pointer, but just below we store the unique pointer
+ // in the parent, so it lives as long as necessary
+ // coverity[escape]
+ current_node->parent = new_intermediate_node_raw;
+ if (current_node->node.first.getBit(-1 - bits)) {
+ new_intermediate_node_raw->right = std::move(current_node);
}
else {
- std::swap(new_node->left, new_child);
+ new_intermediate_node_raw->left = std::move(current_node);
}
- return new_node;
+ return new_intermediate_node_raw;
}
//<! Forks branch for new key at indicated bit position
uint16_t port = d_addr.getPort();
if (d_portMask < 16) {
- uint16_t mask = ~(0xFFFF >> d_portMask);
+ auto mask = static_cast<uint16_t>(~(0xFFFF >> d_portMask));
port = port & mask;
}
for (auto& r: mdp.d_answers) {
if(!primarySOA) {
// we have not seen the first SOA record yet
- if (r.first.d_type != QType::SOA) {
- throw std::runtime_error("The first record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"' is not a SOA ("+QType(r.first.d_type).toString()+")");
+ if (r.d_type != QType::SOA) {
+ throw std::runtime_error("The first record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"' is not a SOA ("+QType(r.d_type).toString()+")");
}
- auto sr = getRR<SOARecordContent>(r.first);
- if (!sr) {
+ auto soaRecord = getRR<SOARecordContent>(r);
+ if (!soaRecord) {
throw std::runtime_error("Error getting the content of the first SOA record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"'");
}
- if(sr->d_st.serial == getRR<SOARecordContent>(oursr)->d_st.serial) {
+ if(soaRecord->d_st.serial == getRR<SOARecordContent>(oursr)->d_st.serial) {
// we are up to date
return ret;
}
- primarySOA = std::move(sr);
+ primarySOA = std::move(soaRecord);
++primarySOACount;
- } else if (r.first.d_type == QType::SOA) {
- auto sr = getRR<SOARecordContent>(r.first);
- if (!sr) {
+ } else if (r.d_type == QType::SOA) {
+ auto soaRecord = getRR<SOARecordContent>(r);
+ if (!soaRecord) {
throw std::runtime_error("Error getting the content of SOA record of IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"'");
}
// we hit a marker SOA record
- if (primarySOA->d_st.serial == sr->d_st.serial) {
+ if (primarySOA->d_st.serial == soaRecord->d_st.serial) {
++primarySOACount;
}
}
// When we see the 2nd record, we can decide what the style is
if (records.size() == 1 && style == Unknown) {
- if (r.first.d_type != QType::SOA) {
- // Non-empty AXFR style has a non-SOA record following the first SOA
- style = AXFR;
- }
- else if (primarySOACount == expectedSOAForAXFR) {
- // Empty zone AXFR style: start SOA is immediately followed by end marker SOA
+ if (r.d_type != QType::SOA || primarySOACount == expectedSOAForAXFR) {
+ // 1. Non-empty AXFR style has a non-SOA record following the first SOA
+ // 2. Empty zone AXFR style: start SOA is immediately followed by end marker SOA
style = AXFR;
}
else {
}
}
- if(r.first.d_place != DNSResourceRecord::ANSWER) {
- if(r.first.d_type == QType::TSIG)
+ if(r.d_place != DNSResourceRecord::ANSWER) {
+ if (r.d_type == QType::TSIG) {
continue;
+ }
- if(r.first.d_type == QType::OPT)
+ if (r.d_type == QType::OPT) {
continue;
+ }
- throw std::runtime_error("Unexpected record (" +QType(r.first.d_type).toString()+") in non-answer section ("+std::to_string(r.first.d_place)+") in IXFR response for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort());
+ throw std::runtime_error("Unexpected record (" +QType(r.d_type).toString()+") in non-answer section ("+std::to_string(r.d_place)+") in IXFR response for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort());
}
- r.first.d_name.makeUsRelative(zone);
- records.push_back(r.first);
+ r.d_name.makeUsRelative(zone);
+ records.push_back(r);
}
}
for (auto &answer : mdp.d_answers) {
// from dnsparser.hh:
// typedef vector<pair<DNSRecord, uint16_t > > answers_t;
- if (answer.first.d_type == QType::SOA && answer.first.d_place == DNSResourceRecord::AUTHORITY) {
- clientSOA = getRR<SOARecordContent>(answer.first);
+ if (answer.d_type == QType::SOA && answer.d_place == DNSResourceRecord::AUTHORITY) {
+ clientSOA = getRR<SOARecordContent>(answer);
if (clientSOA != nullptr) {
break;
}
}
if (config["gid"].IsDefined()) {
+ bool gidParsed = false;
auto gid = config["gid"].as<string>();
try {
configuration.gid = pdns::checked_stoi<gid_t>(gid);
+ gidParsed = true;
}
catch (const std::exception& e) {
- g_log<<Logger::Error<<"Can not parse gid "<<gid<<endl;
- had_error = true;
+ configuration.gid = 0;
}
- if (configuration.gid != 0) {
+ if (!gidParsed) {
//NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
const struct group *gr = getgrnam(gid.c_str());
if (gr == nullptr) {
}
if (config["uid"].IsDefined()) {
+ bool uidParsed = false;
auto uid = config["uid"].as<string>();
try {
configuration.uid = pdns::checked_stoi<uid_t>(uid);
+ uidParsed = true;
}
catch (const std::exception& e) {
- g_log<<Logger::Error<<"Can not parse uid "<<uid<<endl;
- had_error = true;
+ configuration.uid = 0;
}
- if (configuration.uid != 0) {
+ if (!uidParsed) {
//NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
const struct passwd *pw = getpwnam(uid.c_str());
if (pw == nullptr) {
had_error = true;
} else {
configuration.uid = pw->pw_uid;
+ uidParsed = true;
}
//NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
+ }
+ if (uidParsed) {
configuration.userInfo = getpwuid(configuration.uid);
}
}
}
if (configuration->uid != 0) {
- g_log<<Logger::Notice<<"Dropping effective user-id to "<<configuration->uid<<endl;
- if (setuid(configuration->uid) < 0) {
- g_log<<Logger::Error<<"Could not set user id to "<<configuration->uid<<": "<<stringerror()<<endl;
- had_error = true;
- }
if (configuration->userInfo == nullptr) {
if (setgroups(0, nullptr) < 0) {
g_log<<Logger::Error<<"Unable to drop supplementary gids: "<<stringerror()<<endl;
had_error = true;
}
}
+
+ g_log<<Logger::Notice<<"Dropping effective user-id to "<<configuration->uid<<endl;
+ if (setuid(configuration->uid) < 0) {
+ g_log<<Logger::Error<<"Could not set user id to "<<configuration->uid<<": "<<stringerror()<<endl;
+ had_error = true;
+ }
}
if (had_error) {
string reply;
reply.resize(4096);
// will throw a NetworkError on timeout
- ssize_t got = s.readWithTimeout(&reply[0], reply.size(), timeout);
- if (got < 0 || static_cast<size_t>(got) < sizeof(dnsheader)) {
+ size_t got = s.readWithTimeout(reply.data(), reply.size(), timeout);
+ if (got < sizeof(dnsheader)) {
throw std::runtime_error("Invalid response size " + std::to_string(got));
}
throw std::runtime_error("RCODE from response is not NoError but " + RCode::to_s(mdp.d_header.rcode));
}
for(const auto& r: mdp.d_answers) {
- if(r.first.d_type == QType::SOA) {
- sr = getRR<SOARecordContent>(r.first);
+ if(r.d_type == QType::SOA) {
+ sr = getRR<SOARecordContent>(r);
if(sr != nullptr) {
return sr->d_st.serial;
}
"default": {
"certifi": {
"hashes": [
- "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
- "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
+ "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b",
+ "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"
],
"index": "pypi",
"markers": "python_version >= '3.6'",
- "version": "==2023.7.22"
+ "version": "==2024.7.4"
},
"charset-normalizer": {
"hashes": [
},
"urllib3": {
"hashes": [
- "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07",
- "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"
+ "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3",
+ "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"
],
"index": "pypi",
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
- "version": "==1.26.18"
+ "version": "==1.26.19"
}
},
"develop": {}
* `version` : this json format version identifier
* `key_style` : `single` or `split` depending on the number of keys
-* `xsk_algo` : algorithm to roll as name or number, see bellow
+* `xsk_algo` : algorithm to roll as name or number, see below
* `xsk_frequency` : the rate at which to roll the keys
* `xsk_keysize` : keysize in bits
* `xsk_method` : strategy for the rollover (for now, only `prepublish` is supported)
-
#include "config.h"
#include "libssl.hh"
#include <pthread.h>
#include <openssl/conf.h>
+#if defined(DNSDIST) && (OPENSSL_VERSION_MAJOR < 3 || !defined(HAVE_TLS_PROVIDERS))
#ifndef OPENSSL_NO_ENGINE
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage): used by the preprocessor below
+#define DNSDIST_ENABLE_LIBSSL_ENGINE 1
#include <openssl/engine.h>
#endif
+#endif
#include <openssl/err.h>
#ifndef DISABLE_OCSP_STAPLING
#include <openssl/ocsp.h>
#undef CERT
#include "misc.hh"
+#include "tcpiohandler.hh"
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2090100fL)
/* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */
#if OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
static LockGuarded<std::unordered_map<std::string, std::unique_ptr<OSSL_PROVIDER, decltype(&OSSL_PROVIDER_unload)>>> s_providers;
#else
-#ifndef OPENSSL_NO_ENGINE
+#if defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
static LockGuarded<std::unordered_map<std::string, std::unique_ptr<ENGINE, decltype(&ENGINE_free)>>> s_engines;
#endif
#endif
void unregisterOpenSSLUser()
{
if (s_users.fetch_sub(1) == 1) {
-#if OPENSSL_VERSION_MAJOR < 3 || !defined(HAVE_TLS_PROVIDERS)
-#ifndef OPENSSL_NO_ENGINE
+#if defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
for (auto& [name, engine] : *s_engines.lock()) {
ENGINE_finish(engine.get());
engine.reset();
}
s_engines.lock()->clear();
-#endif
-#endif
+#endif /* PDNS_ENABLE_LIBSSL_ENGINE */
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x2090100fL))
ERR_free_strings();
}
#endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */
-#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
+#if defined(HAVE_LIBSSL) && !HAVE_TLS_PROVIDERS
std::pair<bool, std::string> libssl_load_engine([[maybe_unused]] const std::string& engineName, [[maybe_unused]] const std::optional<std::string>& defaultString)
{
-#ifdef OPENSSL_NO_ENGINE
+#if defined(OPENSSL_NO_ENGINE)
return { false, "OpenSSL has been built without engine support" };
-#else
+#elif !defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
+ return { false, "SSL engine support not enabled" };
+#else /* DNSDIST_ENABLE_LIBSSL_ENGINE */
if (s_users.load() == 0) {
/* We need to make sure that OpenSSL has been properly initialized before loading an engine.
This messes up our accounting a bit, so some memory might not be properly released when
engines->insert({engineName, std::move(engine)});
return { true, "" };
-#endif
+#endif /* DNSDIST_ENABLE_LIBSSL_ENGINE */
}
#endif /* HAVE_LIBSSL && !HAVE_TLS_PROVIDERS */
void OpenSSLTLSTicketKeysRing::addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey)
{
d_ticketKeys.write_lock()->push_front(std::move(newKey));
+ if (TLSCtx::hasTicketsKeyAddedHook()) {
+ auto key = d_ticketKeys.read_lock()->front();
+ auto keyContent = key->content();
+ TLSCtx::getTicketsKeyAddedHook()(keyContent);
+ // fills mem with 0's
+ OPENSSL_cleanse(keyContent.data(), keyContent.size());
+ }
}
std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getEncryptionKey()
return (memcmp(d_name, name, sizeof(d_name)) == 0);
}
+std::string OpenSSLTLSTicketKey::content() const
+{
+ std::string result{};
+ result.reserve(TLS_TICKETS_KEY_NAME_SIZE + TLS_TICKETS_CIPHER_KEY_SIZE + TLS_TICKETS_MAC_KEY_SIZE);
+ // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
+ result.append(reinterpret_cast<const char*>(d_name), TLS_TICKETS_KEY_NAME_SIZE);
+ result.append(reinterpret_cast<const char*>(d_cipherKey), TLS_TICKETS_CIPHER_KEY_SIZE);
+ result.append(reinterpret_cast<const char*>(d_hmacKey), TLS_TICKETS_MAC_KEY_SIZE);
+ // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
+
+ return result;
+}
+
#if OPENSSL_VERSION_MAJOR >= 3
static const std::string sha256KeyName{"sha256"};
#endif
#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
}
-/* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
-#ifndef DISABLE_NPN
-void libssl_set_npn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg)
-{
-#ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB
- SSL_CTX_set_next_proto_select_cb(ctx, cb, arg);
-#endif
-}
-#endif /* DISABLE_NPN */
-
+/* called in a client context, if the client advertised more than one ALPN value and the server returned more than one as well, to select the one to use. */
void libssl_set_alpn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg)
{
#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
bool decrypt(const unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx) const;
#endif
+ [[nodiscard]] std::string content() const;
+
private:
unsigned char d_name[TLS_TICKETS_KEY_NAME_SIZE];
unsigned char d_cipherKey[TLS_TICKETS_CIPHER_KEY_SIZE];
private:
void addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey);
-
SharedLockGuarded<boost::circular_buffer<std::shared_ptr<OpenSSLTLSTicketKey> > > d_ticketKeys;
};
pdns::UniqueFilePtr libssl_set_key_log_file(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx, const std::string& logFile);
-/* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
-#ifndef DISABLE_NPN
-void libssl_set_npn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg);
-#endif /* DISABLE_NPN */
-
/* called in a server context, to select an ALPN value advertised by the client if any */
void libssl_set_alpn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg);
/* set the supported ALPN protos in client context */
{
public:
ReadWriteLock() = default;
+ ~ReadWriteLock() = default;
ReadWriteLock(const ReadWriteLock& rhs) = delete;
ReadWriteLock(ReadWriteLock&& rhs) = delete;
+ ReadWriteLock& operator=(ReadWriteLock&&) = delete;
ReadWriteLock& operator=(const ReadWriteLock& rhs) = delete;
std::shared_mutex& getLock()
class ReadLock
{
public:
- ReadLock(ReadWriteLock& lock): ReadLock(lock.getLock())
+ ReadLock(ReadWriteLock& lock) :
+ ReadLock(lock.getLock())
{
}
- ReadLock(ReadWriteLock* lock): ReadLock(lock->getLock())
+ ReadLock(ReadWriteLock* lock) :
+ ReadLock(lock->getLock())
{
}
+ ~ReadLock() = default;
ReadLock(const ReadLock& rhs) = delete;
ReadLock& operator=(const ReadLock& rhs) = delete;
+ ReadLock& operator=(ReadLock&&) = delete;
+
ReadLock(ReadLock&& rhs) noexcept :
d_lock(std::move(rhs.d_lock))
{
}
private:
- ReadLock(std::shared_mutex& lock) : d_lock(lock)
+ ReadLock(std::shared_mutex& lock) :
+ d_lock(lock)
{
}
class WriteLock
{
public:
- WriteLock(ReadWriteLock& lock): WriteLock(lock.getLock())
+ WriteLock(ReadWriteLock& lock) :
+ WriteLock(lock.getLock())
{
}
- WriteLock(ReadWriteLock* lock): WriteLock(lock->getLock())
+ WriteLock(ReadWriteLock* lock) :
+ WriteLock(lock->getLock())
{
}
+ ~WriteLock() = default;
WriteLock(const WriteLock& rhs) = delete;
WriteLock& operator=(const WriteLock& rhs) = delete;
+ WriteLock& operator=(WriteLock&&) = delete;
+
WriteLock(WriteLock&& rhs) noexcept :
d_lock(std::move(rhs.d_lock))
{
}
private:
- WriteLock(std::shared_mutex& lock) : d_lock(lock)
+ WriteLock(std::shared_mutex& lock) :
+ d_lock(lock)
{
}
class TryReadLock
{
public:
- TryReadLock(ReadWriteLock& lock): TryReadLock(lock.getLock())
+ TryReadLock(ReadWriteLock& lock) :
+ TryReadLock(lock.getLock())
{
}
- TryReadLock(ReadWriteLock* lock): TryReadLock(lock->getLock())
+ TryReadLock(ReadWriteLock* lock) :
+ TryReadLock(lock->getLock())
{
}
+ ~TryReadLock() = default;
TryReadLock(const TryReadLock& rhs) = delete;
+ TryReadLock(TryReadLock&&) = delete;
TryReadLock& operator=(const TryReadLock& rhs) = delete;
+ TryReadLock& operator=(TryReadLock&&) = delete;
- bool gotIt() const
+ [[nodiscard]] bool gotIt() const
{
return d_lock.owns_lock();
}
private:
- TryReadLock(std::shared_mutex& lock) : d_lock(lock, std::try_to_lock)
+ TryReadLock(std::shared_mutex& lock) :
+ d_lock(lock, std::try_to_lock)
{
}
class TryWriteLock
{
public:
- TryWriteLock(ReadWriteLock& lock): TryWriteLock(lock.getLock())
+ TryWriteLock(ReadWriteLock& lock) :
+ TryWriteLock(lock.getLock())
{
}
- TryWriteLock(ReadWriteLock* lock): TryWriteLock(lock->getLock())
+ TryWriteLock(ReadWriteLock* lock) :
+ TryWriteLock(lock->getLock())
{
}
+ ~TryWriteLock() = default;
TryWriteLock(const TryWriteLock& rhs) = delete;
+ TryWriteLock(TryWriteLock&&) = delete;
TryWriteLock& operator=(const TryWriteLock& rhs) = delete;
+ TryWriteLock& operator=(TryWriteLock&&) = delete;
- bool gotIt() const
+ [[nodiscard]] bool gotIt() const
{
return d_lock.owns_lock();
}
private:
- TryWriteLock(std::shared_mutex& lock) : d_lock(lock, std::try_to_lock)
+ TryWriteLock(std::shared_mutex& lock) :
+ d_lock(lock, std::try_to_lock)
{
}
class LockGuardedHolder
{
public:
- explicit LockGuardedHolder(T& value, std::mutex& mutex): d_lock(mutex), d_value(value)
+ explicit LockGuardedHolder(T& value, std::mutex& mutex) :
+ d_lock(mutex), d_value(value)
{
}
- T& operator*() const noexcept {
+ T& operator*() const noexcept
+ {
return d_value;
}
- T* operator->() const noexcept {
+ T* operator->() const noexcept
+ {
return &d_value;
}
class LockGuardedTryHolder
{
public:
- explicit LockGuardedTryHolder(T& value, std::mutex& mutex): d_lock(mutex, std::try_to_lock), d_value(value)
+ explicit LockGuardedTryHolder(T& value, std::mutex& mutex) :
+ d_lock(mutex, std::try_to_lock), d_value(value)
{
}
- T& operator*() const {
+ T& operator*() const
+ {
if (!owns_lock()) {
throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
}
return d_value;
}
- T* operator->() const {
+ T* operator->() const
+ {
if (!owns_lock()) {
throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
}
return &d_value;
}
- operator bool() const noexcept {
+ operator bool() const noexcept
+ {
return d_lock.owns_lock();
}
- bool owns_lock() const noexcept {
+ [[nodiscard]] bool owns_lock() const noexcept
+ {
return d_lock.owns_lock();
}
class LockGuarded
{
public:
- explicit LockGuarded(const T& value): d_value(value)
+ explicit LockGuarded(const T& value) :
+ d_value(value)
{
}
- explicit LockGuarded(T&& value): d_value(std::move(value))
+ explicit LockGuarded(T&& value) :
+ d_value(std::move(value))
{
}
T d_value;
};
+template <typename T>
+class RecursiveLockGuardedHolder
+{
+public:
+ explicit RecursiveLockGuardedHolder(T& value, std::recursive_mutex& mutex) :
+ d_lock(mutex), d_value(value)
+ {
+ }
+
+ T& operator*() const noexcept
+ {
+ return d_value;
+ }
+
+ T* operator->() const noexcept
+ {
+ return &d_value;
+ }
+
+private:
+ std::lock_guard<std::recursive_mutex> d_lock;
+ T& d_value;
+};
+
+template <typename T>
+class RecursiveLockGuardedTryHolder
+{
+public:
+ explicit RecursiveLockGuardedTryHolder(T& value, std::recursive_mutex& mutex) :
+ d_lock(mutex, std::try_to_lock), d_value(value)
+ {
+ }
+
+ T& operator*() const
+ {
+ if (!owns_lock()) {
+ throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
+ }
+ return d_value;
+ }
+
+ T* operator->() const
+ {
+ if (!owns_lock()) {
+ throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
+ }
+ return &d_value;
+ }
+
+ operator bool() const noexcept
+ {
+ return d_lock.owns_lock();
+ }
+
+ [[nodiscard]] bool owns_lock() const noexcept
+ {
+ return d_lock.owns_lock();
+ }
+
+ void lock()
+ {
+ d_lock.lock();
+ }
+
+private:
+ std::unique_lock<std::recursive_mutex> d_lock;
+ T& d_value;
+};
+
+template <typename T>
+class RecursiveLockGuarded
+{
+public:
+ explicit RecursiveLockGuarded(const T& value) :
+ d_value(value)
+ {
+ }
+
+ explicit RecursiveLockGuarded(T&& value) :
+ d_value(std::move(value))
+ {
+ }
+
+ explicit RecursiveLockGuarded() = default;
+
+ RecursiveLockGuardedTryHolder<T> try_lock()
+ {
+ return RecursiveLockGuardedTryHolder<T>(d_value, d_mutex);
+ }
+
+ RecursiveLockGuardedHolder<T> lock()
+ {
+ return RecursiveLockGuardedHolder<T>(d_value, d_mutex);
+ }
+
+ RecursiveLockGuardedHolder<const T> read_only_lock()
+ {
+ return RecursiveLockGuardedHolder<const T>(d_value, d_mutex);
+ }
+
+private:
+ std::recursive_mutex d_mutex;
+ T d_value;
+};
+
template <typename T>
class SharedLockGuardedHolder
{
public:
- explicit SharedLockGuardedHolder(T& value, std::shared_mutex& mutex): d_lock(mutex), d_value(value)
+ explicit SharedLockGuardedHolder(T& value, std::shared_mutex& mutex) :
+ d_lock(mutex), d_value(value)
{
}
- T& operator*() const noexcept {
+ T& operator*() const noexcept
+ {
return d_value;
}
- T* operator->() const noexcept {
+ T* operator->() const noexcept
+ {
return &d_value;
}
class SharedLockGuardedTryHolder
{
public:
- explicit SharedLockGuardedTryHolder(T& value, std::shared_mutex& mutex): d_lock(mutex, std::try_to_lock), d_value(value)
+ explicit SharedLockGuardedTryHolder(T& value, std::shared_mutex& mutex) :
+ d_lock(mutex, std::try_to_lock), d_value(value)
{
}
- T& operator*() const {
+ T& operator*() const
+ {
if (!owns_lock()) {
throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
}
return d_value;
}
- T* operator->() const {
+ T* operator->() const
+ {
if (!owns_lock()) {
throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
}
return &d_value;
}
- operator bool() const noexcept {
+ operator bool() const noexcept
+ {
return d_lock.owns_lock();
}
- bool owns_lock() const noexcept {
+ [[nodiscard]] bool owns_lock() const noexcept
+ {
return d_lock.owns_lock();
}
class SharedLockGuardedNonExclusiveHolder
{
public:
- explicit SharedLockGuardedNonExclusiveHolder(const T& value, std::shared_mutex& mutex): d_lock(mutex), d_value(value)
+ explicit SharedLockGuardedNonExclusiveHolder(const T& value, std::shared_mutex& mutex) :
+ d_lock(mutex), d_value(value)
{
}
- const T& operator*() const noexcept {
+ const T& operator*() const noexcept
+ {
return d_value;
}
- const T* operator->() const noexcept {
+ const T* operator->() const noexcept
+ {
return &d_value;
}
class SharedLockGuardedNonExclusiveTryHolder
{
public:
- explicit SharedLockGuardedNonExclusiveTryHolder(const T& value, std::shared_mutex& mutex): d_lock(mutex, std::try_to_lock), d_value(value)
+ explicit SharedLockGuardedNonExclusiveTryHolder(const T& value, std::shared_mutex& mutex) :
+ d_lock(mutex, std::try_to_lock), d_value(value)
{
}
- const T& operator*() const {
+ const T& operator*() const
+ {
if (!owns_lock()) {
throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
}
return d_value;
}
- const T* operator->() const {
+ const T* operator->() const
+ {
if (!owns_lock()) {
throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
}
return &d_value;
}
- operator bool() const noexcept {
+ operator bool() const noexcept
+ {
return d_lock.owns_lock();
}
- bool owns_lock() const noexcept {
+ [[nodiscard]] bool owns_lock() const noexcept
+ {
return d_lock.owns_lock();
}
class SharedLockGuarded
{
public:
- explicit SharedLockGuarded(const T& value): d_value(value)
+ explicit SharedLockGuarded(const T& value) :
+ d_value(value)
{
}
- explicit SharedLockGuarded(T&& value): d_value(std::move(value))
+ explicit SharedLockGuarded(T&& value) :
+ d_value(std::move(value))
{
}
#include "ueberbackend.hh"
-AuthLua4::AuthLua4() { prepareContext(); }
-
LuaContext* AuthLua4::getLua()
{
return d_lw.get();
d_lw->registerFunction<DNSName(UpdatePolicyQuery::*)()>("getTsigName", [](UpdatePolicyQuery& upq) { return upq.tsigName; });
d_lw->registerFunction<std::string(UpdatePolicyQuery::*)()>("getPeerPrincipal", [](UpdatePolicyQuery& upq) { return upq.peerPrincipal; });
/* end of update policy */
+ if (!d_include_path.empty()) {
+ includePath(d_include_path);
+ }
}
void AuthLua4::postLoad() {
class AuthLua4 : public BaseLua4
{
public:
- AuthLua4();
+ AuthLua4(const std::string& includePath="") : BaseLua4(includePath) {
+ prepareContext();
+ };
bool updatePolicy(const DNSName &qname, const QType& qtype, const DNSName &zonename, const DNSPacket& packet);
bool axfrfilter(const ComboAddress&, const DNSName&, const DNSResourceRecord&, std::vector<DNSResourceRecord>&);
LuaContext* getLua();
+#include "config.h"
#include <cassert>
#include <fstream>
#include <unordered_set>
#include <unordered_map>
#include <typeinfo>
+#include <sys/stat.h>
#include "logger.hh"
#include "logging.hh"
#include "iputils.hh"
#include "ext/luawrapper/include/LuaContext.hpp"
#include "dns_random.hh"
-BaseLua4::BaseLua4() = default;
-
-void BaseLua4::loadFile(const std::string& fname)
+void BaseLua4::loadFile(const std::string& fname, bool doPostLoad)
{
std::ifstream ifs(fname);
if (!ifs) {
auto ret = errno;
auto msg = stringerror(ret);
- SLOG(g_log << Logger::Error << "Unable to read configuration file from '" << fname << "': " << msg << endl,
- g_slog->withName("lua")->error(Logr::Error, ret, "Unable to read configuration file", "file", Logging::Loggable(fname), "msg", Logging::Loggable(msg)));
+ g_log << Logger::Error << "Unable to read configuration file from '" << fname << "': " << msg << endl;
throw std::runtime_error(msg);
}
- loadStream(ifs);
+ loadStream(ifs, doPostLoad);
};
void BaseLua4::loadString(const std::string &script) {
std::istringstream iss(script);
- loadStream(iss);
+ loadStream(iss, true);
+};
+
+void BaseLua4::includePath(const std::string& directory) {
+ std::vector<std::string> vec;
+ const std::string& suffix = "lua";
+ auto directoryError = pdns::visit_directory(directory, [this, &directory, &suffix, &vec]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
+ (void)this;
+ if (boost::starts_with(name, ".")) {
+ return true; // skip any dots
+ }
+ if (boost::ends_with(name, suffix)) {
+ // build name
+ string fullName = directory + "/" + std::string(name);
+ // ensure it's readable file
+ struct stat statInfo
+ {
+ };
+ if (stat(fullName.c_str(), &statInfo) != 0 || !S_ISREG(statInfo.st_mode)) {
+ string msg = fullName + " is not a regular file";
+ g_log << Logger::Error << msg << std::endl;
+ throw PDNSException(msg);
+ }
+ vec.emplace_back(fullName);
+ }
+ return true;
+ });
+
+ if (directoryError) {
+ int err = errno;
+ string msg = directory + " is not accessible: " + stringerror(err);
+ g_log << Logger::Error << msg << std::endl;
+ throw PDNSException(msg);
+ }
+
+ std::sort(vec.begin(), vec.end(), CIStringComparePOSIX());
+
+ for(const auto& file: vec) {
+ loadFile(file, false);
+ }
};
// By default no features
d_lw->writeVariable("pdns", d_pd);
}
-void BaseLua4::loadStream(std::istream &is) {
- d_lw->executeCode(is);
+void BaseLua4::loadStream(std::istream &stream, bool doPostLoad) {
+ d_lw->executeCode(stream);
- postLoad();
+ if (doPostLoad) {
+ postLoad();
+ }
}
BaseLua4::~BaseLua4() = default;
{
protected:
std::unique_ptr<LuaContext> d_lw; // this is way on top because it must get destroyed _last_
+ std::string d_include_path; // path where scripts to include at postLoad are
public:
- BaseLua4();
- void loadFile(const std::string& fname);
- void loadString(const std::string& script);
- void loadStream(std::istream& is);
+ BaseLua4(const std::string &includePath) : d_include_path(includePath) {};
+ void loadFile(const std::string &fname, bool doPostLoad=true);
+ void loadString(const std::string &script);
+ void loadStream(std::istream &stream, bool doPostLoad=true);
+ void includePath(const std::string &directory);
virtual ~BaseLua4(); // this is so unique_ptr works with an incomplete type
protected:
void prepareContext();
private:
void checkURL(const CheckDesc& cd, const bool status, const bool first = false)
{
+ setThreadName("pdns/lua-c-url");
+
string remstring;
try {
int timeout = 2;
}
}
void checkTCP(const CheckDesc& cd, const bool status, const bool first = false) {
+ setThreadName("pdns/lua-c-tcp");
try {
int timeout = 2;
if (cd.opts.count("timeout")) {
}
void checkThread()
{
+ setThreadName("pdns/luaupcheck");
while (true)
{
std::chrono::system_clock::time_point checkStart = std::chrono::system_clock::now();
statuses->erase(it);
}
}
+
+ // set thread name again, in case std::async surprised us by doing work in this thread
+ setThreadName("pdns/luaupcheck");
+
std::this_thread::sleep_until(checkStart + std::chrono::seconds(g_luaHealthChecksInterval));
}
}
{
if(!LUA || // we don't have a Lua state yet
!g_LuaRecordSharedState) { // or we want a new one even if we had one
- LUA = make_unique<AuthLua4>();
+ LUA = make_unique<AuthLua4>(::arg()["lua-global-include-dir"]);
setupLuaRecords(*LUA->getLua());
}
return count;
}
-size_t readn2(int fd, void* buffer, size_t len)
+size_t readn2(int fileDesc, void* buffer, size_t len)
{
- size_t pos=0;
- ssize_t res;
- for(;;) {
- res = read(fd, (char*)buffer + pos, len - pos);
- if(res == 0)
+ size_t pos = 0;
+
+ for (;;) {
+ auto res = read(fileDesc, static_cast<char *>(buffer) + pos, len - pos); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic): it's the API
+ if (res == 0) {
throw runtime_error("EOF while reading message");
- if(res < 0) {
- if (errno == EAGAIN)
+ }
+ if (res < 0) {
+ if (errno == EAGAIN) {
throw std::runtime_error("used readn2 on non-blocking socket, got EAGAIN");
- else
- unixDie("failed in readn2");
+ }
+ unixDie("failed in readn2");
}
- pos+=(size_t)res;
- if(pos == len)
+ pos += static_cast<size_t>(res);
+ if (pos == len) {
break;
+ }
}
return len;
}
}
}
#endif
- return std::runtime_error(fullErrorMessage);
+ return std::runtime_error{fullErrorMessage};
}
auto pdns::OpenSSL::error(const std::string& componentName, const std::string& errorMessage) -> std::runtime_error
class DNSName;
// Do not change to "using TSIGHashEnum ..." until you know CodeQL does not choke on it
-typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum;
+typedef enum
+{
+ TSIG_MD5,
+ TSIG_SHA1,
+ TSIG_SHA224,
+ TSIG_SHA256,
+ TSIG_SHA384,
+ TSIG_SHA512,
+ TSIG_GSS,
+} TSIGHashEnum;
+
namespace pdns
{
/**
size_t writen2(int fd, const void *buf, size_t count);
inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
-size_t readn2(int fd, void* buffer, size_t len);
+size_t readn2(int fileDesc, void* buffer, size_t len);
size_t readn2WithTimeout(int fd, void* buffer, size_t len, const struct timeval& idleTimeout, const struct timeval& totalTimeout={0,0}, bool allowIncomplete=false);
size_t writen2WithTimeout(int fd, const void * buffer, size_t len, const struct timeval& timeout);
return now.tv_sec+now.tv_usec/1000000.0;
}
-inline void unixDie(const string &why)
+[[noreturn]] inline void unixDie(const string &why)
{
- throw runtime_error(why+": "+stringerror());
+ throw runtime_error(why + ": " + stringerror(errno));
}
string makeHexDump(const string& str);
string nsec3salt;
int nsec3iters = 0;
for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
- if(i->first.d_type == QType::NSEC3)
+ if(i->d_type == QType::NSEC3)
{
// cerr<<"got nsec3 ["<<i->first.d_name<<"]"<<endl;
// cerr<<i->first.d_content->getZoneRepresentation()<<endl;
- const auto r = getRR<NSEC3RecordContent>(i->first);
- if (!r) {
+ const auto nsec3Record = getRR<NSEC3RecordContent>(*i);
+ if (!nsec3Record) {
continue;
}
// nsec3.insert(new nsec3()
// cerr<<toBase32Hex(r.d_nexthash)<<endl;
- nsec3s.emplace(toLower(i->first.d_name.getRawLabel(0)), toBase32Hex(r->d_nexthash));
- nsec3salt = r->d_salt;
- nsec3iters = r->d_iterations;
- nsec3t.emplace(toLower(i->first.d_name.getRawLabel(0)), r->numberOfTypesSet());
+ nsec3s.emplace(toLower(i->d_name.getRawLabel(0)), toBase32Hex(nsec3Record->d_nexthash));
+ nsec3salt = nsec3Record->d_salt;
+ nsec3iters = nsec3Record->d_iterations;
+ nsec3t.emplace(toLower(i->d_name.getRawLabel(0)), nsec3Record->numberOfTypesSet());
}
else
{
- // cerr<<"namesseen.insert('"<<i->first.d_name<<"')"<<endl;
- names.insert(i->first.d_name);
- namesseen.insert(i->first.d_name);
+ // cerr<<"namesseen.insert('"<<i->d_name<<"')"<<endl;
+ names.insert(i->d_name);
+ namesseen.insert(i->d_name);
}
- if(i->first.d_type == QType::CNAME)
+ if(i->d_type == QType::CNAME)
{
- namesseen.insert(DNSName(i->first.getContent()->getZoneRepresentation()));
+ namesseen.insert(DNSName(i->getContent()->getZoneRepresentation()));
}
- cout << i->first.d_place - 1 << "\t" << i->first.d_name.toString() << "\t" << i->first.d_ttl << "\tIN\t" << DNSRecordContent::NumberToType(i->first.d_type);
- cout << "\t" << i->first.getContent()->getZoneRepresentation() << "\n";
+ cout << i->d_place - 1 << "\t" << i->d_name.toString() << "\t" << i->d_ttl << "\tIN\t" << DNSRecordContent::NumberToType(i->d_type);
+ cout << "\t" << i->getContent()->getZoneRepresentation() << "\n";
}
#if 0
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
+#include "config.h"
#include "misc.hh"
#include <memory>
#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <optional>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
#include <openssl/obj_mac.h>
#ifdef HAVE_LIBCRYPTO_ECDSA
#include <openssl/ecdsa.h>
d_doExpandALIAS = ::arg().mustDo("expand-alias");
d_logDNSDetails= ::arg().mustDo("log-dns-details");
string fname= ::arg()["lua-prequery-script"];
+
if(fname.empty())
{
d_pdl = nullptr;
}
else
{
- d_pdl = std::make_unique<AuthLua4>();
- d_pdl->loadFile(fname); // XXX exception handling?
+ d_pdl = std::make_unique<AuthLua4>(::arg()["lua-global-include-dir"]);
+ d_pdl->loadFile(fname);
}
fname = ::arg()["lua-dnsupdate-policy-script"];
if (fname.empty())
}
else
{
- d_update_policy_lua = std::make_unique<AuthLua4>();
try {
+ d_update_policy_lua = std::make_unique<AuthLua4>();
d_update_policy_lua->loadFile(fname);
}
- catch (const std::runtime_error&) {
+ catch (const std::runtime_error& e) {
+ g_log<<Logger::Warning<<"Failed to load update policy - disabling: "<<e.what()<<endl;
d_update_policy_lua = nullptr;
}
}
}
}
catch (std::exception &e) {
- while (B.get(rr)) ; // don't leave DB handle in bad state
+ B.lookupEnd(); // don't leave DB handle in bad state
throw;
}
B.lookup(QType(QType::ANY), subdomain, d_sd.domain_id, &p);
if (B.get(rr)) {
DLOG(g_log<<"No wildcard match, ancestor exists"<<endl);
- while (B.get(rr)) ;
+ B.lookupEnd();
break;
}
wildcard=subdomain;
break;
}
default:
- while (B.get(rr)) ; // don't leave DB handle in bad state
+ B.lookupEnd(); // don't leave DB handle in bad state
throw PDNSException("Unknown type (" + QType(qtype).toString() + ") for additional service processing");
}
}
}
catch(std::exception &e) {
- while (B.get(rr)) ; // don't leave DB handle in bad state
+ B.lookupEnd(); // don't leave DB handle in bad state
r=p.replyPacket();
r->setRcode(RCode::ServFail);
}
}
if(doSigs)
- addRRSigs(d_dk, B, authSet, r->getRRS());
+ addRRSigs(d_dk, B, authSet, r->getRRS(), &p);
if(PC.enabled() && !noCache && p.couldBeCached())
PC.insert(p, *r, r->getMinTTL()); // in the packet cache
+#include "dnsname.hh"
+#include "dnsparser.hh"
#include "dnsrecords.hh"
+#include "qtype.hh"
#include <boost/smart_ptr/make_shared_array.hpp>
#ifdef HAVE_CONFIG_H
#include "config.h"
if(rr.qtype.getCode() == QType::A || rr.qtype.getCode() == QType::AAAA) {
addresses.insert(rr.qname);
}
+#ifdef HAVE_LUA_RECORDS
if(rr.qtype.getCode() == QType::LUA) {
shared_ptr<DNSRecordContent> drc(DNSRecordContent::make(rr.qtype.getCode(), QClass::IN, rr.content));
auto luarec = std::dynamic_pointer_cast<LUARecordContent>(drc);
addresses.insert(rr.qname);
}
}
+#endif
if(rr.qtype.getCode() == QType::A) {
arecords.insert(rr.qname);
}
sd.db->startTransaction(zone, -1);
- if (!sd.db->replaceRRSet(sd.domain_id, zone, rr.qtype, {rr})) {
- sd.db->abortTransaction();
- cerr<<"Backend did not replace SOA record. Backend might not support this operation."<<endl;
- return -1;
+ auto rrs = vector<DNSResourceRecord>{rr};
+ if (!sd.db->replaceRRSet(sd.domain_id, zone, rr.qtype, rrs)) {
+ sd.db->abortTransaction();
+ cerr << "Backend did not replace SOA record. Backend might not support this operation." << endl;
+ return -1;
}
if (sd.db->doesDNSSEC()) {
cout << "]" << endl;
cout << " Add a ZSK or KSK to zone and specify algo&bits" << endl;
cout << "backend-cmd BACKEND CMD [CMD..] Perform one or more backend commands" << endl;
+ cout << "backend-lookup BACKEND NAME [[TYPE] CLIENT-IP-SUBNET]" << endl;
+ cout << " Perform a backend lookup of NAME, TYPE and CLIENT-IP-SUBNET" << endl;
cout << "b2b-migrate OLD NEW Move all data from one backend to another" << endl;
cout << "bench-db [filename] Bench database backend with queries, one zone per line" << endl;
cout << "check-zone ZONE Check a zone for correctness" << endl;
return 0;
}
+ else if (cmds.at(0) == "backend-lookup") {
+ if (cmds.size() < 3) {
+ cerr << "Usage: backend-lookup BACKEND NAME [TYPE [CLIENT-IP-SUBNET]]" << endl;
+ return 1;
+ }
+
+ std::unique_ptr<DNSBackend> matchingBackend{nullptr};
+
+ for (auto& backend : BackendMakers().all()) {
+ if (backend->getPrefix() == cmds.at(1)) {
+ matchingBackend = std::move(backend);
+ }
+ }
+
+ if (matchingBackend == nullptr) {
+ cerr << "Unknown backend '" << cmds.at(1) << "'" << endl;
+ return 1;
+ }
+
+ QType type = QType::ANY;
+ if (cmds.size() > 3) {
+ type = DNSRecordContent::TypeToNumber(cmds.at(3));
+ }
+
+ DNSName name{cmds.at(2)};
+
+ DNSPacket queryPacket(true);
+ Netmask clientNetmask;
+ if (cmds.size() > 4) {
+ clientNetmask = cmds.at(4);
+ queryPacket.setRealRemote(clientNetmask);
+ }
+
+ matchingBackend->lookup(type, name, -1, &queryPacket);
+
+ bool found = false;
+ DNSZoneRecord resultZoneRecord;
+ while (matchingBackend->get(resultZoneRecord)) {
+ cout << resultZoneRecord.dr.d_name.toString() << "\t" << std::to_string(resultZoneRecord.dr.d_ttl) << "\t" << QClass(resultZoneRecord.dr.d_class).toString() << "\t" << DNSRecordContent::NumberToType(resultZoneRecord.dr.d_type, resultZoneRecord.dr.d_class) << "\t" << resultZoneRecord.dr.getContent()->getZoneRepresentation();
+ if (resultZoneRecord.scopeMask > 0) {
+ clientNetmask.setBits(resultZoneRecord.scopeMask);
+ cout << "\t" << "; " << clientNetmask.toString();
+ }
+ cout << endl;
+ found = true;
+ }
+ if (!found) {
+ cerr << "Backend found 0 zone record results";
+ if (type != QType::ANY) {
+ cerr << "- maybe retry with type ANY?";
+ }
+ cerr << endl;
+ return 1;
+ }
+
+ return 0;
+ }
else {
cerr << "Unknown command '" << cmds.at(0) << "'" << endl;
return 1;
}
return 0;
}
-catch(PDNSException& ae) {
- cerr<<"Error: "<<ae.reason<<endl;
+catch (PDNSException& ae) {
+ cerr << "Error: " << ae.reason << endl;
return 1;
}
-catch(std::exception& e) {
- cerr<<"Error: "<<e.what()<<endl;
+catch (std::exception& e) {
+ cerr << "Error: " << e.what() << endl;
return 1;
}
-catch(...)
-{
- cerr<<"Caught an unknown exception"<<endl;
+catch (...) {
+ cerr << "Caught an unknown exception" << endl;
return 1;
}
#ifndef DISABLE_PROTOBUF
#include "dnsparser.hh"
-void pdns::ProtoZero::Message::encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& ca)
+void pdns::ProtoZero::Message::encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& address)
{
- if (ca.sin4.sin_family == AF_INET) {
- d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin4.sin_addr.s_addr), sizeof(ca.sin4.sin_addr.s_addr));
+ if (address.sin4.sin_family == AF_INET) {
+ d_message.add_bytes(type, reinterpret_cast<const char*>(&address.sin4.sin_addr.s_addr), sizeof(address.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
}
- else if (ca.sin4.sin_family == AF_INET6) {
- d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin6.sin6_addr.s6_addr), sizeof(ca.sin6.sin6_addr.s6_addr));
+ else if (address.sin4.sin_family == AF_INET6) {
+ d_message.add_bytes(type, reinterpret_cast<const char*>(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr.s6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
}
}
void pdns::ProtoZero::Message::encodeNetmask(const protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask)
{
if (!subnet.empty()) {
- ComboAddress ca(subnet.getNetwork());
- ca.truncate(mask);
- if (ca.sin4.sin_family == AF_INET) {
- d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin4.sin_addr.s_addr), sizeof(ca.sin4.sin_addr.s_addr));
+ ComboAddress address(subnet.getNetwork());
+ address.truncate(mask);
+ if (address.sin4.sin_family == AF_INET) {
+ d_message.add_bytes(type, reinterpret_cast<const char*>(&address.sin4.sin_addr.s_addr), sizeof(address.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
}
- else if (ca.sin4.sin_family == AF_INET6) {
- d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin6.sin6_addr.s6_addr), sizeof(ca.sin6.sin6_addr.s6_addr));
+ else if (address.sin4.sin_family == AF_INET6) {
+ d_message.add_bytes(type, reinterpret_cast<const char*>(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr.s6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
}
}
}
// leaving the block will cause the sub writer to compute how much was written based on the new size and update the size accordingly
}
-void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, pdns::ProtoZero::Message::TransportProtocol proto, size_t len)
+void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t qid, pdns::ProtoZero::Message::TransportProtocol proto, size_t len)
{
setMessageIdentity(uniqueId);
setSocketFamily(requestor.sin4.sin_family);
setTo(local);
setInBytes(len);
setTime();
- setId(id);
+ setId(qid);
setQuestion(qname, qtype, qclass);
setFromPort(requestor.getPort());
setToPort(local.getPort());
return;
}
- const dnsheader_aligned dh(packet);
+ const dnsheader_aligned header(packet);
- if (ntohs(dh->ancount) == 0) {
+ if (ntohs(header->ancount) == 0) {
return;
}
- if (ntohs(dh->qdcount) == 0) {
+ if (ntohs(header->qdcount) == 0) {
return;
}
- PacketReader pr(std::string_view(packet, len));
+ PacketReader packetReader(std::string_view(packet, len));
size_t idx = 0;
DNSName rrname;
- uint16_t qdcount = ntohs(dh->qdcount);
- uint16_t ancount = ntohs(dh->ancount);
- uint16_t rrtype;
- uint16_t rrclass;
+ uint16_t qdcount = ntohs(header->qdcount);
+ uint16_t ancount = ntohs(header->ancount);
+ uint16_t rrtype{};
+ uint16_t rrclass{};
string blob;
- struct dnsrecordheader ah;
+ dnsrecordheader recordHeader{};
- rrname = pr.getName();
- rrtype = pr.get16BitInt();
- rrclass = pr.get16BitInt();
- (void) rrtype;
- (void) rrclass;
+ rrname = packetReader.getName();
+ rrtype = packetReader.get16BitInt();
+ rrclass = packetReader.get16BitInt();
+ (void)rrtype;
+ (void)rrclass;
/* consume remaining qd if any */
if (qdcount > 1) {
- for(idx = 1; idx < qdcount; idx++) {
- rrname = pr.getName();
- rrtype = pr.get16BitInt();
- rrclass = pr.get16BitInt();
- (void) rrtype;
- (void) rrclass;
+ for (idx = 1; idx < qdcount; idx++) {
+ rrname = packetReader.getName();
+ rrtype = packetReader.get16BitInt();
+ rrclass = packetReader.get16BitInt();
+ (void)rrtype;
+ (void)rrclass;
}
}
/* parse AN */
for (idx = 0; idx < ancount; idx++) {
- rrname = pr.getName();
- pr.getDnsrecordheader(ah);
+ rrname = packetReader.getName();
+ packetReader.getDnsrecordheader(recordHeader);
- if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
- pr.xfrBlob(blob);
+ if (recordHeader.d_type == QType::A || recordHeader.d_type == QType::AAAA) {
+ packetReader.xfrBlob(blob);
- addRR(rrname, ah.d_type, ah.d_class, ah.d_ttl, blob);
-
- } else if (ah.d_type == QType::CNAME && includeCNAME) {
+ addRR(rrname, recordHeader.d_type, recordHeader.d_class, recordHeader.d_ttl, blob);
+ }
+ else if (recordHeader.d_type == QType::CNAME && includeCNAME) {
protozero::pbf_writer pbf_rr{d_response, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::ResponseField::rrs)};
encodeDNSName(pbf_rr, d_buffer, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::name), rrname);
- pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::type), ah.d_type);
- pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::class_), ah.d_class);
- pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::ttl), ah.d_ttl);
+ pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::type), recordHeader.d_type);
+ pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::class_), recordHeader.d_class);
+ pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::ttl), recordHeader.d_ttl);
DNSName target;
- pr.xfrName(target, true);
+ packetReader.xfrName(target, true);
encodeDNSName(pbf_rr, d_buffer, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::rdata), target);
}
else {
- pr.xfrBlob(blob);
+ packetReader.xfrBlob(blob);
}
}
}
#include <protozero/pbf_writer.hpp>
-namespace pdns {
- namespace ProtoZero {
- class Message {
- public:
-
- enum class MetaValueField : protozero::pbf_tag_type { stringVal = 1, intVal = 2 };
- enum class HTTPVersion : protozero::pbf_tag_type { HTTP1 = 1, HTTP2 = 2, HTTP3 = 3 };
- enum class MetaField : protozero::pbf_tag_type { key = 1, value = 2 };
- enum class Event : protozero::pbf_tag_type { ts = 1, event = 2, start = 3, boolVal = 4, intVal = 5, stringVal = 6, bytesVal = 7, custom = 8 };
- enum class MessageType : int32_t { DNSQueryType = 1, DNSResponseType = 2, DNSOutgoingQueryType = 3, DNSIncomingResponseType = 4 };
- enum class Field : protozero::pbf_tag_type { type = 1, messageId = 2, serverIdentity = 3, socketFamily = 4, socketProtocol = 5, from = 6, to = 7, inBytes = 8, timeSec = 9, timeUsec = 10, id = 11, question = 12, response = 13, originalRequestorSubnet = 14, requestorId = 15, initialRequestId = 16, deviceId = 17, newlyObservedDomain = 18, deviceName = 19, fromPort = 20, toPort = 21, meta = 22, trace = 23, httpVersion = 24 };
- enum class QuestionField : protozero::pbf_tag_type { qName = 1, qType = 2, qClass = 3 };
- enum class ResponseField : protozero::pbf_tag_type { rcode = 1, rrs = 2, appliedPolicy = 3, tags = 4, queryTimeSec = 5, queryTimeUsec = 6, appliedPolicyType = 7, appliedPolicyTrigger = 8, appliedPolicyHit = 9, appliedPolicyKind = 10, validationState = 11 };
- enum class RRField : protozero::pbf_tag_type { name = 1, type = 2, class_ = 3, ttl = 4, rdata = 5, udr = 6 };
- enum class TransportProtocol : protozero::pbf_tag_type { UDP = 1, TCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6, DoQ = 7 };
-
- Message(std::string& buffer): d_buffer(buffer), d_message{d_buffer}
- {
- }
-
- Message(const Message&) = delete;
- Message(Message&&) = delete;
- Message& operator=(const Message&) = delete;
- Message& operator=(Message&&) = delete;
-
- void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, TransportProtocol proto, size_t len);
- void setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass);
-
- void setType(MessageType mtype)
- {
- add_enum(d_message, Field::type, static_cast<int32_t>(mtype));
- }
-
- void setHTTPVersion(HTTPVersion version)
- {
- add_enum(d_message, Field::httpVersion, static_cast<int32_t>(version));
- }
-
- void setMessageIdentity(const boost::uuids::uuid& uniqueId)
- {
- add_bytes(d_message, Field::messageId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
- }
-
- void setServerIdentity(const std::string& serverIdentity)
- {
- add_bytes(d_message, Field::serverIdentity, serverIdentity.data(), serverIdentity.length());
- }
-
- void setSocketFamily(int family)
- {
- add_enum(d_message, Field::socketFamily, family == AF_INET ? 1 : 2);
- }
-
- void setSocketProtocol(TransportProtocol proto)
- {
- add_enum(d_message, Field::socketProtocol, static_cast<int32_t>(proto));
- }
-
- void setFrom(const ComboAddress& ca)
- {
- encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::from), ca);
- }
-
- void setTo(const ComboAddress& ca)
- {
- encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::to), ca);
- }
-
- void setInBytes(uint64_t len)
- {
- add_uint64(d_message, Field::inBytes, len);
- }
-
- void setTime()
- {
- struct timespec ts;
- gettime(&ts, true);
-
- setTime(ts.tv_sec, ts.tv_nsec / 1000);
- }
-
- void setTime(time_t sec, uint32_t usec)
- {
- // coverity[store_truncates_time_t]
- add_uint32(d_message, Field::timeSec, sec);
- add_uint32(d_message, Field::timeUsec, usec);
- }
-
- void setId(uint16_t id)
- {
- add_uint32(d_message, Field::id, ntohs(id));
- }
-
- void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
- {
- protozero::pbf_writer pbf_question{d_message, static_cast<protozero::pbf_tag_type>(Field::question)};
- encodeDNSName(pbf_question, d_buffer, static_cast<protozero::pbf_tag_type>(QuestionField::qName), qname);
- pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qType), qtype);
- pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qClass), qclass);
- }
-
- void setMeta(const std::string& key, const std::unordered_set<std::string>& stringVal, const std::unordered_set<int64_t>& intVal)
- {
- protozero::pbf_writer pbf_meta{d_message, static_cast<protozero::pbf_tag_type>(Field::meta)};
- pbf_meta.add_string(static_cast<protozero::pbf_tag_type>(MetaField::key), key);
- protozero::pbf_writer pbf_meta_value{pbf_meta, static_cast<protozero::pbf_tag_type>(MetaField::value)};
- for (const auto& s: stringVal) {
- pbf_meta_value.add_string(static_cast<protozero::pbf_tag_type>(MetaValueField::stringVal), s);
- }
- for (const auto& i: intVal) {
- pbf_meta_value.add_uint64(static_cast<protozero::pbf_tag_type>(MetaValueField::intVal), i);
- }
- }
-
- void setEDNSSubnet(const Netmask& nm, uint8_t mask)
- {
- encodeNetmask(static_cast<protozero::pbf_tag_type>(Field::originalRequestorSubnet), nm, mask);
- }
-
- void setRequestorId(const std::string& req)
- {
- if (!req.empty()) {
- add_string(d_message, Field::requestorId, req);
- }
- }
-
- void setInitialRequestID(const boost::uuids::uuid& uniqueId)
- {
- add_bytes(d_message, Field::initialRequestId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
- }
-
- void setDeviceId(const std::string& id)
- {
- if (!id.empty()) {
- add_string(d_message, Field::deviceId, id);
- }
- }
-
- void setNewlyObservedDomain(bool nod)
- {
- add_bool(d_message, Field::newlyObservedDomain, nod);
- }
-
- void setDeviceName(const std::string& name)
- {
- if (!name.empty()) {
- add_string(d_message, Field::deviceName, name);
- }
- }
-
- void setFromPort(in_port_t port)
- {
- add_uint32(d_message, Field::fromPort, port);
- }
-
- void setToPort(in_port_t port)
- {
- add_uint32(d_message, Field::toPort, port);
- }
-
- void startResponse()
- {
- d_response = protozero::pbf_writer{d_message, static_cast<protozero::pbf_tag_type>(Field::response)};
- }
-
- void commitResponse()
- {
- d_response.commit();
- }
-
- void setResponseCode(uint8_t rcode)
- {
- d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), rcode);
- }
-
- void setNetworkErrorResponseCode()
- {
- /* special code meaning 'network error', like a timeout */
- d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), 65536);
- }
-
- void setAppliedPolicy(const std::string& policy)
- {
- d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::appliedPolicy), policy);
- }
-
- void addPolicyTags(const std::unordered_set<std::string>& tags)
- {
- for (const auto& tag : tags) {
- addPolicyTag(tag);
- }
- }
-
- void addPolicyTag(const string& tag)
- {
- d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::tags), tag);
- }
-
- void setQueryTime(uint32_t sec, uint32_t usec)
- {
- d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeSec), sec);
- d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeUsec), usec);
- }
-
- void addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME=false);
- void addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob);
-
- protected:
- void encodeComboAddress(protozero::pbf_tag_type type, const ComboAddress& ca);
- void encodeNetmask(protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
- void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, protozero::pbf_tag_type type, const DNSName& name);
-
- static void add_enum(protozero::pbf_writer& writer, Field type, int32_t value)
- {
- writer.add_enum(static_cast<protozero::pbf_tag_type>(type), value);
- }
-
- static void add_bool(protozero::pbf_writer& writer, Field type, bool value)
- {
- writer.add_bool(static_cast<protozero::pbf_tag_type>(type), value);
- }
-
- static void add_uint32(protozero::pbf_writer& writer, Field type, uint32_t value)
- {
- writer.add_uint32(static_cast<protozero::pbf_tag_type>(type), value);
- }
-
- static void add_uint64(protozero::pbf_writer& writer, Field type, uint64_t value)
- {
- writer.add_uint64(static_cast<protozero::pbf_tag_type>(type), value);
- }
-
- static void add_bytes(protozero::pbf_writer& writer, Field type, const char* data, size_t len)
- {
- writer.add_bytes(static_cast<protozero::pbf_tag_type>(type), data, len);
- }
-
- static void add_string(protozero::pbf_writer& writer, Field type, const std::string& str)
- {
- writer.add_string(static_cast<protozero::pbf_tag_type>(type), str);
- }
-
-
- std::string& d_buffer;
- protozero::pbf_writer d_message;
- protozero::pbf_writer d_response;
+namespace pdns
+{
+namespace ProtoZero
+{
+ class Message
+ {
+ public:
+ enum class MetaValueField : protozero::pbf_tag_type
+ {
+ stringVal = 1,
+ intVal = 2
};
+ enum class HTTPVersion : protozero::pbf_tag_type
+ {
+ HTTP1 = 1,
+ HTTP2 = 2,
+ HTTP3 = 3
+ };
+ enum class MetaField : protozero::pbf_tag_type
+ {
+ key = 1,
+ value = 2
+ };
+ enum class Event : protozero::pbf_tag_type
+ {
+ ts = 1,
+ event = 2,
+ start = 3,
+ boolVal = 4,
+ intVal = 5,
+ stringVal = 6,
+ bytesVal = 7,
+ custom = 8
+ };
+ enum class MessageType : int32_t
+ {
+ DNSQueryType = 1,
+ DNSResponseType = 2,
+ DNSOutgoingQueryType = 3,
+ DNSIncomingResponseType = 4
+ };
+ enum class Field : protozero::pbf_tag_type
+ {
+ type = 1,
+ messageId = 2,
+ serverIdentity = 3,
+ socketFamily = 4,
+ socketProtocol = 5,
+ from = 6,
+ to = 7,
+ inBytes = 8,
+ timeSec = 9,
+ timeUsec = 10,
+ id = 11,
+ question = 12,
+ response = 13,
+ originalRequestorSubnet = 14,
+ requestorId = 15,
+ initialRequestId = 16,
+ deviceId = 17,
+ newlyObservedDomain = 18,
+ deviceName = 19,
+ fromPort = 20,
+ toPort = 21,
+ meta = 22,
+ trace = 23,
+ httpVersion = 24,
+ workerId = 25,
+ packetCacheHit = 26,
+ outgoingQueries = 27
+ };
+ enum class QuestionField : protozero::pbf_tag_type
+ {
+ qName = 1,
+ qType = 2,
+ qClass = 3
+ };
+ enum class ResponseField : protozero::pbf_tag_type
+ {
+ rcode = 1,
+ rrs = 2,
+ appliedPolicy = 3,
+ tags = 4,
+ queryTimeSec = 5,
+ queryTimeUsec = 6,
+ appliedPolicyType = 7,
+ appliedPolicyTrigger = 8,
+ appliedPolicyHit = 9,
+ appliedPolicyKind = 10,
+ validationState = 11
+ };
+ enum class RRField : protozero::pbf_tag_type
+ {
+ name = 1,
+ type = 2,
+ class_ = 3,
+ ttl = 4,
+ rdata = 5,
+ udr = 6
+ };
+ enum class TransportProtocol : protozero::pbf_tag_type
+ {
+ UDP = 1,
+ TCP = 2,
+ DoT = 3,
+ DoH = 4,
+ DNSCryptUDP = 5,
+ DNSCryptTCP = 6,
+ DoQ = 7
+ };
+
+ Message(std::string& buffer) :
+ d_buffer(buffer), d_message{d_buffer}
+ {
+ }
+ ~Message() = default;
+ Message(const Message&) = delete;
+ Message(Message&&) = delete;
+ Message& operator=(const Message&) = delete;
+ Message& operator=(Message&&) = delete;
+
+ void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t qid, TransportProtocol proto, size_t len);
+ void setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass);
+
+ void setType(MessageType mtype)
+ {
+ add_enum(d_message, Field::type, static_cast<int32_t>(mtype));
+ }
+
+ void setHTTPVersion(HTTPVersion version)
+ {
+ add_enum(d_message, Field::httpVersion, static_cast<int32_t>(version));
+ }
+
+ void setMessageIdentity(const boost::uuids::uuid& uniqueId)
+ {
+ add_bytes(d_message, Field::messageId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+ }
+
+ void setServerIdentity(const std::string& serverIdentity)
+ {
+ add_bytes(d_message, Field::serverIdentity, serverIdentity.data(), serverIdentity.length());
+ }
+
+ void setSocketFamily(int family)
+ {
+ add_enum(d_message, Field::socketFamily, family == AF_INET ? 1 : 2);
+ }
+
+ void setSocketProtocol(TransportProtocol proto)
+ {
+ add_enum(d_message, Field::socketProtocol, static_cast<int32_t>(proto));
+ }
+
+ void setFrom(const ComboAddress& address)
+ {
+ encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::from), address);
+ }
+
+ void setTo(const ComboAddress& address)
+ {
+ encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::to), address);
+ }
+
+ void setInBytes(uint64_t len)
+ {
+ add_uint64(d_message, Field::inBytes, len);
+ }
+
+ void setTime()
+ {
+ timespec timesp{};
+ gettime(×p, true);
+
+ setTime(timesp.tv_sec, timesp.tv_nsec / 1000);
+ }
+
+ void setTime(time_t sec, uint32_t usec)
+ {
+ // coverity[store_truncates_time_t]
+ add_uint32(d_message, Field::timeSec, sec);
+ add_uint32(d_message, Field::timeUsec, usec);
+ }
+
+ void setId(uint16_t qid)
+ {
+ add_uint32(d_message, Field::id, ntohs(qid));
+ }
+
+ void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
+ {
+ protozero::pbf_writer pbf_question{d_message, static_cast<protozero::pbf_tag_type>(Field::question)};
+ encodeDNSName(pbf_question, d_buffer, static_cast<protozero::pbf_tag_type>(QuestionField::qName), qname);
+ pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qType), qtype);
+ pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qClass), qclass);
+ }
+
+ void setMeta(const std::string& key, const std::unordered_set<std::string>& stringVal, const std::unordered_set<int64_t>& intVal)
+ {
+ protozero::pbf_writer pbf_meta{d_message, static_cast<protozero::pbf_tag_type>(Field::meta)};
+ pbf_meta.add_string(static_cast<protozero::pbf_tag_type>(MetaField::key), key);
+ protozero::pbf_writer pbf_meta_value{pbf_meta, static_cast<protozero::pbf_tag_type>(MetaField::value)};
+ for (const auto& str : stringVal) {
+ pbf_meta_value.add_string(static_cast<protozero::pbf_tag_type>(MetaValueField::stringVal), str);
+ }
+ for (const auto& val : intVal) {
+ pbf_meta_value.add_uint64(static_cast<protozero::pbf_tag_type>(MetaValueField::intVal), val);
+ }
+ }
+
+ void setEDNSSubnet(const Netmask& netmask, uint8_t mask)
+ {
+ encodeNetmask(static_cast<protozero::pbf_tag_type>(Field::originalRequestorSubnet), netmask, mask);
+ }
+
+ void setRequestorId(const std::string& req)
+ {
+ if (!req.empty()) {
+ add_string(d_message, Field::requestorId, req);
+ }
+ }
+
+ void setInitialRequestID(const boost::uuids::uuid& uniqueId)
+ {
+ add_bytes(d_message, Field::initialRequestId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+ }
+
+ void setDeviceId(const std::string& deviceId)
+ {
+ if (!deviceId.empty()) {
+ add_string(d_message, Field::deviceId, deviceId);
+ }
+ }
+
+ void setNewlyObservedDomain(bool nod)
+ {
+ add_bool(d_message, Field::newlyObservedDomain, nod);
+ }
+
+ void setDeviceName(const std::string& name)
+ {
+ if (!name.empty()) {
+ add_string(d_message, Field::deviceName, name);
+ }
+ }
+
+ void setFromPort(in_port_t port)
+ {
+ add_uint32(d_message, Field::fromPort, port);
+ }
+
+ void setToPort(in_port_t port)
+ {
+ add_uint32(d_message, Field::toPort, port);
+ }
+
+ void setWorkerId(uint64_t wid)
+ {
+ add_uint64(d_message, Field::workerId, wid);
+ }
+
+ void setPacketCacheHit(bool hit)
+ {
+ add_bool(d_message, Field::packetCacheHit, hit);
+ }
+
+ void setOutgoingQueries(uint32_t num)
+ {
+ add_uint32(d_message, Field::outgoingQueries, num);
+ }
+
+ void startResponse()
+ {
+ d_response = protozero::pbf_writer{d_message, static_cast<protozero::pbf_tag_type>(Field::response)};
+ }
+
+ void commitResponse()
+ {
+ d_response.commit();
+ }
+
+ void setResponseCode(uint8_t rcode)
+ {
+ d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), rcode);
+ }
+
+ void setNetworkErrorResponseCode()
+ {
+ /* special code meaning 'network error', like a timeout */
+ d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), 65536);
+ }
+
+ void setAppliedPolicy(const std::string& policy)
+ {
+ d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::appliedPolicy), policy);
+ }
+
+ void addPolicyTags(const std::unordered_set<std::string>& tags)
+ {
+ for (const auto& tag : tags) {
+ addPolicyTag(tag);
+ }
+ }
+
+ void addPolicyTag(const string& tag)
+ {
+ d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::tags), tag);
+ }
+
+ void setQueryTime(uint32_t sec, uint32_t usec)
+ {
+ d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeSec), sec);
+ d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeUsec), usec);
+ }
+
+ void addRRsFromPacket(const char* packet, size_t len, bool includeCNAME = false);
+ void addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob);
+
+ protected:
+ void encodeComboAddress(protozero::pbf_tag_type type, const ComboAddress& address);
+ void encodeNetmask(protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
+ static void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, protozero::pbf_tag_type type, const DNSName& name);
+
+ static void add_enum(protozero::pbf_writer& writer, Field type, int32_t value)
+ {
+ writer.add_enum(static_cast<protozero::pbf_tag_type>(type), value);
+ }
+
+ static void add_bool(protozero::pbf_writer& writer, Field type, bool value)
+ {
+ writer.add_bool(static_cast<protozero::pbf_tag_type>(type), value);
+ }
+
+ static void add_uint32(protozero::pbf_writer& writer, Field type, uint32_t value)
+ {
+ writer.add_uint32(static_cast<protozero::pbf_tag_type>(type), value);
+ }
+
+ static void add_uint64(protozero::pbf_writer& writer, Field type, uint64_t value)
+ {
+ writer.add_uint64(static_cast<protozero::pbf_tag_type>(type), value);
+ }
+
+ static void add_bytes(protozero::pbf_writer& writer, Field type, const char* data, size_t len)
+ {
+ writer.add_bytes(static_cast<protozero::pbf_tag_type>(type), data, len);
+ }
+
+ static void add_string(protozero::pbf_writer& writer, Field type, const std::string& str)
+ {
+ writer.add_string(static_cast<protozero::pbf_tag_type>(type), str);
+ }
+
+ // NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes)
+ std::string& d_buffer;
+ protozero::pbf_writer d_message;
+ protozero::pbf_writer d_response;
+ // NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes)
};
};
+};
#endif /* DISABLE_PROTOBUF */
enum class Types : uint8_t { PP_TLV_ALPN = 0x01, PP_TLV_SSL = 0x20 };
};
-static const size_t s_proxyProtocolMinimumHeaderSize = 16;
+static constexpr size_t s_proxyProtocolMinimumHeaderSize = 16;
std::string makeLocalProxyHeader();
std::string makeProxyHeader(bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector<ProxyProtocolValue>& values);
/dnsmessage.pb.h
/pdns-recursor.service
/pdns-recursor@.service
+/pubsuffix.cc
/lua.hpp
/test-suite.log
/testrunner.log
dnslabeltext.cc
CLEANFILES = htmlfiles.h \
- recursor.conf-dist recursor.yml-dist
+ recursor.yml-dist
htmlfiles.h: incfiles ${srcdir}/html/* ${srcdir}/html/js/*
$(AM_V_GEN)$(srcdir)/incfiles > $@.tmp
lua_hpp.mk \
malloctrace.cc malloctrace.hh \
mkpubsuffixcc \
- mtasker_fcontext.cc mtasker_ucontext.cc \
NOTICE \
opensslsigners.hh opensslsigners.cc \
portsmplexer.cc \
test-rpzloader_cc.cc \
test-secpoll_cc.cc \
test-settings.cc \
+ test-sholder_hh.cc \
test-signers.cc \
test-syncres_cc.cc \
test-syncres_cc.hh \
$(srcdir)/mkpubsuffixcc $< $@
## Config file
-sysconf_DATA = recursor.conf-dist recursor.yml-dist
-
-recursor.conf-dist: pdns_recursor
- $(AM_V_GEN)./pdns_recursor --config=default > $@
+sysconf_DATA = recursor.yml-dist
recursor.yml-dist: pdns_recursor
dir=$$(mktemp -d) && touch "$$dir/recursor.yml" && ./pdns_recursor --config-dir="$$dir" --config=default 2> /dev/null > $@ && rm "$$dir/recursor.yml" && rmdir "$$dir"
REVISION "202306080000Z"
DESCRIPTION "Added metrics for NOD and UDR events"
+ REVISION "202405230000Z"
+ DESCRIPTION "Added metrics for maximum chain length and weight"
+
+ REVISION "202408130000Z"
+ DESCRIPTION "Added metric for chain limits reached"
+
+ REVISION "202408280000Z"
+ DESCRIPTION "Added metric for too many incoming TCP connections"
+
::= { powerdns 2 }
powerdns OBJECT IDENTIFIER ::= { enterprises 43315 }
"Count of UDR events"
::= { stats 148 }
+maxChainLength OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum chain length"
+ ::= { stats 149 }
+
+maxChainWeight OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum chain weight"
+ ::= { stats 150 }
+
+chainLimits OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Chain limits reached"
+ ::= { stats 151 }
+
+tcpOverflow OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Incoming TCP limits reached"
+ ::= { stats 152 }
+
---
--- Traps / Notifications
---
zoneDisallowedNotify,
nonResolvingNameserverEntries,
maintenanceUSec,
- maintenanceCalls,
+ maintenanceCount,
authrcode0Count,
authrcode1Count,
authrcode2Count,
packetCacheContended,
packetCacheAcquired,
nodEvents,
- udrEvents
+ udrEvents,
+ maxChainLength,
+ maxChainWeight,
+ chainLimits,
+ tcpOverflow
}
STATUS current
DESCRIPTION "Objects conformance group for PowerDNS Recursor"
PDNS_CHECK_CLOCK_GETTIME
-BOOST_REQUIRE([1.42])
-
-# Check against flat_set header that requires boost >= 1.48
-BOOST_FIND_HEADER([boost/container/flat_set.hpp], [AC_MSG_NOTICE([boost::container::flat_set not available, will fallback to std::set])])
-
-# Boost Context was introduced in 1.51 (Aug 2012), but there was an immediate
-# API break in 1.52 (Nov 2012), so we only support that, and later.
-pdns_context_library=""
-AS_IF([test $boost_major_version -ge 152], [BOOST_CONTEXT([], [no])])
-AS_IF([test x"$boost_cv_lib_context" = "xyes"], [
- pdns_context_library="Boost Context"
-], [
- AC_CHECK_FUNCS([getcontext makecontext swapcontext], [pdns_context_library="System V ucontexts"])
-])
-AC_MSG_CHECKING([what context library to use for MTasker])
-AS_IF([test -n "$pdns_context_library"], [AC_MSG_RESULT([$pdns_context_library])], [AC_MSG_ERROR([neither boost::context nor System V ucontexts available])])
+BOOST_REQUIRE([1.54])
+BOOST_CONTEXT([], [yes])]
PDNS_ENABLE_UNIT_TESTS
PDNS_ENABLE_REPRODUCIBLE
[AC_MSG_NOTICE([libcurl: yes])],
[AC_MSG_NOTICE([libcurl: no])]
)
-AC_MSG_NOTICE([Context library: $pdns_context_library])
AC_MSG_NOTICE([])
Older releases are marked end of life and receive no updates at all.
Pre-releases do not receive immediate security updates.
-The currently supported release train of the PowerDNS Recursor is 5.0.
+The currently supported release train of the PowerDNS Recursor is 5.1.
-PowerDNS Recursor 4.9 will only receive critical updates and will be End of Life one year after PowerDNS Recursor 5.0 was released.
+PowerDNS Recursor 5.0 will only receive critical updates and will be End of Life one year after PowerDNS Recursor 5.1 was released.
-PowerDNS Recursor 4.8 will only receive critical updates and will be End of Life one year after PowerDNS Recursor 4.9 was released.
+PowerDNS Recursor 4.9 will only receive critical updates and will be End of Life one year after PowerDNS Recursor 5.0 was released.
-PowerDNS Recursor 4.0 through 4.7, 3.x, and 2.x are End of Life.
+PowerDNS Recursor 4.0 through 4.8, 3.x, and 2.x are End of Life.
Note: Users with a commercial agreement with PowerDNS.COM BV or Open-Xchange
can receive extended support for releases which are End Of Life. If you are
- Release date
- Critical-Only updates
- End of Life
+ * - 5.1
+ - July 10 2024
+ - ~ February 2025
+ - ~ February 2026
* - 5.0
- January 10 2024
- - ~ July 2024
- - ~ July 2025
+ - July 10 2024
+ - July 10 2025
* - 4.9
- June 30 2023
- January 10 2024
* - 4.8
- December 12 2022
- June 30 2023
- - June 30 2024
+ - EOL June 30 2024
* - 4.7
- May 30 2022
- December 12 2022
For example, in the default setup the root name servers are called ``[a-m].root-servers.net``, so the :program:`Recursor` will resolve the name servers of the ``.net`` domain.
This is needed to correctly determine zone cuts to be able to decide if the ``.root-servers.net`` domain is DNSSEC protected. Newer versions solve this by querying the needed information top-down.
+Starting with version 5.0.0, enabling :ref:`setting-allow-no-rd` allows for queries without the recursion desired bit to be answered from cache.
+Older versions of the ``dig`` program provided by ISC do not set the RD bit on the initial ``+trace`` query causing it to sometimes fail to perform a ``+trace`` when asking a freshly restarted :program:`Recursor` despite the :ref:`setting-allow-no-rd` option being set.
+This is because there is a short while after restarting that the cache has no authoritative data on the root, so it will answer with an NODATA (NOERROR and no answer records) in that period for RD=0 queries asking for the root name servers.
+For ``dig`` this has been fixed in `BIND 9.15.1 <https://gitlab.isc.org/isc-projects/bind9/-/issues/1028>`_ by setting the RD bit.
By default, the :program:`Recursor` requires the following libraries and headers:
-* `Boost <http://boost.org/>`_ 1.35 or newer
+* `Boost <http://boost.org/>`_ 1.54 or newer
* `Lua <http://www.lua.org/>`_ 5.1+ or `LuaJit <http://luajit.org/>`_
* `OpenSSL <https://openssl.org>`_
* For :program:`Recursor` version 5 and higher, `cargo <https://www.rust-lang.org/tools/install>`_ version 1.64 or newer.
:pullreq: 8047
:tickets: 8008
- Another time sensistive test fixed with a fixednow construct.
+ Another time sensitive test fixed with a fixednow construct.
.. change::
:tags: New Features
Changelogs for 4.9.X
====================
+.. changelog::
+ :version: 4.9.8
+ :released: 23rd of July 2024
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14503
+ :tickets: 14499
+
+ Optimize processing of additionals.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14483
+ :tickets: 14471
+
+ Dump right SOA into dumpFile and report non-relative SOA for includeSOA=true.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14480
+ :tickets: 14404
+
+ Yahttp router: avoid unsigned underflow in route().
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14413
+ :tickets: 14400
+
+ Switch el7 builds to Oracle Linux 7.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14416
+ :tickets: 14359
+
+ dns.cc: use pdns::views::UnsignedCharView.
+
+.. changelog::
+ :version: 4.9.7
+ :released: 3rd of July 2024
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14380
+ :tickets: 14373
+
+ Remove potential double SOA records if the target of a dns64 name is NODATA.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14352
+ :tickets: 14346
+
+ Fix TCP case for policy tags to not produce cached tags in protobuf messages.
+
.. changelog::
:version: 4.9.6
:released: 14th of May 2024
Before upgrading, it is advised to read the :doc:`../upgrade`.
+.. changelog::
+ :version: 5.0.8
+ :released: 23rd of July 2024
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14502
+ :tickets: 14499
+
+ Limit the number of async tasks pushed to resolve NS names and optimize processing of additionals.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14482
+ :tickets: 14471
+
+ Dump right SOA into dumpFile and report non-relative SOA for includeSOA=true.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14479
+ :tickets: 14404
+
+ Yahttp router: avoid unsigned underflow in route().
+
+ .. change::
+ :tags: Improvements.
+ :pullreq: 14412
+ :tickets: 134400
+
+ Switch el7 builds to Oracle Linux 7.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14415
+ :tickets: 14359
+
+ dns.cc: use pdns::views::UnsignedCharView.
+
+.. changelog::
+ :version: 5.0.7
+ :released: 3rd of July 2024
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14379
+ :tickets: 14373
+
+ Remove potential double SOA records if the target of a dns64 name is NODATA.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14351
+ :tickets: 14346
+
+ Fix TCP case for policy tags to not produce cached tags in protobuf messages.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14348
+ :tickets: 14340
+
+ Count substituted remote in case of proxy protocol.
+
+.. changelog::
+ :version: 5.0.6
+ :released: 5th of June 2024
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14223
+ :tickets: 14197
+
+ YaHTTP: Enforce max # of request fields and max request line size.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14222
+ :tickets: 14185
+
+ Report error and adjust max-mthreads when linux map limit (vm.max_map_count) is too low to accommodate resource usage under load.
+
.. changelog::
:version: 5.0.5
:released: 14th of May 2024
Before upgrading, it is advised to read the :doc:`../upgrade`.
+.. changelog::
+ :version: 5.1.1
+ :released: 23rd of July 2024
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14516
+ :tickets: 14514
+
+ Fix maintenanceCalls vs maintenanceCount in SNMP MIB.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14501
+ :tickets: 14499
+
+ Limit the number of async tasks pushed to resolve NS names and optimizer processing of additionals.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14481
+ :tickets: 14471
+
+ Dump right SOA into dumpFile and report non-relative SOA for includeSOA=true.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14478
+ :tickets: 14404
+
+ Yahttp router: avoid unsigned underflow in match().
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14477
+ :tickets: 14459
+
+ Move default Docker config to YAML.
+
+.. changelog::
+ :version: 5.1.0
+ :released: 10th of July 2024
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14435
+
+ Fix typo in log message.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14402
+ :tickets: 14400
+
+ Switch el7 builds to Oracle Linux 7
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14389
+ :tickets: 14384
+
+ Keep Lua config in Debian/Ubuntu package as existing setups might use it, even though a fresh one does not.
+
+.. changelog::
+ :version: 5.1.0-rc1
+ :released: 25th of June 2024
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14373
+ :tickets: 14362
+
+ Don't send double SOA record in the case of a dns64 CNAME that does not resolve.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14265,14374
+ :tickets: 13935
+
+ Allow recursor.conf file to contain YAML to ease transition to YAML config.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14318
+
+ Add nsName into outgoing protobuf request/response messages.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14359
+ :tickets: 14356
+
+ dns.cc: use pdns::views::UnsignedCharView.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14346
+ :tickets: 13021
+
+ Fix TCP case for policy tags set by gettag(_ffi).
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 14340
+
+ Fix client remotes count when using proxy protocol.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14312
+
+ Do not add UDR field to outgoingProtobuf answer messages
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14275
+
+ Add options for ignoring domains for UDR purposes (Ensar Sarajčić).
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14309
+
+ Make max CNAME chain length handled settable, previously fixed at 10.
+
+.. changelog::
+ :version: 5.1.0-beta1
+ :released: 6th of June 2024
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14257
+ :tickets: 13020
+
+ Add a few more fields to the protobuf messages.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14221,14258
+
+ Handle authoritative servers slow to respond when load is high better.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14206
+
+ Be a bit more strict with respect to positive answers expanded from a wildcard.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14111
+
+ Extra export types for protobuf messages.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 14268,14259,14260,14262
+
+ Various code cleanups and Coverity prompted fixes.
+
.. changelog::
:version: 5.1.0-alpha1
:released: 15th of May 2024
--- /dev/null
+../../../docs/generate-man-pages.py
\ No newline at end of file
:property [RRSet] rrsets: RRSets in this zone
:property [str] servers: For zones of type "Forwarded", addresses to send the queries to
:property bool recursion_desired: For zones of type "Forwarded", Whether or not the RD bit should be set in the query
+ :property bool notify_allowed: For zones of type "Forwarded", Whether or not to permit incoming NOTIFY to wipe cache for the domain
To properly process new zones, the following conditions must
be true:
.. versionchanged:: 5.1.0
- Added support for the HTTPS, SVCB and APTR record types.
+ Added support for the HTTPS, SVCB and NAPTR record types.
.. function:: protobufServer(server [[[[[[[, timeout=2], maxQueuedEntries=100], reconnectWaitTime=1], maskV4=32], maskV6=128], asyncConnect=false], taggedOnly=false])
.. versionchanged:: 5.1.0
- Added support for the HTTPS, SVCB and APTR records types.
+ Added support for the HTTPS, SVCB and NAPTR records types.
.. function:: outgoingProtobufServer(server [[[[, timeout=2], maxQueuedEntries=100], reconnectWaitTime=1], asyncConnect=false])
* ``logQueries=true``: bool - log outgoing queries
* ``logResponses=true``: bool - log incoming responses
- The following options apply to the settings of the framestream library. Refer to the documentation of that
- library for the default values, exact description and allowable values for these options.
- For all these options, absence or a zero value has the effect of using the library-provided default value.
+ The following options apply to the settings of the `framestream library
+ <https://github.com/farsightsec/fstrm>`. Refer to the documentation of that library for the default
+ values, exact description and allowable values for these options. For all these options, absence or a zero
+ value has the effect of using the library-provided default value.
* ``bufferHint=0``: unsigned
* ``flushTimeout=0``: unsigned
* ``logNODs=true``: bool - log NODs
* ``logUDRs=false``: bool - log UDRs
- The following options apply to the settings of the framestream library. Refer to the documentation of that
- library for the default values, exact description and allowable values for these options.
- For all these options, absence or a zero value has the effect of using the library-provided default value.
+ The following options apply to the settings of the `framestream library
+ <https://github.com/farsightsec/fstrm>`. Refer to the documentation of that library for the default
+ values, exact description and allowable values for these options. For all these options, absence or a zero
+ value has the effect of using the library-provided default value.
* ``bufferHint=0``: unsigned
* ``flushTimeout=0``: unsigned
.. attribute:: DNSQuestion.tag
- The packet-cache tag set via :func:`gettag`, or 0 if it has not been set.
+ The packetcache tag set via :func:`gettag` or :func:`gettag_ffi`.
+ Default tag is zero. Internally to the recursor, the tag is interpreted as an unsigned 32-bit integer.
.. attribute:: DNSQuestion.queryTime
The ``proxyprotocolvalues`` parameter was added.
- The ``gettag`` function is invoked when the Recursor attempts to discover in which packetcache an answer is available.
+ The :func:`gettag` function is invoked when :program:`Recursor` attempts to discover in which packetcache an answer is available.
- This function must return an integer, which is the tag number of the packetcache.
- In addition to this integer, this function can return a table of policy tags.
+ This function must return an unsigned 32-bit integer, which is the tag number of the packetcache.
+ The tag is used to partition the packet cache. The default tag (when :func:`gettag` is not defined) is zero.
+ If :func:`gettag` throws an exception, the zero tag is used.
+
+ In addition to the tag, this function can return a table of policy tags and a few more values to be passed to the resolving process.
The resulting tag number can be accessed via :attr:`dq.tag <DNSQuestion.tag>` in the :func:`preresolve` hook, and the policy tags via :meth:`dq:getPolicyTags() <DNSQuestion:getPolicyTags>` in every hook.
.. versionadded:: 4.1.0
The tagged packetcache can e.g. be used to answer queries from cache that have e.g. been filtered for certain IPs (this logic should be implemented in :func:`gettag`).
This ensure that queries are answered quickly compared to setting :attr:`dq.variable <DNSQuestion.variable>` to true.
- In the latter case, repeated queries will pass through the entire Lua script.
+ In the latter case, repeated queries will not be found in the packetcache and pass through the entire resolving process, and all relevant Lua hooks wil be called.
:param ComboAddress remote: The sender's IP address
:param Netmask ednssubnet: The EDNS Client subnet that was extracted from the packet
.. function:: gettag_ffi(param) -> optional Lua object
- .. versionadded:: 4.1.2
+ .. versionadded:: 4.1.2
- .. versionchanged:: 4.3.0
+ .. versionchanged:: 4.3.0
The ability to craft answers was added.
- This function is the FFI counterpart of the :func:`gettag` function, and offers the same functionality.
- It accepts a single, scalable parameter which can be accessed using :doc:`FFI accessors <ffi>`.
- Like the non-FFI version, it has the ability to set a tag for the packetcache, policy tags, a routing tag, the :attr:`DNSQuestion.requestorId` and :attr:`DNSQuestion.deviceId` values and to fill the :attr:`DNSQuestion.data` table. It also offers ways to mark the answer as variable so it's not inserted into the packetcache, to set a cap on the TTL of the returned records, and to generate a response by adding records and setting the RCode. It can also instruct the recursor to do a proper resolution in order to follow any `CNAME` records added in this step.
+ This function is the FFI counterpart of the :func:`gettag` function, and offers the same functionality.
+ It accepts a single parameter which can be accessed and modified using :doc:`FFI accessors <ffi>`.
+
+ Like the non-FFI version, it has the ability to set a tag for the packetcache, policy tags, a routing tag, the :attr:`DNSQuestion.requestorId` and :attr:`DNSQuestion.deviceId` values and to fill the :attr:`DNSQuestion.data` table. It also offers ways to mark the answer as variable so it's not inserted into the packetcache, to set a cap on the TTL of the returned records, and to generate a response by adding records and setting the RCode. It can also instruct the recursor to do a proper resolution in order to follow any `CNAME` records added in this step.
+
+ If this function does not set the tag or an exception is thrown, the zero tag is assumed.
.. function:: prerpz(dq) -> bool
The recursor can export statistics over SNMP and send traps from :doc:`Lua <lua-scripting/index>`, provided support is compiled into the Recursor and :ref:`setting-snmp-agent` set.
-MIB
-^^^
+For the details of all values that can be retrieved using SNMP, see the `SNMP MIB <https://github.com/PowerDNS/pdns/blob/master/pdns/recursordist/RECURSOR-MIB.txt>`_.
-.. literalinclude:: ../RECURSOR-MIB.txt
.. _metricnames:
^^^^^^^^^^^^^^^
counts the number of mismatches in character case since starting
+chain-limits
+^^^^^^^^^^^^
+counts the number of times a chain limit (size or age) has been hit
+
chain-resends
^^^^^^^^^^^^^
number of queries chained to existing outstanding query
number of responses sent, packet-cache hits excluded, that were in the Bogus state because a NODATA or NXDOMAIN answer lacked the required SOA and/or NSEC(3) records.
-dnssec-result-bogus-signature-no-yet-valid
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+dnssec-result-bogus-signature-not-yet-valid
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. versionadded:: 4.4.2
number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature inception time in the RRSIG was not yet valid.
^^^^^^^^^^^^^^^^^
currently configured maximum number of cache entries
+max-chain-length
+^^^^^^^^^^^^^^^^
+maximum chain length
+
+max-chain-weight
+^^^^^^^^^^^^^^^^
+maximum chain weight. The weight of a chain of outgoing queries is the product of the number of chained queries by the size of the response received from the external authoritative server.
+
max-packetcache-entries
^^^^^^^^^^^^^^^^^^^^^^^
currently configured maximum number of packet cache entries
number of tasks currently in the taskqueues
+.. _stat-tcp-overflow:
+
+tcp-overflow
+^^^^^^^^^^^^
+number of times an incoming TCP connection was closed immediately because there were too many open connections already
+
.. _stat-tcp-client-overflow:
tcp-client-overflow
Once enabled the recursor will keep track of previously seen domains using the SBF data structure, which is periodically persisted to the directory specified in the ``new-domain-history-dir``, which defaults to /var/lib/pdns-recursor/nod.
-Administrators may wish to prevent certain domains or subdomains from ever triggering the NOD algorithm, in which case those domains must be added to the ``new-domain-ignore-list`` setting as a comma separated list. No domain (or subdomain of a domain) listed will be considered a newly observed domain.
+Administrators may wish to prevent certain domains or subdomains from ever triggering the NOD algorithm, in which case those domains must be added to the ``new-domain-ignore-list`` setting as a comma separated list. No domain (or subdomain of a domain) listed will be considered a newly observed domain. It is also possible to use ``new-domain-ignore-list-file`` to read a file with ignored domains, one domain per line.
There are several ways to receive the information about newly observed domains:
The SBF (which is maintained separately per recursor thread) cell size defaults to 67108864, which can be changed using the setting ``unique-response-db-size``. The same caveats regarding FPs/FNs apply as for NOD.
+Similarly to NOD, administrators may wish to prevent certain domains or subdomains from ever triggering the UDR algorithm, in which case those domains must be added to the ``udr-ignore-list`` setting as a comma separated list. No domain (or subdomain of a domain) listed will be considered a new unique domain response. It is also possible to use ``udr-ignore-list-file`` to read a file with ignored domains, one domain per line.
+
Similarly to NOD, unique domain responses can be tracked using several mechanisms:
Logging
MTasker and MThreads
--------------------
-PowerDNS Recursor uses a cooperative multitasking in userspace called ``MTasker``, based either on ``boost::context`` if available, or on ``System V ucontexts`` otherwise. For maximum performance, please make sure that your system supports ``boost::context``, as the alternative has been known to be quite slower.
+PowerDNS :program:`Recursor` uses a cooperative multitasking in userspace called ``MTasker``, based either on ``boost::context`` if available, or on ``System V ucontexts`` otherwise. For maximum performance, please make sure that your system supports ``boost::context``, as the alternative has been known to be quite slower.
The maximum number of simultaneous MTasker threads, called ``MThreads``, can be tuned via :ref:`setting-max-mthreads`, as the default value of 2048 might not be enough for large-scale installations.
This setting limits the number of mthreads *per physical (Posix) thread*.
The threads that create mthreads are the distributor and worker threads.
-When a ``MThread`` is started, a new stack is dynamically allocated for it on the heap. The size of that stack can be configured via the :ref:`setting-stack-size` parameter, whose default value is 200 kB which should be enough in most cases.
+When a ``MThread`` is started, a new stack is dynamically allocated for it. The size of that stack can be configured via the :ref:`setting-stack-size` parameter, whose default value is 200 kB which should be enough in most cases.
To reduce the cost of allocating a new stack for every query, the recursor can cache a small amount of stacks to make sure that the allocation stays cheap. This can be configured via the :ref:`setting-stack-cache-size` setting.
This limit is per physical (Posix) thread.
The only trade-off of enabling this cache is a slightly increased memory consumption, at worst equals to the number of stacks specified by :ref:`setting-stack-cache-size` multiplied by the size of one stack, itself specified via :ref:`setting-stack-size`.
+Linux limits the number of memory mappings a process can allocate by the ``vm.max_map_count`` kernel parameter.
+A single ``MThread`` stack can take up to 3 memory mappings.
+Starting with version 4.9, it is advised to check and if needed update the value of ``sysctl vm.max_map_count`` to make sure that the :program:`Recursor` can allocate enough stacks under load; suggested value is at least ``4 * (threads + 2) * max-mthreads``.
+Some Linux distributions use a default value of about one million, which should be enough for most configurations.
+Other distributions default to 64k, which can be too low for large setups.
+
Performance tips
----------------
This is solved by rebooting with ``clock=tsc`` or upgrading to a 2.6.17 kernel.
This is relevant if dmesg shows ``Using pmtmr for high-res timesource``.
+Memory usage
+------------
+
+:program:`Recursor` keeps all the data it needs in memory.
+The default configuration uses a little more than 1GB when the caches are full.
+Depending on configuration, memory usage can amount to many gigabytes for a large installation.
+
+.. warning::
+ Avoid swapping. The memory access patterns of :program:`Recursor` are random. This means
+ that it will cause trashing (the OS spending lots of time pulling in and writing out memory
+ pages) if :program:`Recursor` uses more physical memory than available and performance will be severely impacted.
+
+Below the memory usage observed for a specific test case are described.
+Please note that depending on OS, version of system libraries, version of the :program:`Recursor`, features used and usage patterns these numbers may vary.
+Test and observe your system to learn more about the memory requirements specific to your case.
+
+The most important subsystems that use memory are:
+
+- The packet cache. The amount of memory used in a test case was about 500 bytes per entry
+- The record cache. The amount of memory used in a test case was about 850 bytes per entry
+- Authoritative zones loaded. Memory usage is dependent on the size and number loaded.
+- RPZ zones loaded. Memory usage is dependent on the size and number loaded.
+- NOD DBs. Memory usage is dependent on specific settings of this subsystem.
+
+An estimate for the memory used by its caches for a :program:`Recursor` having 2 million record cache entries and 1 million packet cache entries is ``2e6 * 850 * + 1e6 * 500 = about 2GB``.
+
Connection tracking and firewalls
---------------------------------
#
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --generate-hashes requirements.in
--hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
--hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
# via sphinx
-certifi==2024.2.2 \
- --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
- --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
+certifi==2024.7.4 \
+ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
+ --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
# via requests
changelog==0.5.8 \
--hash=sha256:43b21840874130666b7534b76b402bbb914f8c9c413d5ea9d45850ca4767dafb \
--hash=sha256:4edf0223a0685a7c485ae5a156b6f529ba1ee481a1417817935b20bde1956232 \
--hash=sha256:6fc9287dfc823fe9aa432463edd6cea47fa9ebbf488d7f289b322ffcfca075c7
# via sphinx
-urllib3==2.2.0 \
- --hash=sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20 \
- --hash=sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224
+urllib3==2.2.2 \
+ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
+ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
# via requests
# WARNING: The following packages were not pinned, but pip requires them to be
Cache Management
----------------
-Sometimes a domain fails to resolve due to an error on the domain owner's end, or records for your own domain have updated and you want your users to immediatly see them without waiting for the TTL to expire.
+Sometimes a domain fails to resolve due to an error on the domain owner's end, or records for your own domain have updated and you want your users to immediately see them without waiting for the TTL to expire.
The :doc:`rec_control <manpages/rec_control.1>` tool can be used to selectively wipe the cache.
To wipe all records for the exact name 'www.example.com'::
rec_control trace-regex
-
+Logging details of queries and answers
+--------------------------------------
+
+In some cases a tracing provides too much information, and we want to follow what the recursor is doing on a higher level.
+By setting :ref:`setting-yaml-logging.quiet` to ``true`` the recursor will produce a log line for each client query received and answered.
+Be aware that this causes overhead and should not be used in a high query-per-second production environment::
+
+ Jul 09 09:08:31 msg="Question" subsystem="syncres" level="0" prio="Info" tid="4" ts="1720508911.919" ecs="" mtid="1" proto="udp" qname="www.example.com" qtype="A" remote="127.0.0.1:54573"
+
+ Jul 09 09:08:32 msg="Answer" subsystem="syncres" level="0" prio="Info" tid="4" ts="1720508912.549" additional="1" answer-is-variable="0" answers="1" dotout="0" ecs="" into-packetcache="1" maxdepth="3" mtid="1" netms="617.317000" outqueries="13" proto="udp" qname="www.example.com" qtype="A" rcode="0" rd="1" remote="127.0.0.1:54573" tcpout="0" throttled="0" timeouts="0" totms="627.060000" validationState="Secure"
+
+When ``quiet`` is set to ``false``, the following keys and values are logged for questions and answers not
+answered from the packet cache.
+Refer to :doc:`appendices/structuredlogging` for more details on the common keys used for structured logging messages.
+Note that depending on record cache content a single client query can result into multiple queries to authoritative servers.
+If the exact answer is available from the record cache no outgoing queries are needed.
+
++-------------------------------------------------------------------------------------------+
+| **Keys common to Questions and Answers** |
++-----------------------+-----------------------------+-------------------------------------+
+| **Key** | **Description** | **Remarks** |
++-----------------------+-----------------------------+-------------------------------------+
+|``ecs`` |Client ECS info |Filled in if enabled |
++-----------------------+-----------------------------+-------------------------------------+
+|``proto`` |Protocol used by client |``udp`` or ``tcp`` |
++-----------------------+-----------------------------+-------------------------------------+
+|``qname`` |Query name | |
++-----------------------+-----------------------------+-------------------------------------+
+|``qtype`` |Query type | |
++-----------------------+-----------------------------+-------------------------------------+
+|``remote`` |Client address |IP:port combination |
++-----------------------+-----------------------------+-------------------------------------+
+| **Keys specific to Answers** |
++-----------------------+-----------------------------+-------------------------------------+
+|``additional`` |Number of additional records | |
+| |in answer | |
++-----------------------+-----------------------------+-------------------------------------+
+|``answer-is-variable`` |Is answer marked variable by |e.g. ECS dependent answers |
+| |recursor? | |
++-----------------------+-----------------------------+-------------------------------------+
+|``answers`` |Number of answer records in | |
+| |answer | |
++-----------------------+-----------------------------+-------------------------------------+
+|``dotout`` |Number of outgoing DoT | |
+| |queries sent to authoritative| |
+| |servers to resolve answer | |
++-----------------------+-----------------------------+-------------------------------------+
+|``into-packetcache`` |Is the answer being stored |Variable answers (as determined by |
+| |into the packetcache? |the recursor or marked as such by Lua|
+| | |code) will not be put into the packet|
+| | |cache |
++-----------------------+-----------------------------+-------------------------------------+
+|``maxdepth`` |Depth of recursion needed to |Some queries need resolving multiple |
+| |resolve answer |targets, e.g. to find the right |
+| | |delegation or answers containing |
+| | |CNAMEs |
++-----------------------+-----------------------------+-------------------------------------+
+|``netms`` |Time spent waiting for | |
+| |answers from authoritative | |
+| |servers | |
++-----------------------+-----------------------------+-------------------------------------+
+|``outqueries`` |Total queries sent to |A single client query can cause |
+| |authoritative servers |multiple queries to authoritative |
+| | |servers, depending on record cache |
+| | |content and the query itself. |
++-----------------------+-----------------------------+-------------------------------------+
+|``rcode`` |Result code |If no rcode is available (e.g. in the|
+| | |case of timeouts) this value can be |
+| | |negative |
++-----------------------+-----------------------------+-------------------------------------+
+|``rd`` |Did the client set the | |
+| |Recursion Desired DNS Header | |
+| |flag? | |
++-----------------------+-----------------------------+-------------------------------------+
+|``tcpout`` |Number of outgoing TCP | |
+| |queries sent to authoritative| |
+| |servers to resolve answer | |
+| | | |
++-----------------------+-----------------------------+-------------------------------------+
+|``throttled`` |Number of potential outgoing |If a target is throttled, the |
+| |queries **not** sent out |recursor will try another suitable |
+| |because the target was marked|authoritative server (if available) |
+| |as unreliable by previous | |
+| |interactions | |
+| | | |
++-----------------------+-----------------------------+-------------------------------------+
+|``timeouts`` |Number of outgoing queries | |
+| |that timed out | |
++-----------------------+-----------------------------+-------------------------------------+
+|``totms`` |Total time spent resolving | |
++-----------------------+-----------------------------+-------------------------------------+
+|``validationState`` |The DNSSEC status of the | |
+| |answer | |
++-----------------------+-----------------------------+-------------------------------------+
Before upgrading, it is advised to read the :doc:`changelog/index`.
When upgrading several versions, please read **all** notes applying to the upgrade.
-5.0.5 to 5.1.0 and master
--------------------------
+5.1.0 to master
+----------------
+
+Changed behaviour
+-----------------
+The way :ref:`setting-yaml-incoming.max_tcp_clients` is enforced has changed.
+If there are too many incoming TCP connections, new connections will be accepted but then closed immediately.
+Previously, excess connections would linger in the OS listen queue until timeout or until processing of incoming TCP connections resumed due to the number of connections being processed dropping below the limit.
+There is a new metric ``tcp-overflow`` that counts the connections closed immediately.
+
+
+5.0.6 to 5.1.0
+--------------
+
+The recursor.conf configuration file may contain YAML configuration syntax and new installs using our packages from repo.powerdns.com will install a configuration file using YAML syntax.
+Note to third-party package maintainers: please start doing the same.
+
+.. warning::
+
+ If you are using the default *unmodified* ``recursor.conf`` from a previous release, it will be overwritten by an equivalent ``recursor.conf`` in YAML format by most packaging tools.
+ If you *also* have local setting files in the include directory, these are now expected to be in YAML format as well, because the format of the included files must be the same as the format of the main ``recursor.conf``.
+ This has the consequence that the previously included files will not be processed after the upgrade.
+ To work around this issue, either:
+
+ - modify the ``recursor.conf`` before upgrading so it does not get overwritten by the upgrade,
+ - copy back the original old-style ``recursor.conf`` after upgrading,
+ - or change the format of the existing included files into YAML and make sure their names have the ``.yml`` suffix.
+
+ A *modified* ``recursor.conf`` file will not be overwritten by an upgrade.
New settings
^^^^^^^^^^^^
- The :ref:`setting-system-resolver-ttl` setting has been introduced to set the TTL of the system resolver. The system resolver can be used to resolve forwarding names.
- The :ref:`setting-system-resolver-interval` setting has been introduced to set the interval of resolve checks done by the system resolver.
- The :ref:`setting-system-resolver-self-resolve-check` setting has been introduced to disable to discovery of self-resolving configurations.
+- The :ref:`setting-max-chain-length` setting has been introduced to limit the maximum number of queries that can be attached to an outgoing request chain.
+- The :ref:`setting-max-cnames-followed` setting has been introduced to limit the length of CNAME chains followed. Previously this limit was fixed at 10.
+- The :ref:`setting-new-domain-ignore-list-file`, :ref:`setting-unique-response-ignore-list` and :ref:`setting-unique-response-ignore-list-file` settings have been introduced to filter names reported by the NOD and UDR subsystems.
+
Changed settings
^^^^^^^^^^^^^^^^
- The :ref:`setting-max-qperq` default value has been lowered to 50, and the qname-minimization special case has been removed.
- Disabling :ref:`setting-structured-logging` is no longer supported.
- The :ref:`setting-structured-logging-backend` setting has gained the possibility to request JSON formatted output of structured logging information.
+
+5.0.5 to 5.0.6
+--------------
+
+Changed settings
+^^^^^^^^^^^^^^^^
+
- The :ref:`setting-max-mthreads` setting will be adjusted to a lower value if the value of ``sysctl vm.max_map_count`` is too low to support the maximum number of mthread stacks. In this case :program:`Recursor` logs an error message including the suggested value of ``vm.max_map_count`` to not cause lowering of :ref:`setting-max-mthreads`.
5.0.4 to 5.0.5
--- /dev/null
+../../../../ext/arc4random/meson.build
\ No newline at end of file
--- /dev/null
+../../../../ext/json11/meson.build
\ No newline at end of file
--- /dev/null
+../../../../ext/probds/meson.build
\ No newline at end of file
--- /dev/null
+../../../../ext/yahttp/meson.build
\ No newline at end of file
--- /dev/null
+../../../../../ext/yahttp/yahttp/meson.build
\ No newline at end of file
void DNSFilterEngine::Zone::dump(FILE* filePtr) const
{
- /* fake the SOA record */
- auto soa = DNSRecordContent::make(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
- fprintf(filePtr, "%s IN SOA %s\n", d_domain.toString().c_str(), soa->getZoneRepresentation().c_str());
+ if (DNSRecord soa = d_zoneData->d_soa; !soa.d_name.empty()) {
+ fprintf(filePtr, "%s IN SOA %s\n", soa.d_name.toString().c_str(), soa.getContent()->getZoneRepresentation().c_str());
+ }
+ else {
+ /* fake the SOA record */
+ auto soarr = DNSRecordContent::make(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
+ fprintf(filePtr, "%s IN SOA %s\n", d_domain.toString().c_str(), soarr->getZoneRepresentation().c_str());
+ }
for (const auto& pair : d_qpolName) {
dumpNamedPolicy(filePtr, pair.first + d_domain, pair.second);
#include <unordered_set>
#include "rec-main.hh"
-RecursorLua4::RecursorLua4() { prepareContext(); }
-
boost::optional<dnsheader> RecursorLua4::DNSQuestion::getDH() const
{
if (dh != nullptr) {
// clang-format off
-void RecursorLua4::postPrepareContext()
+void RecursorLua4::postPrepareContext() // NOLINT(readability-function-cognitive-complexity)
{
d_lw->registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dnsQuestion) -> const DNSName& { return dnsQuestion.qname; }, [](DNSQuestion& /* dnsQuestion */, const DNSName& newName) { (void) newName; });
d_lw->registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dnsQuestion) -> uint16_t { return dnsQuestion.qtype; }, [](DNSQuestion& /* dnsQuestion */, uint16_t newType) { (void) newType; });
(*event.discardedPolicies)[policy] = true;
}
});
+ if (!d_include_path.empty()) {
+ includePath(d_include_path);
+ }
}
// clang-format on
class RecursorLua4 : public BaseLua4
{
public:
- RecursorLua4();
+ RecursorLua4(const std::string& includePath = "") :
+ BaseLua4(includePath)
+ {
+ prepareContext();
+ };
RecursorLua4(const RecursorLua4&) = delete;
RecursorLua4(RecursorLua4&&) = delete;
RecursorLua4& operator=(const RecursorLua4&) = delete;
#endif // HAVE_FSTRM
-static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const boost::optional<const boost::uuids::uuid&>& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, size_t bytes, const boost::optional<Netmask>& srcmask)
+static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const boost::optional<const boost::uuids::uuid&>& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, size_t bytes, const boost::optional<Netmask>& srcmask, const std::string& nsName)
{
if (!outgoingLoggers) {
return;
m.setEDNSSubnet(*srcmask, 128);
}
+ if (!nsName.empty()) {
+ m.setMeta("nsName", {nsName}, {});
+ }
for (auto& logger : *outgoingLoggers) {
if (logger->logQueries()) {
remoteLoggerQueueData(*logger, buffer);
}
}
-static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const boost::optional<const boost::uuids::uuid&>& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, const boost::optional<Netmask>& srcmask, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes)
+static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const boost::optional<const boost::uuids::uuid&>& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, const boost::optional<Netmask>& srcmask, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes, const std::string& nsName)
{
if (!outgoingLoggers) {
return;
if (srcmask) {
m.setEDNSSubnet(*srcmask, 128);
}
+ if (!nsName.empty()) {
+ m.setMeta("nsName", {nsName}, {});
+ }
m.startResponse();
m.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
}
for (const auto& record : records) {
- m.addRR(record, exportTypes, false);
+ m.addRR(record, exportTypes, std::nullopt);
}
m.commitResponse();
uint16_t qid = dns_random_uint16();
DNSPacketWriter pw(vpacket, domain, type);
bool dnsOverTLS = SyncRes::s_dot_to_port_853 && address.getPort() == 853;
+ std::string nsName;
+ if (!context.d_nsName.empty()) {
+ nsName = context.d_nsName.toStringNoDot();
+ }
pw.getHeader()->rd = sendRDQuery;
pw.getHeader()->id = qid;
if (outgoingLoggers) {
uuid = getUniqueID();
- logOutgoingQuery(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, vpacket.size(), srcmask);
+ logOutgoingQuery(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, vpacket.size(), srcmask, nsName);
}
srcmask = boost::none; // this is also our return value, even if EDNS0Level == 0
if (!doTCP) {
int queryfd;
- ret = asendto(vpacket.data(), vpacket.size(), 0, address, qid, domain, type, weWantEDNSSubnet, &queryfd);
+ ret = asendto(vpacket.data(), vpacket.size(), 0, address, qid, domain, type, weWantEDNSSubnet, &queryfd, *now);
if (ret != LWResult::Result::Success) {
return ret;
}
- if (queryfd == -1) {
+ if (queryfd <= -1) {
*chained = true;
}
// peer has closed it on error, so we retry. At some point we
// *will* get a new connection, so this loop is not endless.
isNew = true; // tcpconnect() might throw for new connections. In that case, we want to break the loop, scanbuild complains here, which is a false positive afaik
- std::string nsName;
- if (!context.d_nsName.empty()) {
- nsName = context.d_nsName.toStringNoDot();
- }
isNew = tcpconnect(address, connection, dnsOverTLS, nsName);
ret = tcpsendrecv(address, connection, localip, vpacket, len, buf);
#ifdef HAVE_FSTRM
if (ret != LWResult::Result::Success) { // includes 'timeout'
if (outgoingLoggers) {
- logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, 0, -1, {}, queryTime, exportTypes);
+ logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, 0, -1, {}, queryTime, exportTypes, nsName);
}
return ret;
}
+ if (*chained) {
+ auto msec = lwr->d_usec / 1000;
+ if (msec > g_networkTimeoutMsec * 2 / 3) {
+ auto jitterMsec = dns_random(msec);
+ if (jitterMsec > 0) {
+ mthreadSleep(jitterMsec);
+ }
+ }
+ }
+
buf.resize(len);
#ifdef HAVE_FSTRM
if (mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
if (outgoingLoggers) {
- logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+ logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes, nsName);
}
lwr->d_validpacket = true;
return LWResult::Result::Success; // this is "success", the error is set in lwr->d_rcode
}
lwr->d_records.reserve(mdp.d_answers.size());
- for (const auto& a : mdp.d_answers)
- lwr->d_records.push_back(a.first);
+ for (const auto& answer : mdp.d_answers) {
+ lwr->d_records.push_back(answer);
+ }
EDNSOpts edo;
if (EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
}
if (outgoingLoggers) {
- logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+ logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes, nsName);
}
lwr->d_validpacket = true;
t_Counters.at(rec::Counter::serverParseError)++;
if (outgoingLoggers) {
- logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+ logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes, nsName);
}
return LWResult::Result::Success; // success - oddly enough
Success = 1,
PermanentError = 2 /* not transport related */,
OSLimitError = 3,
- Spoofed = 4 /* Spoofing attempt (too many near-misses) */
+ Spoofed = 4, /* Spoofing attempt (too many near-misses) */
+ ChainLimitError = 5,
};
+ [[nodiscard]] static bool isLimitError(Result res)
+ {
+ return res == Result::OSLimitError || res == Result::ChainLimitError;
+ }
+
vector<DNSRecord> d_records;
int d_rcode{0};
bool d_validpacket{false};
};
LWResult::Result asendto(const void* data, size_t len, int flags, const ComboAddress& toAddress, uint16_t qid,
- const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc);
+ const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc, timeval& now);
LWResult::Result arecvfrom(PacketBuffer& packet, int flags, const ComboAddress& fromAddr, size_t& len, uint16_t qid,
const DNSName& domain, uint16_t qtype, int fileDesc, const struct timeval& now);
--- /dev/null
+../../meson
\ No newline at end of file
--- /dev/null
+project(
+ 'pdns-recursor',
+ ['c', 'cpp'],
+ version: run_command('../../builder-support' / 'gen-version', check: true).stdout().strip(),
+ license: 'GPLv2',
+ license_files: 'NOTICE',
+ meson_version: '>= 1.2.1',
+ default_options: [
+ 'buildtype=debugoptimized',
+ 'warning_level=2', # TODO Move this to 3 to enable -Wpedantic
+ 'cpp_std=c++17',
+ ],
+)
+add_project_arguments('-DRECURSOR', language: 'cpp')
+
+
+product_source_dir = meson.current_source_dir()
+product_build_dir = meson.current_build_dir()
+summary('Source Dir', product_source_dir, section: 'Build')
+summary('Build Dir', product_build_dir, section: 'Build')
+
+# Create the configuration object and dependencies list.
+conf = configuration_data()
+conf.set_quoted('PACKAGE_STRING', meson.project_version(), description: 'version')
+conf.set_quoted('NODCACHEDIRNOD', get_option('localstatedir') + '/nod', description: 'NOD data directory')
+conf.set_quoted('NODCACHEDIRUDR', get_option('localstatedir') + '/udr', description: 'NDR data directory')
+
+# Feature detection and system configuration
+subdir('meson' / 'config') # Config
+subdir('meson' / 'version') # Generate version define
+subdir('meson' / 'compiler-setup') # Common compiler setup
+subdir('meson' / 'summary') # Print a system/project summary
+subdir('meson' / 'sysconfdir') # Sysconfdir
+subdir('meson' / 'platform') # Platform detection
+subdir('meson' / 'timet-size') # Check the size of time_t
+subdir('meson' / 'timet-sign') # Check the sign of time_t
+subdir('meson' / 'atomics') # Check atomics support
+subdir('meson' / 'pthread-headers') # Check pthread headers
+subdir('meson' / 'pthread-setname') # Pthread setname madness
+subdir('meson' / 'pthread-np') # Pthread _np functions
+subdir('meson' / 'strerror') # Strerror_r
+subdir('meson' / 'lua') # Lua
+subdir('meson' / 'hardening') # Hardening
+subdir('meson' / 'net-libs') # Network Libraries
+subdir('meson' / 'tm-gmtoff') # Check for tm_gmtoff field in struct tm
+subdir('meson' / 'mmap') # Check for mmap
+subdir('meson' / 'libsodium') # Libsodium-based signers
+subdir('meson' / 'libdecaf') # Libdecaf-based signers
+subdir('meson' / 'libcrypto') # OpenSSL-based signers
+subdir('meson' / 'libssl') # OpenSSL libssl
+subdir('meson' / 'libsnmp') # SNMP
+subdir('meson' / 'dot') # DNS over TLS
+subdir('meson' / 'clock-gettime') # Clock_gettime
+subdir('meson' / 'boost') # Boost
+subdir('meson' / 'boost-context') # Boost Context Switching Library
+subdir('meson' / 'boost-test') # Boost Testing Library
+subdir('meson' / 'boost-filesystem') # Boost File System Library
+subdir('meson' / 'reproducible') # Reproducible Builds
+subdir('meson' / 'libsystemd') # Systemd notification
+subdir('meson' / 'systemd') # Systemd and unit file handling
+subdir('meson' / 'code-coverage') # Code coverage
+subdir('meson' / 'auto-var-init') # Automatic Variable Initialization
+subdir('meson' / 'sanitizers') # Sanitizers
+subdir('meson' / 'malloc-trace') # Malloc-trace
+subdir('meson' / 'socket-dir') # Socket Dir
+subdir('meson' / 'various-functions') # Various Functions
+subdir('meson' / 'various-headers') # Various Headers
+subdir('meson' / 'libresolv') # res_query
+subdir('meson' / 'dnstap') # DNSTAP through libfstream
+subdir('meson' / 'libcurl') # Curl
+
+subdir('settings')
+
+common_sources = []
+
+fs = import('fs')
+src_dir = fs.is_dir('.') ? '.' : ''
+docs_dir = 'docs'
+# Toplevel includes
+dep_pdns = declare_dependency(include_directories: include_directories('.', src_dir))
+
+# Ext
+subdir('ext' / 'arc4random')
+subdir('ext' / 'json11')
+subdir('ext' / 'luawrapper')
+subdir('ext' / 'protozero')
+subdir('ext' / 'probds')
+subdir('ext' / 'yahttp')
+subdir('meson' / 'nod') # Newly Observed Domains
+
+common_sources += files(
+ src_dir / 'aggressive_nsec.cc',
+ src_dir / 'arguments.cc',
+ src_dir / 'axfr-retriever.cc',
+ src_dir / 'base32.cc',
+ src_dir / 'base64.cc',
+ src_dir / 'coverage.cc',
+ src_dir / 'credentials.cc',
+ src_dir / 'dns.cc',
+ src_dir / 'dnsname.cc',
+ src_dir / 'dnsparser.cc',
+ src_dir / 'dnsrecords.cc',
+ src_dir / 'dnssecinfra.cc',
+ src_dir / 'dnswriter.cc',
+ src_dir / 'ednsextendederror.cc',
+ src_dir / 'ednsoptions.cc',
+ src_dir / 'ednspadding.cc',
+ src_dir / 'ednssubnet.cc',
+ src_dir / 'filterpo.cc',
+ src_dir / 'gettime.cc',
+ src_dir / 'gss_context.cc',
+ src_dir / 'iputils.cc',
+ src_dir / 'ixfr.cc',
+ src_dir / 'json.cc',
+ src_dir / 'libssl.cc',
+ src_dir / 'logger.cc',
+ src_dir / 'logging.cc',
+ src_dir / 'lua-base4.cc',
+ src_dir / 'lua-recursor4.cc',
+ src_dir / 'lwres.cc',
+ src_dir / 'misc.cc',
+ src_dir / 'mtasker_context.cc',
+ src_dir / 'negcache.cc',
+ src_dir / 'nsecrecords.cc',
+ src_dir / 'protozero.cc',
+ src_dir / 'proxy-protocol.cc',
+ src_dir / 'pubsuffixloader.cc',
+ src_dir / 'qtype.cc',
+ src_dir / 'query-local-address.cc',
+ src_dir / 'rcpgenerator.cc',
+ src_dir / 'rec-carbon.cc',
+ src_dir / 'rec-eventtrace.cc',
+ src_dir / 'rec-lua-conf.cc',
+ src_dir / 'rec-protozero.cc',
+ src_dir / 'rec-responsestats.cc',
+ src_dir / 'rec-system-resolve.cc',
+ src_dir / 'rec-taskqueue.cc',
+ src_dir / 'rec-tcounters.cc',
+ src_dir / 'rec-zonetocache.cc',
+ src_dir / 'rec_channel.cc',
+ src_dir / 'rec_channel_rec.cc',
+ src_dir / 'recpacketcache.cc',
+ src_dir / 'recursor_cache.cc',
+ src_dir / 'reczones-helpers.cc',
+ src_dir / 'reczones.cc',
+ src_dir / 'remote_logger.cc',
+ src_dir / 'resolver.cc',
+ src_dir / 'rpzloader.cc',
+ src_dir / 'secpoll-recursor.cc',
+ src_dir / 'secpoll.cc',
+ src_dir / 'shuffle.cc',
+ src_dir / 'sillyrecords.cc',
+ src_dir / 'snmp-agent.cc',
+ src_dir / 'sortlist.cc',
+ src_dir / 'svc-records.cc',
+ src_dir / 'syncres.cc',
+ src_dir / 'taskqueue.cc',
+ src_dir / 'tcpiohandler.cc',
+ src_dir / 'threadname.cc',
+ src_dir / 'tsigverifier.cc',
+ src_dir / 'unix_utility.cc',
+ src_dir / 'uuid-utils.cc',
+ src_dir / 'validate.cc',
+ src_dir / 'validate-recursor.cc',
+ src_dir / 'version.cc',
+ src_dir / 'webserver.cc',
+ src_dir / 'ws-api.cc',
+ src_dir / 'ws-recursor.cc',
+ src_dir / 'zonemd.cc',
+ src_dir / 'zoneparser-tng.cc',
+)
+
+conditional_sources = {
+ 'minicurl': {
+ 'sources': [
+ src_dir / 'minicurl.cc',
+ src_dir / 'minicurl.hh',
+ ],
+ 'condition': dep_libcurl.found(),
+ },
+ 'dnstap': {
+ 'sources': [
+ src_dir / 'dnstap.cc',
+ src_dir / 'fstrm_logger.cc',
+ ],
+ 'condition': dep_dnstap.found(),
+ },
+ 'nod': {
+ 'sources': [
+ src_dir / 'nod.cc',
+ ],
+ 'condition': dep_nod.found(),
+ },
+}
+
+foreach name, info: conditional_sources
+ if info['condition']
+ common_sources += files(info['sources'])
+ endif
+endforeach
+
+mplexer_sources = [src_dir / 'pollmplexer.cc']
+if have_linux
+ mplexer_sources += src_dir / 'epollmplexer.cc'
+endif
+if have_darwin
+ mplexer_sources += src_dir / 'kqueuemplexer.cc'
+endif
+if have_openbsd
+ mplexer_sources += src_dir / 'kqueuemplexer.cc'
+endif
+if have_freebsd
+ mplexer_sources += src_dir / 'kqueuemplexer.cc'
+endif
+if have_sunos
+ mplexer_sources += src_dir / 'devpollmplexer.cc'
+ mplexer_sources += src_dir / 'portsmplexer.cc'
+endif
+
+# Generate config.h
+config_h = configure_file(configuration: conf, output: 'config.h')
+
+sh_program = find_program('sh')
+dep_no_config_in_source_check = custom_target(
+ input: [],
+ output: ['check absense of config.h file in source directory'],
+ command: [sh_program, '-c', 'test ! -e @SOURCE_ROOT@/config.h'],
+ build_always_stale: true,
+)
+dep_no_config_in_source = declare_dependency(
+ sources: dep_no_config_in_source_check
+)
+
+html_sources = [
+ src_dir / 'html/index.html',
+ src_dir / 'html/local-2022.js',
+ src_dir / 'html/js/rickshaw.min.js',
+ src_dir / 'html/js/moment.js',
+ src_dir / 'html/js/rickshaw.js',
+ src_dir / 'html/js/d3.v3.js',
+ src_dir / 'html/js/handlebars-v4.0.11.js',
+ src_dir / 'html/js/handlebars-v4.0.11-min.js',
+ src_dir / 'html/js/d3.v3-min.js',
+ src_dir / 'html/js/moment.min.js',
+ src_dir / 'html/lines.css',
+ src_dir / 'html/legend.css',
+ src_dir / 'html/styling.css',
+ src_dir / 'html/detail.css',
+ src_dir / 'html/graph.css',
+ src_dir / 'html/powerdns-logo-220px.png',
+]
+
+incfiles = find_program('incfiles')
+
+htmlfiles = custom_target(
+ command: [incfiles, '@SOURCE_ROOT@'],
+ input: html_sources,
+ output: 'htmlfiles.h',
+ capture: true
+)
+
+dep_htmlfiles = declare_dependency(
+ sources: [htmlfiles],
+)
+
+deps = [
+ dep_pdns,
+ dep_no_config_in_source,
+ dep_rust_settings,
+ dep_boost,
+ dep_boost_context,
+ dep_threads,
+ dep_json11,
+ dep_libcrypto,
+ dep_libresolv,
+ dep_libsnmp,
+ dep_libsodium,
+ dep_libssl,
+ dep_lua,
+ dep_protozero,
+ dep_yahttp,
+ dep_htmlfiles,
+ dep_dnstap,
+ dep_libcurl,
+]
+
+# Conditional sources that need to be separated into standalone libraries for special
+# linking without implicitly getting rid of symbols.
+librec_signers_sodium = dependency('', required: false)
+if dep_libsodium.found()
+ librec_signers_sodium = declare_dependency(
+ link_whole: static_library(
+ 'rec-signers-sodium',
+ sources: files(src_dir / 'sodiumsigners.cc'),
+ dependencies: [dep_boost, dep_libsodium],
+ )
+ )
+endif
+
+librec_signers_decaf = dependency('', required: false)
+if dep_libdecaf.found()
+ librec_signers_decaf = declare_dependency(
+ link_whole: static_library(
+ 'rec-signers-decaf',
+ sources: files(src_dir / 'decafsigners.cc'),
+ dependencies: [dep_boost, dep_libdecaf],
+ )
+ )
+endif
+
+librec_signers_openssl = declare_dependency(
+ link_whole: static_library(
+ 'rec-signers-openssl',
+ sources: files(src_dir / 'opensslsigners.cc'),
+ dependencies: [dep_boost, dep_libssl],
+ )
+)
+
+# If we have pubsuffix.cc in the source tree, use it. Otherwise download and build it.
+pubsuffix_dl_source = 'effective_tld_names.dat'
+pubsuffix_cc = src_dir / 'pubsuffix.cc'
+if not fs.is_file(pubsuffix_cc)
+ curl_command = find_program('curl', required: true)
+ pubsuffix_dl_source = custom_target(
+ 'pubsuffix-dl',
+ command: [curl_command, '-s', '-S', '-o', '@OUTPUT@', 'https://publicsuffix.org/list/public_suffix_list.dat'],
+ output: pubsuffix_dl_source
+ )
+
+ mkpubsuffix_command = find_program('mkpubsuffixcc', required: true)
+ pubsuffix_cc = custom_target(
+ 'pubsuffix-cc',
+ command: [mkpubsuffix_command, '@INPUT@', '@OUTPUT@'],
+ input: pubsuffix_dl_source,
+ output: 'pubsuffix.cc',
+ )
+endif
+
+dep_pubsuffix = declare_dependency(
+ sources: pubsuffix_cc
+)
+
+librec_dnslabeltext_source = src_dir / 'dnslabeltext.rl'
+librec_dnslabeltext_gen = src_dir / 'dnslabeltext.cc'
+if not fs.is_file(librec_dnslabeltext_gen)
+ ragel = find_program('ragel', required: true)
+
+ summary('Ragel', ragel.found(), bool_yn: ragel.found(), section: 'DNS Labels')
+ summary('Ragel Path', ragel.full_path(), section: 'DNS Labels')
+ summary('Ragel Version', ragel.version(), section: 'DNS Labels')
+
+ ragel_generator = generator(
+ ragel,
+ output: '@BASENAME@.cc',
+ arguments: ['@INPUT@', '-o', '@OUTPUT@'],
+ )
+
+ librec_dnslabeltext_gen = ragel_generator.process(librec_dnslabeltext_source)
+endif
+
+librec_dnslabeltext = declare_dependency(
+ link_with: static_library(
+ 'rec-dnslabeltext',
+ librec_dnslabeltext_gen,
+ dependencies: deps,
+ )
+)
+
+librec_common = declare_dependency(
+ link_with: static_library(
+ 'rec-common',
+ common_sources,
+ config_h,
+ dependencies: [
+ deps,
+ dep_settings_ch,
+ librec_dnslabeltext,
+ ],
+ )
+)
+
+tools = {
+ 'pdns_recursor': {
+ 'main': src_dir / 'rec-main.cc',
+ 'files-extra': [
+ src_dir / 'capabilities.cc',
+ src_dir / 'channel.cc',
+ src_dir / 'pdns_recursor.cc',
+ src_dir / 'rec-tcp.cc',
+ src_dir / 'rec-tcpout.cc',
+ src_dir / 'rec-snmp.cc',
+ src_dir / 'rec-tcp.cc',
+ mplexer_sources,
+ ],
+ 'manpages': ['pdns_recursor.1'],
+ 'deps-extra': [
+ dep_boost,
+ dep_nod,
+ dep_lua,
+ dep_protozero,
+ dep_yahttp,
+ dep_json11,
+ dep_settings,
+ dep_rust_settings,
+ dep_systemd,
+ librec_signers_openssl,
+ librec_signers_decaf,
+ librec_signers_sodium,
+ dep_pubsuffix,
+ ],
+ },
+ 'rec_control': {
+ 'main': src_dir / 'rec_control.cc',
+ 'manpages': ['rec_control.1'],
+ 'deps-extra': [
+ dep_boost,
+ dep_settings,
+ dep_rust_settings,
+ ],
+ },
+}
+
+test_sources = []
+test_sources += files(
+ src_dir / 'ednscookies.cc',
+ src_dir / 'test-aggressive_nsec_cc.cc',
+ src_dir / 'test-arguments_cc.cc',
+ src_dir / 'test-base32_cc.cc',
+ src_dir / 'test-base64_cc.cc',
+ src_dir / 'test-common.hh',
+ src_dir / 'test-credentials_cc.cc',
+ src_dir / 'test-dns_random_hh.cc',
+ src_dir / 'test-dnsname_cc.cc',
+ src_dir / 'test-dnsparser_hh.cc',
+ src_dir / 'test-dnsrecordcontent.cc',
+ src_dir / 'test-dnsrecords_cc.cc',
+ src_dir / 'test-ednsoptions_cc.cc',
+ src_dir / 'test-filterpo_cc.cc',
+ src_dir / 'test-histogram_hh.cc',
+ src_dir / 'test-iputils_hh.cc',
+ src_dir / 'test-ixfr_cc.cc',
+ src_dir / 'test-luawrapper.cc',
+ src_dir / 'test-misc_hh.cc',
+ src_dir / 'test-mplexer.cc',
+ src_dir / 'test-mtasker.cc',
+ src_dir / 'test-negcache_cc.cc',
+ src_dir / 'test-packetcache_hh.cc',
+ src_dir / 'test-rcpgenerator_cc.cc',
+ src_dir / 'test-rec-system-resolve.cc',
+ src_dir / 'test-rec-taskqueue.cc',
+ src_dir / 'test-rec-tcounters_cc.cc',
+ src_dir / 'test-rec-zonetocache.cc',
+ src_dir / 'test-recpacketcache_cc.cc',
+ src_dir / 'test-recursorcache_cc.cc',
+ src_dir / 'test-reczones-helpers.cc',
+ src_dir / 'test-rpzloader_cc.cc',
+ src_dir / 'test-secpoll_cc.cc',
+ src_dir / 'test-settings.cc',
+ src_dir / 'test-signers.cc',
+ src_dir / 'test-syncres_cc.cc',
+ src_dir / 'test-syncres_cc.hh',
+ src_dir / 'test-syncres_cc1.cc',
+ src_dir / 'test-syncres_cc10.cc',
+ src_dir / 'test-syncres_cc2.cc',
+ src_dir / 'test-syncres_cc3.cc',
+ src_dir / 'test-syncres_cc4.cc',
+ src_dir / 'test-syncres_cc5.cc',
+ src_dir / 'test-syncres_cc6.cc',
+ src_dir / 'test-syncres_cc7.cc',
+ src_dir / 'test-syncres_cc8.cc',
+ src_dir / 'test-syncres_cc9.cc',
+ src_dir / 'test-tsig.cc',
+)
+
+if enable_nod
+ test_sources += files(src_dir / 'test-nod_cc.cc')
+endif
+
+if get_option('unit-tests')
+ librec_test = declare_dependency(
+ link_whole: static_library(
+ 'rec-test',
+ config_h,
+ test_sources,
+ dependencies: [
+ dep_boost,
+ dep_boost_test,
+ dep_lua,
+ dep_nod,
+ dep_settings,
+ dep_rust_settings,
+ librec_signers_openssl,
+ librec_signers_decaf,
+ librec_signers_sodium,
+ ],
+ )
+ )
+ tools += {
+ 'testrunner': {
+ 'main': [
+ src_dir / 'testrunner.cc',
+ mplexer_sources,
+ ],
+ 'deps-extra': [
+ librec_test,
+ dep_boost_test,
+ ],
+ }
+ }
+endif
+
+man_pages = []
+foreach tool, info: tools
+ var_name = tool.underscorify()
+ main = files(info['main'])
+
+ export_dynamic = 'export-dynamic' in info ? info['export-dynamic'] : false
+ files_extra = 'files-extra' in info ? info['files-extra'] : []
+ deps_extra = 'deps-extra' in info ? info['deps-extra'] : []
+
+ set_variable(
+ var_name,
+ executable(
+ tool,
+ main,
+ config_h,
+ files_extra,
+ export_dynamic: export_dynamic,
+ dependencies: [
+ librec_common,
+ deps_extra,
+ ],
+ )
+ )
+
+ if 'manpages' in info
+ foreach man_page: info['manpages']
+ man_pages += docs_dir / 'manpages' / (man_page + '.rst')
+ endforeach
+ endif
+endforeach
+
+# Man-pages.
+py = import('python')
+python = py.find_installation('python3', modules: 'venv', required: false)
+
+summary('Python', python.found(), bool_yn: true, section: 'Manual Pages')
+summary('Path', python.full_path(), section: 'Manual Pages')
+summary('Version', python.version(), section: 'Manual Pages')
+
+if python.found()
+ run_target(
+ 'man-pages',
+ command: [
+ python,
+ product_source_dir / docs_dir / 'generate-man-pages.py',
+ '--venv-name', 'venv-rec-man-pages',
+ '--requirements-file', docs_dir / 'requirements.txt',
+ '--source-directory', docs_dir,
+ '--target-directory', 'rec-man-pages',
+ ] + man_pages,
+ )
+endif
--- /dev/null
+option('lua', type: 'combo', choices: ['auto', 'luajit', 'lua'], value: 'auto', description: 'Lua implementation to use')
+option('hardening', type: 'feature', value: 'auto', description: 'Compiler security checks')
+option('hardening-experimental-cf', type: 'combo', choices: ['disabled', 'full', 'branch', 'return', 'check'], value: 'disabled', description: 'Control Flow hardening')
+option('hardening-experimental-scp', type: 'feature', value: 'disabled', description: 'Stack Clash Protection')
+option('hardening-fortify-source', type: 'combo', choices: ['auto', 'disabled', '1', '2', '3'], value: '2', description: 'Source fortification level')
+#option('rng-kiss', type: 'boolean', value: false, description: 'Use the unsafe KISS RNG')
+option('signers-libsodium', type: 'feature', value: 'auto', description: 'Enable libsodium-based signers')
+option('signers-libdecaf', type: 'feature', value: 'auto', description: 'Enable libdecaf-based signers')
+option('signers-libcrypto', type: 'feature', value: 'auto', description: 'Enable OpenSSL libcrypto-based signers)')
+option('signers-libcrypto-path', type: 'string', value: '', description: 'Custom path to find OpenSSL libcrypto')
+option('tls-libssl', type: 'feature', value: 'auto', description: 'OpenSSL-based TLS')
+option('dns-over-tls', type: 'boolean', value: false, description: 'DNS over TLS (requires GnuTLS or OpenSSL)')
+option('unit-tests', type: 'boolean', value: false, description: 'Build and run unit tests')
+# not relevant for rec, but accessed by boost meson.build
+option('unit-tests-backends', type: 'boolean', value: false, description: 'Build and run backend unit tests')
+option('reproducible', type: 'boolean', value: false, description: 'Reproducible builds (for distro maintainers, makes debugging difficult)')
+option('systemd', type: 'feature', value: 'auto', description: 'Systemd notification (requires libsystemd)')
+option('systemd-service-user', type: 'string', value: 'pdns', description: 'Systemd service user (setuid and unit file; user is not created)')
+option('systemd-service-group', type: 'string', value: 'pdns', description: 'Systemd service group (setgid and unit file; group is not created)')
+option('auto-var-init', type: 'combo', value: 'disabled', choices: ['zero', 'pattern', 'disabled'], description: 'Enable initialization of automatic variables')
+option('malloc-trace', type: 'boolean', value: false, description: 'Enable malloc-trace')
+option('socket-dir', type: 'string', value: '/var/run', description: 'Where the control socket lives')
+option('snmp', type: 'boolean', value: false, description: 'Enable SNMP')
+option('dnstap', type: 'feature', value: 'auto', description: 'Enable DNSTAP support through libfstrm')
+option('libcurl', type: 'feature', value: 'auto', description: 'Enable Curl support')
+option('nod', type: 'boolean', value: true, description: 'Enable Newly Obserbed Domains')
}
using tfunc_t = void(void*); //!< type of the pointer that starts a thread
+ uint64_t nextWaiterDelayUsec(uint64_t defusecs);
int waitEvent(EventKey& key, EventVal* val = nullptr, unsigned int timeoutMsec = 0, const struct timeval* now = nullptr);
void yield();
int sendEvent(const EventKey& key, const EventVal* val = nullptr);
#include <valgrind/valgrind.h>
#endif /* PDNS_USE_VALGRIND */
+template <class EventKey, class EventVal, class Cmp>
+uint64_t MTasker<EventKey, EventVal, Cmp>::nextWaiterDelayUsec(uint64_t defusecs)
+{
+ if (d_waiters.empty()) {
+ // no waiters
+ return defusecs;
+ }
+ auto& ttdindex = boost::multi_index::get<KeyTag>(d_waiters);
+ auto iter = ttdindex.begin();
+ timeval rnow{};
+ gettimeofday(&rnow, nullptr);
+ if (iter->ttd.tv_sec != 0) {
+ // we have a waiter with a timeout specified
+ if (rnow < iter->ttd) {
+ // we should not wait longer than the default timeout
+ return std::min(defusecs, uSec(iter->ttd - rnow));
+ }
+ // already expired
+ return 0;
+ }
+ return defusecs;
+}
+
//! puts a thread to sleep waiting until a specified event arrives
/** Threads can call waitEvent to register that they are waiting on an event with a certain key.
If so desired, the event can carry data which is returned in val in case that is non-zero.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifdef HAVE_CONFIG_H
+
#include "config.h"
+#include "mtasker_context.hh"
+#include <exception>
+#include <cassert>
+#include <type_traits>
+#include <boost/version.hpp>
+#if BOOST_VERSION < 106100
+#include <boost/context/fcontext.hpp>
+using boost::context::make_fcontext;
+#else
+#include <boost/context/detail/fcontext.hpp>
+using boost::context::detail::make_fcontext;
+#endif /* BOOST_VERSION < 106100 */
+
+// __CET__ is set by the compiler if relevant, so far only relevant/tested for amd64 on OpenBSD
+#if defined(__amd64__)
+#if __CET__ & 0x1
+#define CET_ENDBR __asm("endbr64")
+#else
+#define CET_ENDBR
+#endif
+#else
+#define CET_ENDBR
+#endif
+
+#ifdef PDNS_USE_VALGRIND
+#include <valgrind/valgrind.h>
+#endif /* PDNS_USE_VALGRIND */
+
+#ifdef HAVE_FIBER_SANITIZER
+__thread void* t_mainStack{nullptr};
+__thread size_t t_mainStackSize{0};
+#endif /* HAVE_FIBER_SANITIZER */
+
+#if BOOST_VERSION < 105600
+/* Note: This typedef means functions taking fcontext_t*, like jump_fcontext(),
+ * now require a reinterpret_cast rather than a static_cast, since we're
+ * casting from pdns_context_t->uc_mcontext, which is void**, to
+ * some_opaque_struct**. In later versions fcontext_t is already void*. So if
+ * you remove this, then fix the ugly.
+ */
+using fcontext_t = boost::context::fcontext_t*;
+
+/* Emulate the >= 1.56 API for Boost 1.52 through 1.55 */
+static inline intptr_t
+jump_fcontext(fcontext_t* const ofc, fcontext_t const nfc,
+ intptr_t const arg)
+{
+ /* If the fcontext_t is preallocated then use it, otherwise allocate one
+ * on the stack ('self') and stash a pointer away in *ofc so the returning
+ * MThread can access it. This is safe because we're suspended, so the
+ * context object always outlives the jump.
+ */
+ if (*ofc) {
+ return boost::context::jump_fcontext(*ofc, nfc, arg);
+ }
+ else {
+ boost::context::fcontext_t self;
+ *ofc = &self;
+ auto ret = boost::context::jump_fcontext(*ofc, nfc, arg);
+ *ofc = nullptr;
+ return ret;
+ }
+}
+#else
+
+#if BOOST_VERSION < 106100
+using boost::context::fcontext_t;
+using boost::context::jump_fcontext;
+#else
+using boost::context::detail::fcontext_t;
+using boost::context::detail::jump_fcontext;
+using boost::context::detail::transfer_t;
+#endif /* BOOST_VERSION < 106100 */
+
+static_assert(std::is_pointer<fcontext_t>::value,
+ "Boost Context has changed the fcontext_t type again :-(");
+#endif
+
+/* Boost context only provides a means of passing a single argument across a
+ * jump. args_t simply provides a way to pass more by reference.
+ */
+struct args_t
+{
+#if BOOST_VERSION < 106100
+ fcontext_t prev_ctx = nullptr;
+#endif
+ pdns_ucontext_t* self = nullptr;
+ std::function<void(void)>* work = nullptr;
+};
+
+extern "C"
+{
+ static void
+#if BOOST_VERSION < 106100
+ threadWrapper(intptr_t const xargs)
+ {
+#else
+ threadWrapper(transfer_t const theThread)
+ {
+#endif
+ /* Access the args passed from pdns_makecontext, and copy them directly from
+ * the calling stack on to ours (we're now using the MThreads stack).
+ * This saves heap allocating an args object, at the cost of an extra
+ * context switch to fashion this constructor-like init phase. The work
+ * function object is still only moved after we're (re)started, so may
+ * still be set or changed after a call to pdns_makecontext. This matches
+ * the behaviour of the System V implementation, which can inherently only
+ * be passed ints and pointers.
+ */
+ notifyStackSwitchDone();
+#if BOOST_VERSION < 106100
+ auto* args = reinterpret_cast<args_t*>(xargs);
+#else
+ auto* args = static_cast<args_t*>(theThread.data);
+#endif
+ auto* ctx = args->self;
+ auto* work = args->work;
+ /* we switch back to pdns_makecontext() */
+ notifyStackSwitchToKernel();
+#if BOOST_VERSION < 106100
+ jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
+ static_cast<fcontext_t>(args->prev_ctx), 0);
+#else
+ transfer_t res = jump_fcontext(theThread.fctx, nullptr);
+ CET_ENDBR;
+ /* we got switched back from pdns_swapcontext() */
+ if (res.data != nullptr) {
+ /* if res.data is not a nullptr, it holds a pointer to the context
+ we just switched from, and we need to fill it to be able to
+ switch back to it later. */
+ auto* ptr = static_cast<fcontext_t*>(res.data);
+ *ptr = res.fctx;
+ }
+#endif
+ notifyStackSwitchDone();
+ args = nullptr;
+
+ try {
+ auto start = std::move(*work);
+ start();
+ }
+ catch (...) {
+ ctx->exception = std::current_exception();
+ }
+
+ notifyStackSwitchToKernel();
+ /* Emulate the System V uc_link feature. */
+ auto* const next_ctx = ctx->uc_link->uc_mcontext;
+#if BOOST_VERSION < 106100
+ jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
+ static_cast<fcontext_t>(next_ctx),
+ reinterpret_cast<intptr_t>(ctx));
+#else
+ jump_fcontext(static_cast<fcontext_t>(next_ctx), nullptr);
+#endif
+
+#ifdef NDEBUG
+ __builtin_unreachable();
+#endif
+ }
+}
+
+pdns_ucontext_t::pdns_ucontext_t() :
+ uc_mcontext(nullptr), uc_link(nullptr)
+{
+#ifdef PDNS_USE_VALGRIND
+ valgrind_id = 0;
+#endif /* PDNS_USE_VALGRIND */
+}
+
+#ifdef PDNS_USE_VALGRIND
+pdns_ucontext_t::~pdns_ucontext_t()
+{
+ /* There's nothing to delete here since fcontext doesn't require anything
+ * to be heap allocated.
+ */
+ if (valgrind_id != 0) {
+ VALGRIND_STACK_DEREGISTER(valgrind_id);
+ }
+}
+#else
+pdns_ucontext_t::~pdns_ucontext_t() = default;
+#endif /* PDNS_USE_VALGRIND */
+
+void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
+{
+ /* we either switch back to threadwrapper() if it's the first time,
+ or we switch back to pdns_swapcontext(),
+ in both case we will be returning from a call to jump_fcontext(). */
+#if BOOST_VERSION < 106100
+ intptr_t ptr = jump_fcontext(reinterpret_cast<fcontext_t*>(&octx.uc_mcontext),
+ static_cast<fcontext_t>(ctx.uc_mcontext), 0);
+
+ auto origctx = reinterpret_cast<pdns_ucontext_t*>(ptr);
+ if (origctx && origctx->exception)
+ std::rethrow_exception(origctx->exception);
+#else
+ transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext), &octx.uc_mcontext);
+ CET_ENDBR;
+ if (res.data != nullptr) {
+ /* if res.data is not a nullptr, it holds a pointer to the context
+ we just switched from, and we need to fill it to be able to
+ switch back to it later. */
+ auto* ptr = static_cast<fcontext_t*>(res.data);
+ *ptr = res.fctx;
+ }
+ if (ctx.exception) {
+ std::rethrow_exception(ctx.exception);
+ }
#endif
+}
-#if defined(HAVE_BOOST_CONTEXT)
-#include "mtasker_fcontext.cc" // NOLINT(bugprone-suspicious-include)
+void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
+{
+ // NOLINTBEGIN(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ assert(ctx.uc_link);
+ assert(ctx.uc_stack.size() >= 8192);
+ assert(!ctx.uc_mcontext);
+ // NOLINTEND(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ ctx.uc_mcontext = make_fcontext(&ctx.uc_stack[ctx.uc_stack.size() - 1],
+ ctx.uc_stack.size() - 1, &threadWrapper);
+ args_t args;
+ args.self = &ctx;
+ args.work = &start;
+ /* jumping to threadwrapper */
+ notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size() - 1], ctx.uc_stack.size() - 1);
+#if BOOST_VERSION < 106100
+ jump_fcontext(reinterpret_cast<fcontext_t*>(&args.prev_ctx),
+ static_cast<fcontext_t>(ctx.uc_mcontext),
+ reinterpret_cast<intptr_t>(&args));
#else
-#include "mtasker_ucontext.cc" // NOLINT(bugprone-suspicious-include)
+ transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext),
+ &args);
+ CET_ENDBR;
+ /* back from threadwrapper, updating the context */
+ ctx.uc_mcontext = res.fctx;
#endif
+ notifyStackSwitchDone();
+}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "mtasker_context.hh"
-#include <exception>
-#include <cassert>
-#include <type_traits>
-#include <boost/version.hpp>
-#if BOOST_VERSION < 106100
-#include <boost/context/fcontext.hpp>
-using boost::context::make_fcontext;
-#else
-#include <boost/context/detail/fcontext.hpp>
-using boost::context::detail::make_fcontext;
-#endif /* BOOST_VERSION < 106100 */
-
-// __CET__ is set by the compiler if relevant, so far only relevant/tested for amd64 on OpenBSD
-#if defined(__amd64__)
-#if __CET__ & 0x1
-#define CET_ENDBR __asm("endbr64")
-#else
-#define CET_ENDBR
-#endif
-#else
-#define CET_ENDBR
-#endif
-
-#ifdef PDNS_USE_VALGRIND
-#include <valgrind/valgrind.h>
-#endif /* PDNS_USE_VALGRIND */
-
-#ifdef HAVE_FIBER_SANITIZER
-__thread void* t_mainStack{nullptr};
-__thread size_t t_mainStackSize{0};
-#endif /* HAVE_FIBER_SANITIZER */
-
-#if BOOST_VERSION < 105600
-/* Note: This typedef means functions taking fcontext_t*, like jump_fcontext(),
- * now require a reinterpret_cast rather than a static_cast, since we're
- * casting from pdns_context_t->uc_mcontext, which is void**, to
- * some_opaque_struct**. In later versions fcontext_t is already void*. So if
- * you remove this, then fix the ugly.
- */
-using fcontext_t = boost::context::fcontext_t*;
-
-/* Emulate the >= 1.56 API for Boost 1.52 through 1.55 */
-static inline intptr_t
-jump_fcontext(fcontext_t* const ofc, fcontext_t const nfc,
- intptr_t const arg)
-{
- /* If the fcontext_t is preallocated then use it, otherwise allocate one
- * on the stack ('self') and stash a pointer away in *ofc so the returning
- * MThread can access it. This is safe because we're suspended, so the
- * context object always outlives the jump.
- */
- if (*ofc) {
- return boost::context::jump_fcontext(*ofc, nfc, arg);
- }
- else {
- boost::context::fcontext_t self;
- *ofc = &self;
- auto ret = boost::context::jump_fcontext(*ofc, nfc, arg);
- *ofc = nullptr;
- return ret;
- }
-}
-#else
-
-#if BOOST_VERSION < 106100
-using boost::context::fcontext_t;
-using boost::context::jump_fcontext;
-#else
-using boost::context::detail::fcontext_t;
-using boost::context::detail::jump_fcontext;
-using boost::context::detail::transfer_t;
-#endif /* BOOST_VERSION < 106100 */
-
-static_assert(std::is_pointer<fcontext_t>::value,
- "Boost Context has changed the fcontext_t type again :-(");
-#endif
-
-/* Boost context only provides a means of passing a single argument across a
- * jump. args_t simply provides a way to pass more by reference.
- */
-struct args_t
-{
-#if BOOST_VERSION < 106100
- fcontext_t prev_ctx = nullptr;
-#endif
- pdns_ucontext_t* self = nullptr;
- std::function<void(void)>* work = nullptr;
-};
-
-extern "C"
-{
- static void
-#if BOOST_VERSION < 106100
- threadWrapper(intptr_t const xargs)
- {
-#else
- threadWrapper(transfer_t const t)
- {
-#endif
- /* Access the args passed from pdns_makecontext, and copy them directly from
- * the calling stack on to ours (we're now using the MThreads stack).
- * This saves heap allocating an args object, at the cost of an extra
- * context switch to fashion this constructor-like init phase. The work
- * function object is still only moved after we're (re)started, so may
- * still be set or changed after a call to pdns_makecontext. This matches
- * the behaviour of the System V implementation, which can inherently only
- * be passed ints and pointers.
- */
- notifyStackSwitchDone();
-#if BOOST_VERSION < 106100
- auto args = reinterpret_cast<args_t*>(xargs);
-#else
- auto args = reinterpret_cast<args_t*>(t.data);
-#endif
- auto ctx = args->self;
- auto work = args->work;
- /* we switch back to pdns_makecontext() */
- notifyStackSwitchToKernel();
-#if BOOST_VERSION < 106100
- jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
- static_cast<fcontext_t>(args->prev_ctx), 0);
-#else
- transfer_t res = jump_fcontext(t.fctx, 0);
- CET_ENDBR;
- /* we got switched back from pdns_swapcontext() */
- if (res.data) {
- /* if res.data is not a nullptr, it holds a pointer to the context
- we just switched from, and we need to fill it to be able to
- switch back to it later. */
- fcontext_t* ptr = static_cast<fcontext_t*>(res.data);
- *ptr = res.fctx;
- }
-#endif
- notifyStackSwitchDone();
- args = nullptr;
-
- try {
- auto start = std::move(*work);
- start();
- }
- catch (...) {
- ctx->exception = std::current_exception();
- }
-
- notifyStackSwitchToKernel();
- /* Emulate the System V uc_link feature. */
- auto const next_ctx = ctx->uc_link->uc_mcontext;
-#if BOOST_VERSION < 106100
- jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
- static_cast<fcontext_t>(next_ctx),
- reinterpret_cast<intptr_t>(ctx));
-#else
- jump_fcontext(static_cast<fcontext_t>(next_ctx), 0);
-#endif
-
-#ifdef NDEBUG
- __builtin_unreachable();
-#endif
- }
-}
-
-pdns_ucontext_t::pdns_ucontext_t() :
- uc_mcontext(nullptr), uc_link(nullptr)
-{
-#ifdef PDNS_USE_VALGRIND
- valgrind_id = 0;
-#endif /* PDNS_USE_VALGRIND */
-}
-
-pdns_ucontext_t::~pdns_ucontext_t()
-{
- /* There's nothing to delete here since fcontext doesn't require anything
- * to be heap allocated.
- */
-#ifdef PDNS_USE_VALGRIND
- if (valgrind_id != 0) {
- VALGRIND_STACK_DEREGISTER(valgrind_id);
- }
-#endif /* PDNS_USE_VALGRIND */
-}
-
-void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
-{
- /* we either switch back to threadwrapper() if it's the first time,
- or we switch back to pdns_swapcontext(),
- in both case we will be returning from a call to jump_fcontext(). */
-#if BOOST_VERSION < 106100
- intptr_t ptr = jump_fcontext(reinterpret_cast<fcontext_t*>(&octx.uc_mcontext),
- static_cast<fcontext_t>(ctx.uc_mcontext), 0);
-
- auto origctx = reinterpret_cast<pdns_ucontext_t*>(ptr);
- if (origctx && origctx->exception)
- std::rethrow_exception(origctx->exception);
-#else
- transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext), &octx.uc_mcontext);
- CET_ENDBR;
- if (res.data) {
- /* if res.data is not a nullptr, it holds a pointer to the context
- we just switched from, and we need to fill it to be able to
- switch back to it later. */
- fcontext_t* ptr = static_cast<fcontext_t*>(res.data);
- *ptr = res.fctx;
- }
- if (ctx.exception) {
- std::rethrow_exception(ctx.exception);
- }
-#endif
-}
-
-void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
-{
- assert(ctx.uc_link);
- assert(ctx.uc_stack.size() >= 8192);
- assert(!ctx.uc_mcontext);
- ctx.uc_mcontext = make_fcontext(&ctx.uc_stack[ctx.uc_stack.size() - 1],
- ctx.uc_stack.size() - 1, &threadWrapper);
- args_t args;
- args.self = &ctx;
- args.work = &start;
- /* jumping to threadwrapper */
- notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size() - 1], ctx.uc_stack.size() - 1);
-#if BOOST_VERSION < 106100
- jump_fcontext(reinterpret_cast<fcontext_t*>(&args.prev_ctx),
- static_cast<fcontext_t>(ctx.uc_mcontext),
- reinterpret_cast<intptr_t>(&args));
-#else
- transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext),
- &args);
- CET_ENDBR;
- /* back from threadwrapper, updating the context */
- ctx.uc_mcontext = res.fctx;
-#endif
- notifyStackSwitchDone();
-}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "mtasker_context.hh"
-#include <system_error>
-#include <exception>
-#include <cstring>
-#include <cassert>
-#include <csignal>
-#include <cstdint>
-#include <ucontext.h>
-
-#ifdef PDNS_USE_VALGRIND
-#include <valgrind/valgrind.h>
-#endif /* PDNS_USE_VALGRIND */
-
-#ifdef HAVE_FIBER_SANITIZER
-__thread void* t_mainStack{nullptr};
-__thread size_t t_mainStackSize{0};
-#endif /* HAVE_FIBER_SANITIZER */
-
-template <typename Message>
-static __attribute__((noinline, cold, noreturn)) void
-throw_errno(Message&& msg)
-{
- throw std::system_error(errno, std::system_category(), std::forward<Message>(msg));
-}
-
-static inline std::pair<int, int>
-splitPointer(void* const ptr) noexcept
-{
- static_assert(sizeof(int) == 4, "splitPointer() requires an 4 byte 'int'");
- // In theory, we need this assertion. In practice, it prevents compilation
- // on EL6 i386. Without the assertion, everything works.
- // If you ever run into trouble with this code, please heed the warnings at
- // http://man7.org/linux/man-pages/man3/makecontext.3.html#NOTES
- // static_assert (sizeof(uintptr_t) == 8,
- // "splitPointer() requires an 8 byte 'uintptr_t'");
- std::pair<int, int> words;
- auto rep = reinterpret_cast<uintptr_t>(ptr);
- uint32_t const hw = rep >> 32;
- auto const lw = static_cast<uint32_t>(rep);
- std::memcpy(&words.first, &hw, 4);
- std::memcpy(&words.second, &lw, 4);
- return words;
-}
-
-template <typename T>
-static inline T*
-joinPtr(int const first, int const second) noexcept
-{
- static_assert(sizeof(int) == 4, "joinPtr() requires an 4 byte 'int'");
- // See above.
- // static_assert (sizeof(uintptr_t) == 8,
- // "joinPtr() requires an 8 byte 'uintptr_t'");
- uint32_t hw;
- uint32_t lw;
- std::memcpy(&hw, &first, 4);
- std::memcpy(&lw, &second, 4);
- return reinterpret_cast<T*>((static_cast<uintptr_t>(hw) << 32) | lw);
-}
-
-extern "C"
-{
- static void
- threadWrapper(int const ctx0, int const ctx1, int const fun0, int const fun1)
- {
- notifyStackSwitchDone();
- auto ctx = joinPtr<pdns_ucontext_t>(ctx0, ctx1);
- try {
- auto start = std::move(*joinPtr<std::function<void()>>(fun0, fun1));
- start();
- }
- catch (...) {
- ctx->exception = std::current_exception();
- }
- notifyStackSwitchToKernel();
- }
-} // extern "C"
-
-pdns_ucontext_t::pdns_ucontext_t()
-{
- uc_mcontext = new ::ucontext_t();
- uc_link = nullptr;
-#ifdef PDNS_USE_VALGRIND
- valgrind_id = 0;
-#endif /* PDNS_USE_VALGRIND */
-}
-
-pdns_ucontext_t::~pdns_ucontext_t()
-{
- delete static_cast<ucontext_t*>(uc_mcontext);
-#ifdef PDNS_USE_VALGRIND
- if (valgrind_id != 0) {
- VALGRIND_STACK_DEREGISTER(valgrind_id);
- }
-#endif /* PDNS_USE_VALGRIND */
-}
-
-void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
-{
- if (::swapcontext(static_cast<ucontext_t*>(octx.uc_mcontext),
- static_cast<ucontext_t*>(ctx.uc_mcontext))) {
- throw_errno("swapcontext() failed");
- }
- if (ctx.exception) {
- std::rethrow_exception(ctx.exception);
- }
-}
-
-void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
-{
- assert(ctx.uc_link);
- assert(ctx.uc_stack.size());
-
- auto const mcp = static_cast<ucontext_t*>(ctx.uc_mcontext);
- auto const next = static_cast<ucontext_t*>(ctx.uc_link->uc_mcontext);
- if (::getcontext(mcp)) {
- throw_errno("getcontext() failed");
- }
- mcp->uc_link = next;
- mcp->uc_stack.ss_sp = ctx.uc_stack.data();
- mcp->uc_stack.ss_size = ctx.uc_stack.size() - 1;
- mcp->uc_stack.ss_flags = 0;
-
- auto ctxarg = splitPointer(&ctx);
- auto funarg = splitPointer(&start);
- return ::makecontext(mcp, reinterpret_cast<void (*)(void)>(&threadWrapper),
- 4, ctxarg.first, ctxarg.second,
- funarg.first, funarg.second);
-}
bool g_gettagNeedsEDNSOptions{false};
bool g_useKernelTimestamp;
std::atomic<uint32_t> g_maxCacheEntries, g_maxPacketCacheEntries;
-#ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
boost::container::flat_set<uint16_t> g_avoidUdpSourcePorts;
-#else
-std::set<uint16_t> g_avoidUdpSourcePorts;
-#endif
uint16_t g_minUdpSourcePort;
uint16_t g_maxUdpSourcePort;
double g_balancingFactor;
t_fdm->addReadFD(socket.getHandle(), handleGenUDPQueryResponse, pident);
PacketBuffer data;
- int ret = g_multiTasker->waitEvent(pident, &data, g_networkTimeoutMsec);
+ int ret = g_multiTasker->waitEvent(pident, &data, authWaitTimeMSec(g_multiTasker));
if (ret == 0 || ret == -1) { // timeout
t_fdm->removeReadFD(socket.getHandle());
thread_local std::unique_ptr<UDPClientSocks> t_udpclientsocks;
+// If we have plenty of mthreads slot left, use default timeout.
+// Otherwise reduce the timeout to be between g_networkTimeoutMsec/10 and g_networkTimeoutMsec
+unsigned int authWaitTimeMSec(const std::unique_ptr<MT_t>& mtasker)
+{
+ const auto max = g_maxMThreads;
+ const auto current = mtasker->numProcesses();
+ const unsigned int cutoff = max / 10; // if we have less than 10% used, do not reduce auth timeout
+ if (current < cutoff) {
+ return g_networkTimeoutMsec;
+ }
+ const auto avail = max - current;
+ return std::max(g_networkTimeoutMsec / 10, g_networkTimeoutMsec * avail / (max - cutoff));
+}
+
/* these two functions are used by LWRes */
LWResult::Result asendto(const void* data, size_t len, int /* flags */,
- const ComboAddress& toAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc)
+ const ComboAddress& toAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc, timeval& now)
{
auto pident = std::make_shared<PacketID>();
assert(chain.first->key->domain == pident->domain); // NOLINT
// don't chain onto existing chained waiter or a chain already processed
if (chain.first->key->fd > -1 && !chain.first->key->closed) {
- chain.first->key->chain.insert(qid); // we can chain
- *fileDesc = -1; // gets used in waitEvent / sendEvent later on
+ auto currentChainSize = chain.first->key->authReqChain.size();
+ *fileDesc = -static_cast<int>(currentChainSize + 1); // value <= -1, gets used in waitEvent / sendEvent later on
+ if (g_maxChainLength > 0 && currentChainSize >= g_maxChainLength) {
+ return LWResult::Result::ChainLimitError;
+ }
+ assert(uSec(chain.first->key->creationTime) != 0); // NOLINT
+ auto age = now - chain.first->key->creationTime;
+ if (uSec(age) > static_cast<uint64_t>(1000) * authWaitTimeMSec(g_multiTasker) * 2 / 3) {
+ return LWResult::Result::ChainLimitError;
+ }
+ chain.first->key->authReqChain.emplace(*fileDesc, qid); // we can chain
+ auto maxLength = t_Counters.at(rec::Counter::maxChainLength);
+ if (currentChainSize + 1 > maxLength) {
+ t_Counters.at(rec::Counter::maxChainLength) = currentChainSize + 1;
+ }
return LWResult::Result::Success;
}
}
pident->domain = domain;
pident->type = qtype;
pident->remote = fromAddr;
+ pident->creationTime = now;
- int ret = g_multiTasker->waitEvent(pident, &packet, g_networkTimeoutMsec, &now);
+ int ret = g_multiTasker->waitEvent(pident, &packet, authWaitTimeMSec(g_multiTasker), &now);
len = 0;
/* -1 means error, 0 means timeout, 1 means a result from handleUDPServerResponse() which might still be an error */
}
private:
- std::unique_ptr<DNSComboWriter>& d_dc;
+ std::unique_ptr<DNSComboWriter>& d_dc; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
bool d_handled{false};
};
{
bool ret = false;
// First check the (sub)domain isn't ignored for NOD purposes
- if (!g_nodDomainWL.check(dname)) {
- // Now check the NODDB (note this is probabilistic so can have FNs/FPs)
- if (g_nodDBp && g_nodDBp->isNewDomain(dname)) {
- if (g_nodLog) {
- // This should probably log to a dedicated log file
- SLOG(g_log << Logger::Notice << "Newly observed domain nod=" << dname << endl,
- nodlogger->info(Logr::Notice, "New domain observed"));
- }
- t_Counters.at(rec::Counter::nodCount)++;
- ret = true;
+ if (g_nodDomainWL.check(dname)) {
+ return ret;
+ }
+ // Now check the NODDB (note this is probabilistic so can have FNs/FPs)
+ if (g_nodDBp && g_nodDBp->isNewDomain(dname)) {
+ if (g_nodLog) {
+ // This should probably log to a dedicated log file
+ SLOG(g_log << Logger::Notice << "Newly observed domain nod=" << dname << endl,
+ nodlogger->info(Logr::Notice, "New domain observed"));
}
+ t_Counters.at(rec::Counter::nodCount)++;
+ ret = true;
}
return ret;
}
static bool udrCheckUniqueDNSRecord(Logr::log_t nodlogger, const DNSName& dname, uint16_t qtype, const DNSRecord& record)
{
bool ret = false;
+ // First check the (sub)domain isn't ignored for UDR purposes
+ if (g_udrDomainWL.check(dname)) {
+ return ret;
+ }
if (record.d_place == DNSResourceRecord::ANSWER || record.d_place == DNSResourceRecord::ADDITIONAL) {
// Create a string that represent a triplet of (qname, qtype and RR[type, name, content])
std::stringstream strStream;
}),
ret.end());
}
+ else {
+ // Remove double SOA records
+ std::set<DNSName> seenSOAs;
+ ret.erase(std::remove_if(
+ ret.begin(),
+ ret.end(),
+ [&seenSOAs](DNSRecord& record) {
+ if (record.d_type == QType::SOA) {
+ if (seenSOAs.count(record.d_name) > 0) {
+ // We've had this SOA before, remove it
+ return true;
+ }
+ seenSOAs.insert(record.d_name);
+ }
+ return false;
+ }),
+ ret.end());
+ }
t_Counters.at(rec::Counter::dns64prefixanswers)++;
return rcode;
}
return false;
}
- notifyset_t::const_iterator ret;
do {
- ret = t_allowNotifyFor->find(qname);
+ auto ret = t_allowNotifyFor->find(qname);
if (ret != t_allowNotifyFor->end()) {
return true;
}
pbMessage.setDeviceName(dnsQuestion.deviceName);
pbMessage.setToPort(comboWriter->d_destination.getPort());
pbMessage.addPolicyTags(comboWriter->d_gettagPolicyTags);
-
+ pbMessage.setWorkerId(RecThreadInfo::id());
+ pbMessage.setPacketCacheHit(false);
+ pbMessage.setOutgoingQueries(resolver.d_outqueries);
for (const auto& metaValue : dnsQuestion.meta) {
pbMessage.setMeta(metaValue.first, metaValue.second.stringVal, metaValue.second.intVal);
}
variable = true;
}
- if (g_multiTasker->numProcesses() > g_maxMThreads) {
+ if (g_multiTasker->numProcesses() >= g_maxMThreads) {
if (!g_quiet) {
SLOG(g_log << Logger::Notice << RecThreadInfo::id() << " [" << g_multiTasker->getTid() << "/" << g_multiTasker->numProcesses() << "] DROPPED question from " << source.toStringWithPort() << (source != fromaddr ? " (via " + fromaddr.toStringWithPort() + ")" : "") << ", over capacity" << endl,
g_slogudpin->info(Logr::Notice, "Dropped question, over capacity", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr)));
}
}
if (t_remotes) {
- t_remotes->push_back(fromaddr);
+ t_remotes->push_back(source);
}
if (t_allowFrom && !t_allowFrom->match(&mappedSource)) {
// We close the chain for new entries, since they won't be processed anyway
iter->key->closed = true;
- if (iter->key->chain.empty()) {
+ if (iter->key->authReqChain.empty()) {
return;
}
- for (auto i = iter->key->chain.begin(); i != iter->key->chain.end(); ++i) {
+
+ auto maxWeight = t_Counters.at(rec::Counter::maxChainWeight);
+ auto weight = iter->key->authReqChain.size() * content.size();
+ if (weight > maxWeight) {
+ t_Counters.at(rec::Counter::maxChainWeight) = weight;
+ }
+
+ for (auto [fileDesc, qid] : iter->key->authReqChain) {
auto packetID = std::make_shared<PacketID>(*resend);
- packetID->fd = -1;
- packetID->id = *i;
+ packetID->fd = fileDesc;
+ packetID->id = qid;
g_multiTasker->sendEvent(packetID, &content);
t_Counters.at(rec::Counter::chainResends)++;
}
}
+void mthreadSleep(unsigned int jitterMsec)
+{
+ auto neverHappens = std::make_shared<PacketID>();
+ neverHappens->id = dns_random_uint16();
+ neverHappens->type = dns_random_uint16();
+ neverHappens->remote = ComboAddress("100::"); // discard-only
+ neverHappens->remote.setPort(dns_random_uint16());
+ neverHappens->fd = -1;
+ assert(g_multiTasker->waitEvent(neverHappens, nullptr, jitterMsec) != -1); // NOLINT
+}
+
static void handleUDPServerResponse(int fileDesc, FDMultiplexer::funcparam_t& var)
{
auto pid = boost::any_cast<std::shared_ptr<PacketID>>(var);
+++ /dev/null
-../pubsuffix.cc
\ No newline at end of file
class RecLuaConfigContext : public BaseLua4
{
public:
- RecLuaConfigContext()
+ RecLuaConfigContext() :
+ BaseLua4("")
{
prepareContext();
}
RecursorControlChannel g_rcc; // only active in the handler thread
bool g_regressionTestMode;
bool g_yamlSettings;
+string g_yamlSettingsSuffix;
bool g_luaSettingsInYAML;
#ifdef NOD_ENABLED
DNSName g_nodLookupDomain;
bool g_nodLog;
SuffixMatchNode g_nodDomainWL;
+SuffixMatchNode g_udrDomainWL;
std::string g_nod_pbtag;
bool g_udrEnabled;
bool g_udrLog;
std::set<ComboAddress> g_proxyProtocolExceptions;
boost::optional<ComboAddress> g_dns64Prefix{boost::none};
DNSName g_dns64PrefixReverse;
+unsigned int g_maxChainLength;
std::shared_ptr<SyncRes::domainmap_t> g_initialDomainMap; // new threads needs this to be setup
std::shared_ptr<NetmaskGroup> g_initialAllowFrom; // new thread needs to be setup with this
std::shared_ptr<NetmaskGroup> g_initialAllowNotifyFrom; // new threads need this to be setup
msg.setRequestorId(requestorId);
msg.setDeviceId(deviceId);
msg.setDeviceName(deviceName);
+ msg.setWorkerId(RecThreadInfo::id());
+ // For queries, packetCacheHit and outgoingQueries are not relevant
if (!policyTags.empty()) {
msg.addPolicyTags(policyTags);
pbMessage.setDeviceId(deviceId);
pbMessage.setDeviceName(deviceName);
pbMessage.setToPort(destination.getPort());
+ pbMessage.setWorkerId(RecThreadInfo::id());
+ // this method is only used for PC cache hits
+ pbMessage.setPacketCacheHit(true);
+ // we do not set outgoingQueries, it is not relevant for PC cache hits
+
for (const auto& metaItem : meta) {
pbMessage.setMeta(metaItem.first, metaItem.second.stringVal, metaItem.second.intVal);
}
}
}
-static void parseNODIgnorelist(const std::string& wlist)
+static void parseIgnorelist(const std::string& wlist, SuffixMatchNode& matchNode)
{
vector<string> parts;
stringtok(parts, wlist, ",; ");
for (const auto& part : parts) {
- g_nodDomainWL.add(DNSName(part));
+ matchNode.add(DNSName(part));
+ }
+}
+
+static void parseIgnorelistFile(const std::string& fname, SuffixMatchNode& matchNode)
+{
+ string line;
+ std::ifstream ignorelistFileStream(fname);
+ if (!ignorelistFileStream) {
+ throw ArgException(fname + " could not be opened");
+ }
+
+ while (getline(ignorelistFileStream, line)) {
+ boost::trim(line);
+
+ try {
+ matchNode.add(DNSName(line));
+ }
+ catch (const std::exception& e) {
+ SLOG(g_log << Logger::Warning << "Ignoring line of ignorelist due to an error: " << e.what() << endl,
+ g_slog->withName("config")->error(Logr::Warning, e.what(), "Ignoring line of ignorelist due to an error", "exception", Logging::Loggable("std::exception")));
+ }
}
}
g_nodEnabled = ::arg().mustDo("new-domain-tracking");
g_nodLookupDomain = DNSName(::arg()["new-domain-lookup"]);
g_nodLog = ::arg().mustDo("new-domain-log");
- parseNODIgnorelist(::arg()["new-domain-whitelist"]);
- parseNODIgnorelist(::arg()["new-domain-ignore-list"]);
+ parseIgnorelist(::arg()["new-domain-whitelist"], g_nodDomainWL);
+ parseIgnorelist(::arg()["new-domain-ignore-list"], g_nodDomainWL);
+ if (!::arg().isEmpty("new-domain-ignore-list-file")) {
+ parseIgnorelistFile(::arg()["new-domain-ignore-list-file"], g_nodDomainWL);
+ }
// Setup Unique DNS Response subsystem
g_udrEnabled = ::arg().mustDo("unique-response-tracking");
g_udrLog = ::arg().mustDo("unique-response-log");
g_nod_pbtag = ::arg()["new-domain-pb-tag"];
g_udr_pbtag = ::arg()["unique-response-pb-tag"];
+ parseIgnorelist(::arg()["unique-response-ignore-list"], g_udrDomainWL);
+ if (!::arg().isEmpty("unique-response-ignore-list-file")) {
+ parseIgnorelistFile(::arg()["unique-response-ignore-list-file"], g_udrDomainWL);
+ }
}
#endif /* NOD_ENABLED */
cleanSlashes(configName);
if (g_yamlSettings) {
- configName += ".yml";
+ configName += g_yamlSettingsSuffix;
string msg;
pdns::rust::settings::rec::Recursorsettings settings;
// XXX Does ::arg()["include-dir"] have the right value, i.e. potentially overriden by command line?
SyncRes::s_event_trace_enabled = ::arg().asNum("event-trace-enabled");
SyncRes::s_save_parent_ns_set = ::arg().mustDo("save-parent-ns-set");
SyncRes::s_max_busy_dot_probes = ::arg().asNum("max-busy-dot-probes");
+ SyncRes::s_max_CNAMES_followed = ::arg().asNum("max-cnames-followed");
{
uint64_t sse = ::arg().asNum("serve-stale-extensions");
if (sse > std::numeric_limits<uint16_t>::max()) {
RecThreadInfo::makeThreadPipes(log);
g_tcpTimeout = ::arg().asNum("client-tcp-timeout");
+ g_maxTCPClients = ::arg().asNum("max-tcp-clients");
g_maxTCPPerClient = ::arg().asNum("max-tcp-per-client");
g_tcpMaxQueriesPerConn = ::arg().asNum("max-tcp-queries-per-connection");
g_maxUDPQueriesPerRound = ::arg().asNum("max-udp-queries-per-round");
g_useKernelTimestamp = ::arg().mustDo("protobuf-use-kernel-timestamp");
+ g_maxChainLength = ::arg().asNum("max-chain-length");
disableStats(StatComponent::API, ::arg()["stats-api-blacklist"]);
disableStats(StatComponent::Carbon, ::arg()["stats-carbon-blacklist"]);
}
}
-static void runTCPMaintenance(RecThreadInfo& threadInfo, bool& listenOnTCP, unsigned int maxTcpClients)
-{
- if (threadInfo.isTCPListener()) {
- if (listenOnTCP) {
- if (TCPConnection::getCurrentConnections() > maxTcpClients) { // shutdown, too many connections
- for (const auto fileDesc : threadInfo.getTCPSockets()) {
- t_fdm->removeReadFD(fileDesc);
- }
- listenOnTCP = false;
- }
- }
- else {
- if (TCPConnection::getCurrentConnections() <= maxTcpClients) { // reenable
- for (const auto fileDesc : threadInfo.getTCPSockets()) {
- t_fdm->addReadFD(fileDesc, handleNewTCPQuestion);
- }
- listenOnTCP = true;
- }
- }
- }
-}
-
static void recLoop()
{
- unsigned int maxTcpClients = ::arg().asNum("max-tcp-clients");
- bool listenOnTCP{true};
time_t last_stat = 0;
time_t last_carbon = 0;
time_t last_lua_maintenance = 0;
}
runLuaMaintenance(threadInfo, last_lua_maintenance, luaMaintenanceInterval);
- t_fdm->run(&g_now);
+ auto timeoutUsec = g_multiTasker->nextWaiterDelayUsec(500000);
+ t_fdm->run(&g_now, static_cast<int>(timeoutUsec / 1000));
// 'run' updates g_now for us
-
- runTCPMaintenance(threadInfo, listenOnTCP, maxTcpClients);
}
catch (const PDNSException& pdnsException) {
s_rateLimitedLogger.log(g_slog->withName("runtime"), "recLoop", pdnsException);
checkFrameStreamExport(luaconfsLocal, luaconfsLocal->frameStreamExportConfig, t_frameStreamServersInfo);
checkFrameStreamExport(luaconfsLocal, luaconfsLocal->nodFrameStreamExportConfig, t_nodFrameStreamServersInfo);
#endif
+ for (const auto& rpz : luaconfsLocal->rpzs) {
+ string name = rpz.polName.empty() ? (rpz.primaries.empty() ? "rpzFile" : rpz.name) : rpz.polName;
+ t_Counters.at(rec::PolicyNameHits::policyName).counts[name] = 0;
+ }
}
t_fdm = unique_ptr<FDMultiplexer>(getMultiplexer(log));
::arg().laxParse(argc, argv); // do a lax parse
if (::arg().mustDo("version")) {
- showProductVersion();
- showBuildConfiguration();
+ cout << getProductVersion();
+ cout << getBuildConfiguration();
return 0;
}
if (::arg().mustDo("help")) {
}
g_log.setLoglevel(s_logUrgency);
g_log.toConsole(s_logUrgency);
- showProductVersion();
+
+ for (const string& line : getProductVersionLines()) {
+ g_log << Logger::Info << line << endl;
+ }
if (!::arg().mustDo("structured-logging")) {
g_log << Logger::Error << "Disabling structured logging is not supported anymore" << endl;
}
::arg().setSLog(startupLog);
- const string yamlconfigname = configname + ".yml";
+ string yamlconfigname;
pdns::rust::settings::rec::Recursorsettings settings;
- auto yamlstatus = pdns::settings::rec::tryReadYAML(yamlconfigname, true, g_yamlSettings, g_luaSettingsInYAML, settings, startupLog);
- if (yamlstatus == pdns::settings::rec::PresentButFailed) {
- return 1;
+ pdns::settings::rec::YamlSettingsStatus yamlstatus{};
+
+ for (const string suffix : {".yml", ".conf"}) {
+ yamlconfigname = configname + suffix;
+ yamlstatus = pdns::settings::rec::tryReadYAML(yamlconfigname, true, g_yamlSettings, g_luaSettingsInYAML, settings, startupLog);
+ if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::OK) {
+ g_yamlSettingsSuffix = suffix;
+ break;
+ }
+ if (suffix == ".yml" && yamlstatus == pdns::settings::rec::PresentButFailed) {
+ return 1;
+ }
}
if (g_yamlSettings) {
}
if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::OK) {
auto lock = g_yamlStruct.lock();
- *lock = settings;
+ *lock = std::move(settings);
}
- if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::CannotOpen) {
+ else {
configname += ".conf";
+ startupLog->info(Logr::Warning, "Trying to read YAML from .yml or .conf failed, failing back to old-style config read", "configname", Logging::Loggable(configname));
bool mustExit = false;
std::tie(ret, mustExit) = doConfig(startupLog, configname, argc, argv);
if (ret != 0 || mustExit) {
}
}
+static void* pleaseInitPolCounts(const string& name)
+{
+ if (t_Counters.at(rec::PolicyNameHits::policyName).counts.count(name) == 0) {
+ t_Counters.at(rec::PolicyNameHits::policyName).counts[name] = 0;
+ }
+ return nullptr;
+}
+
static void activateRPZFile(const RPZTrackerParams& params, LuaConfigItems& lci, shared_ptr<DNSFilterEngine::Zone>& zone)
{
auto log = lci.d_slog->withValues("file", Logging::Loggable(params.name));
- zone->setName(params.polName);
+ zone->setName(params.polName.empty() ? "rpzFile" : params.polName);
try {
SLOG(g_log << Logger::Warning << "Loading RPZ from file '" << params.name << "'" << endl,
log->info(Logr::Info, "Loading RPZ from file"));
else {
DNSName domain(params.name);
zone->setDomain(domain);
- zone->setName(params.polName);
+ zone->setName(params.polName.empty() ? params.name : params.polName);
params.zoneIdx = lci.dfe.addZone(zone);
activateRPZPrimary(params, lci, zone, domain);
}
+ broadcastFunction([name = zone->getName()] { return pleaseInitPolCounts(name); });
}
}
#include "nod.hh"
#endif /* NOD_ENABLED */
-#ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
#include <boost/container/flat_set.hpp>
-#endif
extern std::shared_ptr<Logr::Logger> g_slogtcpin;
extern std::shared_ptr<Logr::Logger> g_slogudpin;
};
std::string d_query;
std::unordered_set<std::string> d_policyTags;
- const std::unordered_set<std::string> d_gettagPolicyTags;
+ std::unordered_set<std::string> d_gettagPolicyTags;
std::string d_routingTag;
std::vector<DNSRecord> d_records;
using RemoteLoggerStats_t = std::unordered_map<std::string, RemoteLoggerInterface::Stats>;
extern bool g_yamlSettings;
+extern string g_yamlSettingsSuffix;
extern bool g_logCommonErrors;
extern size_t g_proxyProtocolMaximumSize;
extern std::atomic<bool> g_quiet;
extern bool g_reusePort;
extern bool g_anyToTcp;
extern size_t g_tcpMaxQueriesPerConn;
+extern unsigned int g_maxTCPClients;
extern unsigned int g_maxTCPPerClient;
extern int g_tcpTimeout;
extern uint16_t g_udpTruncationThreshold;
extern size_t g_maxUDPQueriesPerRound;
extern bool g_useKernelTimestamp;
extern bool g_allowNoRD;
+extern unsigned int g_maxChainLength;
extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
extern thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
extern thread_local std::shared_ptr<notifyset_t> t_allowNotifyFor;
extern DNSName g_nodLookupDomain;
extern bool g_nodLog;
extern SuffixMatchNode g_nodDomainWL;
+extern SuffixMatchNode g_udrDomainWL;
extern std::string g_nod_pbtag;
extern bool g_udrEnabled;
extern bool g_udrLog;
extern thread_local FrameStreamServersInfo t_nodFrameStreamServersInfo;
#endif /* HAVE_FSTRM */
-#ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
extern boost::container::flat_set<uint16_t> g_avoidUdpSourcePorts;
-#else
-extern std::set<uint16_t> g_avoidUdpSourcePorts;
-#endif
/* without reuseport, all listeners share the same sockets */
typedef vector<pair<int, std::function<void(int, boost::any&)>>> deferredAdd_t;
extern bool g_luaSettingsInYAML;
void startLuaConfigDelayedThreads(const vector<RPZTrackerParams>& rpzs, uint64_t generation);
void activateLuaConfig(LuaConfigItems& lci);
+unsigned int authWaitTimeMSec(const std::unique_ptr<MT_t>& mtasker);
#define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10"
#define LOCAL_NETS_INVERSE "!127.0.0.0/8, !10.0.0.0/8, !100.64.0.0/10, !169.254.0.0/16, !192.168.0.0/16, !172.16.0.0/12, !::1/128, !fc00::/7, !fe80::/10"
#include "rec-protozero.hh"
#include <variant>
-void pdns::ProtoZero::RecMessage::addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, [[maybe_unused]] bool udr)
+void pdns::ProtoZero::RecMessage::addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, [[maybe_unused]] std::optional<bool> udr)
{
if (record.d_place != DNSResourceRecord::ANSWER || record.d_class != QClass::IN) {
return;
break;
}
#ifdef NOD_ENABLED
- pbf_rr.add_bool(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::udr), udr);
- pbf_rr.commit();
+ if (udr) {
+ pbf_rr.add_bool(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::udr), *udr);
+ pbf_rr.commit();
- // Save the offset of the byte containing the just added bool. We can do this since
- // we know a bit about how protobuf's encoding works.
- offsets.push_back(d_rspbuf.length() - 1);
+ // Save the offset of the byte containing the just added bool. We can do this since
+ // we know a bit about how protobuf's encoding works.
+ offsets.push_back(d_rspbuf.length() - 1);
+ }
#endif
}
// DNSResponse related fields below
- void addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, bool udr);
+ void addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, std::optional<bool> udr);
void setAppliedPolicyType(const DNSFilterEngine::PolicyType type)
{
#ifdef HAVE_NET_SNMP
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/definitions.h>
+#include <net-snmp/types.h>
+#include <net-snmp/utilities.h>
+#include <net-snmp/config_api.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#undef INET6 /* SRSLY? */
+
#define RECURSOR_OID 1, 3, 6, 1, 4, 1, 43315, 2
#define RECURSOR_STATS_OID RECURSOR_OID, 1
#define RECURSOR_TRAPS_OID RECURSOR_OID, 10, 0
static const oid10 packetCacheAcquiredOID = {RECURSOR_STATS_OID, 146};
static const oid10 nodEventsOID = {RECURSOR_STATS_OID, 147};
static const oid10 udrEventsOID = {RECURSOR_STATS_OID, 148};
+static const oid10 maxChainLengthOID = {RECURSOR_STATS_OID, 149};
+static const oid10 maxChainWeightOID = {RECURSOR_STATS_OID, 150};
+static const oid10 chainLimitsOID = {RECURSOR_STATS_OID, 151};
+static const oid10 tcpOverflowOID = {RECURSOR_STATS_OID, 152};
static std::unordered_map<oid, std::string> s_statsMap;
#ifdef HAVE_NET_SNMP
netsnmp_variable_list* varList = nullptr;
- snmp_varlist_add_variable(&varList,
- snmpTrapOID.data(),
- snmpTrapOID.size(),
- ASN_OBJECT_ID,
- customTrapOID.data(),
- customTrapOID.size() * sizeof(oid));
+ addSNMPTrapOID(&varList,
+ customTrapOID.data(),
+ customTrapOID.size() * sizeof(oid));
snmp_varlist_add_variable(&varList,
trapReasonOID.data(),
registerCounter64Stat("non-resolving-nameserver-entries", nonResolvingNameserverEntriesOID);
registerCounter64Stat("maintenance-usec", maintenanceUSecOID);
registerCounter64Stat("maintenance-calls", maintenanceCallsOID);
+ registerCounter64Stat("chain-limits", chainLimitsOID);
#define RCODE(num) registerCounter64Stat("auth-" + RCode::to_short_s(num) + "-answers", rcode##num##AnswersOID) // NOLINT(cppcoreguidelines-macro-usage)
RCODE(0);
registerCounter64Stat("packetcache-acquired", packetCacheAcquiredOID);
registerCounter64Stat("nod-events", nodEventsOID);
registerCounter64Stat("udr-events", udrEventsOID);
+ registerCounter64Stat("max-chain-length", maxChainLengthOID);
+ registerCounter64Stat("max-chain-weight", maxChainWeightOID);
+ registerCounter64Stat("tcp-overflow", tcpOverflowOID);
#endif /* HAVE_NET_SNMP */
}
if (parser.d_header.rcode != RCode::NoError || parser.d_answers.size() != 1) {
return {};
}
- const auto& dnsrecord = parser.d_answers.at(0).first;
+ const auto& dnsrecord = parser.d_answers.at(0);
if (dnsrecord.d_type == QType::TXT) {
if (auto txt = getRR<TXTRecordContent>(dnsrecord); txt != nullptr) {
const auto& text = txt->d_text;
sourceDisallowedNotify, // when this is increased, qcounter is also
zoneDisallowedNotify, // when this is increased, qcounter is also
policyDrops,
+ tcpOverflow,
tcpClientOverflow,
clientParseError,
serverParseError,
maintenanceCalls,
nodCount,
udrCount,
+ maxChainLength,
+ maxChainWeight,
+ chainLimits,
numberOfCounters
};
// worker thread(s) now no longer process TCP queries.
size_t g_tcpMaxQueriesPerConn;
+unsigned int g_maxTCPClients;
unsigned int g_maxTCPPerClient;
int g_tcpTimeout;
bool g_anyToTcp;
if (t_pdl) {
try {
if (t_pdl->hasGettagFFIFunc()) {
- RecursorLua4::FFIParams params(qname, qtype, comboWriter->d_local, comboWriter->d_remote, comboWriter->d_destination, comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_data, comboWriter->d_policyTags, comboWriter->d_records, ednsOptions, comboWriter->d_proxyProtocolValues, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_rcode, comboWriter->d_ttlCap, comboWriter->d_variable, true, logQuery, comboWriter->d_logResponse, comboWriter->d_followCNAMERecords, comboWriter->d_extendedErrorCode, comboWriter->d_extendedErrorExtra, comboWriter->d_responsePaddingDisabled, comboWriter->d_meta);
+ RecursorLua4::FFIParams params(qname, qtype, comboWriter->d_local, comboWriter->d_remote, comboWriter->d_destination, comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_data, comboWriter->d_gettagPolicyTags, comboWriter->d_records, ednsOptions, comboWriter->d_proxyProtocolValues, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_rcode, comboWriter->d_ttlCap, comboWriter->d_variable, true, logQuery, comboWriter->d_logResponse, comboWriter->d_followCNAMERecords, comboWriter->d_extendedErrorCode, comboWriter->d_extendedErrorExtra, comboWriter->d_responsePaddingDisabled, comboWriter->d_meta);
comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI);
comboWriter->d_tag = t_pdl->gettag_ffi(params);
comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI, comboWriter->d_tag, false);
}
else if (t_pdl->hasGettagFunc()) {
comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTag);
- comboWriter->d_tag = t_pdl->gettag(comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_destination, qname, qtype, &comboWriter->d_policyTags, comboWriter->d_data, ednsOptions, true, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_proxyProtocolValues);
+ comboWriter->d_tag = t_pdl->gettag(comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_destination, qname, qtype, &comboWriter->d_gettagPolicyTags, comboWriter->d_data, ednsOptions, true, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_proxyProtocolValues);
comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTag, comboWriter->d_tag, false);
}
+ // Copy d_gettagPolicyTags to d_policyTags, so other Lua hooks see them and can add their
+ // own. Before storing into the packetcache, the tags in d_gettagPolicyTags will be
+ // cleared by addPolicyTagsToPBMessageIfNeeded() so they do *not* end up in the PC. When an
+ // Protobuf message is constructed, one part comes from the PC (including the tags
+ // set by non-gettag hooks), and the tags in d_gettagPolicyTags will be added by the code
+ // constructing the PB message.
+ comboWriter->d_policyTags = comboWriter->d_gettagPolicyTags;
}
catch (const std::exception& e) {
if (g_logCommonErrors) {
} // good query
}
-static void handleRunningTCPQuestion(int fileDesc, FDMultiplexer::funcparam_t& var)
+static void handleRunningTCPQuestion(int fileDesc, FDMultiplexer::funcparam_t& var) // NOLINT(readability-function-cognitive-complexity)
{
auto conn = boost::any_cast<shared_ptr<TCPConnection>>(var);
++iter->second.stats.netmaskMatches;
}
}
+ if (t_remotes) {
+ t_remotes->push_back(conn->d_source);
+ }
if (t_allowFrom && !t_allowFrom->match(&conn->d_mappedSource)) {
if (!g_quiet) {
SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping TCP query from " << conn->d_mappedSource.toString() << ", address not matched by allow-from" << endl,
ComboAddress addr;
socklen_t addrlen = sizeof(addr);
int newsock = accept(fileDesc, reinterpret_cast<struct sockaddr*>(&addr), &addrlen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
- if (newsock >= 0) {
- if (g_multiTasker->numProcesses() > g_maxMThreads) {
- t_Counters.at(rec::Counter::overCapacityDrops)++;
- try {
- closesocket(newsock);
- }
- catch (const PDNSException& e) {
- SLOG(g_log << Logger::Error << "Error closing TCP socket after an over capacity drop: " << e.reason << endl,
- g_slogtcpin->error(Logr::Error, e.reason, "Error closing TCP socket after an over capacity drop", "exception", Logging::Loggable("PDNSException")));
- }
- return;
- }
-
- if (t_remotes) {
- t_remotes->push_back(addr);
- }
-
- ComboAddress destaddr;
- socklen_t len = sizeof(destaddr);
- getsockname(newsock, reinterpret_cast<sockaddr*>(&destaddr), &len); // if this fails, we're ok with it NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
- bool fromProxyProtocolSource = expectProxyProtocol(addr, destaddr);
- ComboAddress mappedSource = addr;
- if (!fromProxyProtocolSource && t_proxyMapping) {
- if (const auto* iter = t_proxyMapping->lookup(addr)) {
- mappedSource = iter->second.address;
- ++iter->second.stats.netmaskMatches;
- }
+ if (newsock < 0) {
+ return;
+ }
+ auto closeSock = [newsock](rec::Counter cnt, const string& msg) {
+ try {
+ closesocket(newsock);
+ t_Counters.at(cnt)++;
+ // We want this bump to percolate up without too much delay
+ t_Counters.updateSnap(false);
}
- if (!fromProxyProtocolSource && t_allowFrom && !t_allowFrom->match(&mappedSource)) {
- if (!g_quiet) {
- SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping TCP query from " << mappedSource.toString() << ", address neither matched by allow-from nor proxy-protocol-from" << endl,
- g_slogtcpin->info(Logr::Error, "dropping TCP query address neither matched by allow-from nor proxy-protocol-from", "source", Logging::Loggable(mappedSource)));
- }
- t_Counters.at(rec::Counter::unauthorizedTCP)++;
- try {
- closesocket(newsock);
- }
- catch (const PDNSException& e) {
- SLOG(g_log << Logger::Error << "Error closing TCP socket after an ACL drop: " << e.reason << endl,
- g_slogtcpin->error(Logr::Error, e.reason, "Error closing TCP socket after an ACL drop", "exception", Logging::Loggable("PDNSException")));
- }
- return;
+ catch (const PDNSException& e) {
+ g_slogtcpin->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("PDNSException"));
}
+ };
- if (g_maxTCPPerClient > 0 && t_tcpClientCounts->count(addr) > 0 && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) {
- t_Counters.at(rec::Counter::tcpClientOverflow)++;
- try {
- closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
- }
- catch (const PDNSException& e) {
- SLOG(g_log << Logger::Error << "Error closing TCP socket after an overflow drop: " << e.reason << endl,
- g_slogtcpin->error(Logr::Error, e.reason, "Error closing TCP socket after an overflow drop", "exception", Logging::Loggable("PDNSException")));
- }
- return;
- }
+ if (TCPConnection::getCurrentConnections() >= g_maxTCPClients) {
+ closeSock(rec::Counter::tcpOverflow, "Error closing TCP socket after an overflow drop");
+ return;
+ }
+ if (g_multiTasker->numProcesses() >= g_maxMThreads) {
+ closeSock(rec::Counter::overCapacityDrops, "Error closing TCP socket after an over capacity drop");
+ return;
+ }
- setNonBlocking(newsock);
- setTCPNoDelay(newsock);
- std::shared_ptr<TCPConnection> tcpConn = std::make_shared<TCPConnection>(newsock, addr);
- tcpConn->d_source = addr;
- tcpConn->d_destination = destaddr;
- tcpConn->d_mappedSource = mappedSource;
-
- if (fromProxyProtocolSource) {
- tcpConn->proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
- tcpConn->data.resize(tcpConn->proxyProtocolNeed);
- tcpConn->state = TCPConnection::PROXYPROTOCOLHEADER;
+ ComboAddress destaddr;
+ socklen_t len = sizeof(destaddr);
+ getsockname(newsock, reinterpret_cast<sockaddr*>(&destaddr), &len); // if this fails, we're ok with it NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
+ bool fromProxyProtocolSource = expectProxyProtocol(addr, destaddr);
+ if (!fromProxyProtocolSource && t_remotes) {
+ t_remotes->push_back(addr);
+ }
+ ComboAddress mappedSource = addr;
+ if (!fromProxyProtocolSource && t_proxyMapping) {
+ if (const auto* iter = t_proxyMapping->lookup(addr)) {
+ mappedSource = iter->second.address;
+ ++iter->second.stats.netmaskMatches;
}
- else {
- tcpConn->state = TCPConnection::BYTE0;
+ }
+ if (!fromProxyProtocolSource && t_allowFrom && !t_allowFrom->match(&mappedSource)) {
+ if (!g_quiet) {
+ SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping TCP query from " << mappedSource.toString() << ", address neither matched by allow-from nor proxy-protocol-from" << endl,
+ g_slogtcpin->info(Logr::Error, "dropping TCP query address neither matched by allow-from nor proxy-protocol-from", "source", Logging::Loggable(mappedSource)));
}
+ closeSock(rec::Counter::unauthorizedTCP, "Error closing TCP socket after an ACL drop");
+ return;
+ }
- struct timeval ttd
- {
- };
- Utility::gettimeofday(&ttd, nullptr);
- ttd.tv_sec += g_tcpTimeout;
+ if (g_maxTCPPerClient > 0 && t_tcpClientCounts->count(addr) > 0 && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) {
+ closeSock(rec::Counter::tcpClientOverflow, "Error closing TCP socket after a client overflow drop");
+ return;
+ }
- t_fdm->addReadFD(tcpConn->getFD(), handleRunningTCPQuestion, tcpConn, &ttd);
+ setNonBlocking(newsock);
+ setTCPNoDelay(newsock);
+ std::shared_ptr<TCPConnection> tcpConn = std::make_shared<TCPConnection>(newsock, addr);
+ tcpConn->d_source = addr;
+ tcpConn->d_destination = destaddr;
+ tcpConn->d_mappedSource = mappedSource;
+
+ if (fromProxyProtocolSource) {
+ tcpConn->proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
+ tcpConn->data.resize(tcpConn->proxyProtocolNeed);
+ tcpConn->state = TCPConnection::PROXYPROTOCOLHEADER;
+ }
+ else {
+ tcpConn->state = TCPConnection::BYTE0;
}
+
+ timeval ttd{};
+ Utility::gettimeofday(&ttd, nullptr);
+ ttd.tv_sec += g_tcpTimeout;
+
+ t_fdm->addReadFD(tcpConn->getFD(), handleRunningTCPQuestion, tcpConn, &ttd);
}
static void TCPIOHandlerIO(int fileDesc, FDMultiplexer::funcparam_t& var);
// Will set pident->lowState
TCPIOHandlerStateChange(IOState::Done, state, pident);
- int ret = g_multiTasker->waitEvent(pident, &data, g_networkTimeoutMsec);
+ int ret = g_multiTasker->waitEvent(pident, &data, authWaitTimeMSec(g_multiTasker));
TCPLOG(pident->tcpsock, "arecvtcp " << ret << ' ' << data.size() << ' ');
if (ret == 0) {
TCPLOG(pident->tcpsock, "timeout" << endl);
addGetStat("unauthorized-tcp", [] { return g_Counters.sum(rec::Counter::unauthorizedTCP); });
addGetStat("source-disallowed-notify", [] { return g_Counters.sum(rec::Counter::sourceDisallowedNotify); });
addGetStat("zone-disallowed-notify", [] { return g_Counters.sum(rec::Counter::zoneDisallowedNotify); });
+ addGetStat("tcp-overflow", [] { return g_Counters.sum(rec::Counter::tcpOverflow); });
addGetStat("tcp-client-overflow", [] { return g_Counters.sum(rec::Counter::tcpClientOverflow); });
addGetStat("client-parse-errors", [] { return g_Counters.sum(rec::Counter::clientParseError); });
addGetStat("nod-events", [] { return g_Counters.sum(rec::Counter::nodCount); });
addGetStat("udr-events", [] { return g_Counters.sum(rec::Counter::udrCount); });
+ addGetStat("max-chain-length", [] { return g_Counters.max(rec::Counter::maxChainLength); });
+ addGetStat("max-chain-weight", [] { return g_Counters.max(rec::Counter::maxChainWeight); });
+ addGetStat("chain-limits", [] { return g_Counters.sum(rec::Counter::chainLimits); });
+
/* make sure that the ECS stats are properly initialized */
SyncRes::clearECSStats();
for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize4.size(); idx++) {
bool dummy1{};
bool dummy2{};
pdns::rust::settings::rec::Recursorsettings settings;
- auto yamlstat = pdns::settings::rec::tryReadYAML(configname + ".yml", false, dummy1, dummy2, settings, g_slog);
+ auto yamlstat = pdns::settings::rec::tryReadYAML(configname + g_yamlSettingsSuffix, false, dummy1, dummy2, settings, g_slog);
if (yamlstat != pdns::settings::rec::YamlSettingsStatus::OK) {
return {1, "Not reloading dynamic part of YAML configuration\n"};
}
lci = g_luaconfs.getCopy();
if (broadcast) {
startLuaConfigDelayedThreads(lci.rpzs, lci.generation);
- broadcastFunction([=] { return pleaseSupplantProxyMapping(proxyMapping); });
+ broadcastFunction([pmap = std::move(proxyMapping)] { return pleaseSupplantProxyMapping(pmap); });
}
else {
// Initial proxy mapping
cleanSlashes(configname);
- const string yamlconfigname = configname + ".yml";
string msg;
pdns::rust::settings::rec::Recursorsettings settings;
-
- auto yamlstatus = pdns::settings::rec::readYamlSettings(yamlconfigname, "", settings, msg, g_slog);
-
- switch (yamlstatus) {
- case pdns::settings::rec::YamlSettingsStatus::CannotOpen:
- break;
- case pdns::settings::rec::YamlSettingsStatus::PresentButFailed:
- log->error(Logr::Error, msg, "YAML config found, but error ocurred processing it", "configname", Logging::Loggable(yamlconfigname));
- exit(1); // NOLINT(concurrency-mt-unsafe)
- break;
- case pdns::settings::rec::YamlSettingsStatus::OK:
- log->info(Logr::Notice, "YAML config found and processed", "configname", Logging::Loggable(yamlconfigname));
- pdns::settings::rec::bridgeStructToOldStyleSettings(settings);
- break;
+ pdns::settings::rec::YamlSettingsStatus yamlstatus{};
+
+ for (const string suffix : {".yml", ".conf"}) {
+ const string yamlconfigname = configname + suffix;
+ yamlstatus = pdns::settings::rec::readYamlSettings(yamlconfigname, "", settings, msg, g_slog);
+
+ switch (yamlstatus) {
+ case pdns::settings::rec::YamlSettingsStatus::CannotOpen:
+ break;
+ case pdns::settings::rec::YamlSettingsStatus::PresentButFailed:
+ if (suffix == ".yml") {
+ log->error(Logr::Error, msg, "YAML config found, but error ocurred processing it", "configname", Logging::Loggable(yamlconfigname));
+ exit(1); // NOLINT(concurrency-mt-unsafe)
+ }
+ break;
+ case pdns::settings::rec::YamlSettingsStatus::OK:
+ log->info(Logr::Notice, "YAML config found and processed", "configname", Logging::Loggable(yamlconfigname));
+ pdns::settings::rec::bridgeStructToOldStyleSettings(settings);
+ break;
+ }
+ if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::OK) {
+ break;
+ }
}
-
- if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::CannotOpen) {
+ if (yamlstatus != pdns::settings::rec::YamlSettingsStatus::OK) {
configname += ".conf";
arg().laxFile(configname);
}
#include "settings/cxxsettings.hh"
#include "rec-system-resolve.hh"
+// XXX consider including rec-main.hh?
extern int g_argc;
extern char** g_argv;
+extern string g_yamlSettingsSuffix;
bool primeHints(time_t now)
{
log->info(Logr::Notice, "Reloading zones, purging data from cache"));
if (yaml) {
- configname += ".yml";
+ configname += g_yamlSettingsSuffix;
string msg;
pdns::rust::settings::rec::Recursorsettings settings;
// XXX Does ::arg()["include-dir"] have the right value, i.e. potentially overriden by command line?
continue;
}
+ // We want the full name in the SOA record
+ if (dnsRecord.d_type == QType::SOA) {
+ zone->setSOA(dnsRecord);
+ }
dnsRecord.d_name.makeUsRelative(zoneName);
if (dnsRecord.d_type == QType::SOA) {
soaRecordContent = getRR<SOARecordContent>(dnsRecord);
- zone->setSOA(dnsRecord);
continue;
}
The Rust code uses CXX for bridging between C++ and Rust.
At the moment of writing, we only call Rust code from C++ and not vice versa.
-Additionally, the Rust Serde crate (and specifically Serde-YAML) is used to generatec code to handle YAML.
+Additionally, the Rust Serde crate (and specifically Serde-YAML) is used to generate code to handle YAML.
The entry point for code generation is `generate.py`, which uses `table.py` to produce C++, Rust and .rst files.
-See `generate.sh` for some details about the generation process.
+See `generate.py` for some details about the generation process.
This directory also contains a couple of `*-in.*` files which are included into files generated by the generation process.
From the C++ point of view, several namespaces are defined:
* `build.rs`: `The custom build file used by CXX, see CXX docs.
* `cxx.h`: The generic types used by CXX generated code.
* `lib.rs.h`: The project specific C++ types generated by CXX.
-* `libsettings.a`: The actual static library procuced by this crate.
+* `libsettings.a`: The actual static library produced by this crate.
* `src`: The actual rust code, `lib.rs` is generated, `bridge.rs` and `helpers.rs` are maintained manually.
* `target`: The `cargo` maintained Rust build directory.
The generated code
------------------
-C++, Rust and docmentation generating is done by the `generate.py` Python script using `table.py` as input.
+C++, Rust and documentation generating is done by the `generate.py` Python script using `table.py` as input.
After that, the C++ to Rust bridge code is generated by CXX.
Lets take a look at the `log_bogus` setting.
The source of its definition is in `table.py`:
},
```
-The old-style documention generated for this can be found in `../docs/settings.rst`:
+The old-style documentation generated for this can be found in `../docs/settings.rst`:
```
.. _setting-dnssec-log-bogus:
**Note**: This is not logged per-query but every time records are validated as Bogus.
```
-The new-style documention generated for this can be found in `../docs/yamlsettings.rst`, its name includes the section and it lists a YAML default:
+The new-style documentation generated for this can be found in `../docs/yamlsettings.rst`, its name includes the section and it lists a YAML default:
```
.. _setting-yaml-dnssec.log_bogus:
// And for all other values below, the default is either an empty string or an empty vector.
// Once we get more u64 values below with different default values this hack no longer works.
rustvalue.u64_val = 24;
- map.emplace(std::pair{std::pair{section, name}, pdns::rust::settings::rec::OldStyle{section, name, name, type, rustvalue, false}});
+ map.emplace(std::pair{std::pair{section, name}, pdns::rust::settings::rec::OldStyle{section, name, name, type, std::move(rustvalue), false}});
};
def("dnssec", "trustanchors", "Vec<TrustAnchor>");
def("dnssec", "negative_trustanchors", "Vec<NegativeTrustAnchor>");
}
}
if (!dsRecords.empty()) {
- pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), dsRecords};
+ pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), std::move(dsRecords)};
dnssec.trustanchors.emplace_back(trustAnchor);
}
}
case pdns::settings::rec::YamlSettingsStatus::PresentButFailed:
SLOG(g_log << Logger::Error << "YAML config found for configname '" << yamlconfigname << "' but error ocurred processing it" << endl,
- startupLog->error(Logr::Error, msg, "YAML config found, but error occurred processsing it", "configname", Logging::Loggable(yamlconfigname)));
+ startupLog->error(Logr::Error, msg, "YAML config found, but error occurred processing it", "configname", Logging::Loggable(yamlconfigname)));
break;
case pdns::settings::rec::YamlSettingsStatus::OK:
If both ``recursor.conf`` and ``recursor.yml`` files are found in the configuration directory the YAML file is used.
A configuration using the old style syntax can be converted to a YAML configuration using the instructions in :doc:`appendices/yamlconversion`.
- Release 5.0.0 will install a default old-style ``recursor.conf`` files only.
+ Release 5.0.0 will install a default old-style ``recursor.conf`` file.
- With the release of version 5.1.0, packages will stop installing a default ``recursor.conf`` and start installing a default ``recursor.yml`` file if no existing ``recursor.conf`` is present.
- In the absense of a ``recursor.yml`` file, an existing ``recursor.conf`` file will be accepted and used.
+ Starting with version 5.1.0, in the absence of a ``recursor.yml`` file, an existing ``recursor.conf`` will be processed as YAML,
+ if that fails, it will be processed as old-style configuration.
+ Packages will stop installing a old-style ``recursor.conf`` file and start installing a default ``recursor.conf`` file containing YAML syntax.
- With the release of 5.2.0, the default will be to expect a ``recursor.yml`` file and reading of ``recursor.conf`` files will have to be enabled specifically by providing a command line option.
+ With the release of 5.2.0, the default will be to expect a YAML configuration file and reading of old-style ``recursor.conf`` files will have to be enabled specifically by providing a command line option.
In a future release support for the "old-style" ``recursor.conf`` settings file will be dropped.
After merging, ``dnssec.log_bogus`` will be ``false``, the sequence of ``recursor.forward_zones`` will contain 2 zones and the ``outgoing`` addresses used will contain one entry, as the ``extra.yml`` entry has overwritten the existing one.
-``outgoing.dont-query`` has a non-empty sequence as default value. The main ``recursor.yml`` did not set it, so before processing ``extra.yml`` had the default value.
+``outgoing.dont-query`` has a non-empty sequence as default value. The main ``recursor.yml`` did not set it, so before processing ``extra.yml`` it had the default value.
After processing ``extra.yml`` the value will be set to the empty sequence, as existing default values are overwritten by new values.
.. warning::
The result will *not* be a a single forward with two IP addresses, but two entries for ``example.net``.
It depends on the specific setting how the sequence is processed and interpreted further.
+Description of YAML syntax for structured types
+-----------------------------------------------
+
Socket Address
^^^^^^^^^^^^^^
-A socket address is either an IP or and IP:port combination
+A socket address is a string containing either an IP address or and IP address:port combination
For example:
.. code-block:: yaml
Subnets can also be prefixed with a ``!``, specifying negation.
This can be used to deny addresses from a previously allowed range.
-For example, ``alow-from`` takes a sequence of subnets:
+For example, ``allow-from`` takes a sequence of subnets:
.. code-block:: yaml
.. code-block:: yaml
- zone: zonename
+ zone: string
forwarders:
- Socket Address
- ...
recurse: Boolean, default false
allow_notify: Boolean, default false
-An example of a ``forward_zones`` entry, which consists of a sequence of forward zone entries:
+An example of a ``forward_zones`` entry, which consists of a sequence of `Forward Zone`_ entries:
.. code-block:: yaml
.. code-block:: yaml
- zone: name
- file: filename
+ zone: string
+ file: string
-An example of a ``auth_zones`` entry, consisting of a sequence of auth zones:
+An example of a ``auth_zones`` entry, consisting of a sequence of `Auth Zone`_:
.. code-block:: yaml
file: zones/example.net.zone
-YAML settings corresponding to Lua config items
------------------------------------------------
+Description of YAML syntax corresponding to Lua config items
+------------------------------------------------------------
-The YAML settings below were introduced in verison 5.1.0 and correspond to the
+The YAML settings below were introduced in version 5.1.0 and correspond to their
respective Lua settings. Refer to :doc:`lua-config/index`.
TrustAnchor
.. code-block:: yaml
- name: zonename
+ name: string
dsrecords: sequence of DS record strings in presentation format
-An example of a ``trustanchors`` sequence:
+An example of a ``trustanchors`` entry, which is a sequence of `TrustAnchor`_:
.. code-block:: yaml
.. code-block:: yaml
- name: zonename
- reason: text
+ name: string
+ reason: string
-An example of a ``negative trustanchors`` sequence:
+An example of a ``negative_trustanchors`` entry, which is a sequence of `NegativeTrustAnchor`_:
.. code-block:: yaml
exportTypes: [A, AAAA, CNAME] Sequence of QType names
logMappedFrom: false
-An example of a ``protobuf_servers`` entry:
+An example of a ``protobuf_servers`` entry, which is a sequence of `ProtobufServer`_:
.. code-block:: yaml
protobuf_servers:
- - servers: [6.7.8.9]
- timeout: 2
- maxQueuedEntries: 100
- reconnectWaitTime: 1
- taggedOnly: false
- asyncConnect: false
- logQueries: true
- logResponses: true
- exportTypes: [A, AAAA, CNAME]
- logMappedFrom: false
+ - servers: [127.0.0.1:4578]
+ exportTypes: [A, AAAA]
+ - servers: ['[2001:DB8::1]':7891]
+ logQueries: false
+ logResponses: true
+ exportTypes: [A]
DNSTapFrameStreamServers
^^^^^^^^^^^^^^^^^^^^^^^^
queueNotifyThreshold: 0
reopenInterval: 0
+An example of a ``dnstap_framestream_servers`` entry, which is a sequence of `DNSTapFrameStreamServers`_:
+
+.. code-block:: yaml
+
+ dnstap_framestream_servers:
+ - servers: [127.0.0.1:2024]
+ logQueries: false
+ logResponses: true
DNSTapNODFrameStreamServers
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: yaml
- servers: [] Sequence of strings representing SocketAddress or a socker path
+ servers: [] Sequence of strings representing SocketAddress or a socket path
logNODs: true
logUDRs: false
bufferHint: 0
queueNotifyThreshold: 0
reopenInterval: 0
+An example of a ``dnstap_nod_framestream_servers`` entry, which is a sequence of `DNSTapNODFrameStreamServers`_:
+
+.. code-block:: yaml
+
+ dnstap_nop_framestream_servers:
+ - servers: [127.0.0.1:2024]
+ logNODs: false
+ logUDRs: true
+
SortList
^^^^^^^^
As of version 5.1.0, a sortlist entry is defined as
- subnet: Subnet
order: number
+An example of a ``sortlists`` entry, which is a sequence of `SortList`_:
+
+.. code-block:: yaml
+
+ sortlists:
+ - key: 198.18.0.0/8
+ subnets:
+ - subnet: 233.252.0.0/24
+ order: 10
+ - key: 198.18.1.0/8
+ subnets:
+ - subnet: 198.18.0.0/16
+ order: 20
+ - subnet: 203.0.113.0/24
+ order: 20
+
RPZ
^^^
As of version 5.1.0, an RPZ entry is defined as
dumpFile: string
seedFile: string
-If ``addresses` is empty, the ``name`` field specifies the path name of the RPZ, otherwise the ``name`` field defines the name of the RPZ.
+If ``addresses`` is empty, the ``name`` field specifies the path name of the RPZ, otherwise the ``name`` field defines the name of the RPZ.
+
+
+An example of an ``rpzs`` entry, which is a sequence of `RPZ`_:
+
+.. code-block:: yaml
+
+ rpzs:
+ - name: 'path/to/a/file'
+ - name: 'remote.rpz'
+ addresses: ['192.168.178.99']
+ policyName: mypolicy
ZoneToCache
^^^^^^^^^^^
tsig:
name: name of key
algo: algorithm
- secret: Base64 endcoded secret
+ secret: Base64 encoded secret
refreshPeriod: 86400
retryOnErrorPeriod: 60
maxReceivedMBytes: 0 Zero mean no restrcition
- localAddress: local IP address to bind to.
+ localAddress: local IP address to bind to.
zonemd: One of ignore, validate, require
dnssec: One of ignore, validate, require
-For example, a sequence of two ZoneToCache entries:
+An example of an ``zonetocaches`` entry, which is a sequence of `ZoneToCache`_:
.. code-block:: yaml
zonetocaches:
- - zone: .
- method: url
- sources: ['http://...']
- - zone: example.com
- method: file
- sources: ['dir/example.com.zone']
+ - zone: .
+ method: url
+ sources: ['https://www.example.com/path']
+ - zone: example.com
+ method: file
+ sources: ['dir/example.com.zone']
AllowedAdditionalQType
^^^^^^^^^^^^^^^^^^^^^^
-As of version 5.1.0, an allowed addtional qtype entry is defined as:
+As of version 5.1.0, an allowed additional qtype entry is defined as:
.. code-block:: yaml
targets: [] Sequence of string representing QType
mode: One of Ignore, CacheOnly, CacheOnlyRequireAuth, ResolveImmediately, ResolveDeferred, default CacheOnlyRequireAuth
-For example:
+An example of an ``allowed_additional_qtypes`` entry, which is a sequence of `AllowedAdditionalQType`_:
.. code-block:: yaml
address: IPAddress
domains: [] Sequence of string
-For example:
+An example of an ``proxymappings`` entry, which is a sequence of `ProxyMapping`_:
.. code-block:: yaml
proxymappings:
- - subnet: 192.168.178.0/24
- address: 128.66.1.2
-
+ - subnet: 192.168.178.0/24
+ address: 128.66.1.2
+ - subnet: 192.168.179.0/24
+ address: 128.66.1.3
+ domains:
+ - example.com
+ - example.net
The YAML settings
-----------------
+The notation ``section.name`` means that an entry ``name`` can appear in the YAML section ``section``.
+So the entry ``recordcache.max_ttl`` will end up in settings file as follows:
+
+.. code-block:: yaml
+
+ recordcache:
+ ...
+ max_ttl: 3600
+ ...
+
.. note::
Starting with version 5.0.0, :program:`Recursor` supports a new YAML syntax for configuration files.
A configuration using the old style syntax can be converted to a YAML configuration using the instructions in :doc:`appendices/yamlconversion`.
- In a future release support for the "old-style" settings decribed here will be dropped.
+ In a future release support for the "old-style" settings described here will be dropped.
See :doc:`yamlsettings` for details.
.. note::
#
# For Rust it generates rust/src/lib.rs, containing the structs with
# CXX and Serde annotations and associated code. rust-preamble-in.rs is
-# included before the generated code and rus-bridge-in.rs inside the
+# included before the generated code and rust-bridge-in.rs inside the
# bridge module in the generated lib.rs. Header files generated by CXX
# (lib.rs.h and cxx.h) are copied from deep inside the generated code
# hierarchy into the rust subdir as well.
file.write(f'to_arg(settings.{section}.{name});\n')
file.write('}\n')
-def gen_cxx(entries):
+def gen_cxx(gendir, entries):
"""Generate the C++ code from the defs in table.py"""
- with open('cxxsettings-generated.cc', mode='w', encoding="UTF-8") as file:
+ with open(gendir + '/cxxsettings-generated.cc', mode='w', encoding="UTF-8") as file:
file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n\n')
file.write('#include "arguments.hh"\n')
file.write('#include "cxxsettings.hh"\n')
"""Generate Rust code for the default handling of a vector for typeName"""
ret = f'// DEFAULT HANDLING for {name}\n'
ret += f'fn default_value_{name}() -> Vec<recsettings::{typeName}> {{\n'
- ret += f' let deserialized: Vec<recsettings::{typeName}> = serde_yaml::from_str({quote(defvalue)}).unwrap();\n'
+ ret += f' let msg = "default value defined for `{name}\' should be valid YAML";'
+ ret += f' let deserialized: Vec<recsettings::{typeName}> = serde_yaml::from_str({quote(defvalue)}).expect(&msg);\n'
ret += f' deserialized\n'
ret += '}\n'
ret += f'fn default_value_equal_{name}(value: &Vec<recsettings::{typeName}>)'
name = entry['name']
file.write(f' if m.contains_key("{name}") {{\n')
if rtype in ('bool', 'u64', 'f64', 'String'):
- file.write(f' self.{name} = rhs.{name}.to_owned();\n')
+ file.write(f' rhs.{name}.clone_into(&mut self.{name});\n')
else:
file.write(f' if is_overriding(m, "{name}") || ')
file.write(f'self.{name} == DEFAULT_CONFIG.{section}.{name} {{\n')
file.write(' }\n')
file.write('}\n\n')
-def gen_rust(entries):
+def gen_rust(srcdir, entries):
"""Generate Rust code all entries"""
def_functions = []
sections = {}
- with open('rust/src/lib.rs', mode='w', encoding='UTF-8') as file:
+ with open(srcdir + '/rust/src/lib.rs', mode='w', encoding='UTF-8') as file:
file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
file.write('// START INCLUDE rust-preable-in.rs\n')
- with open('rust-preamble-in.rs', mode='r', encoding='UTF-8') as pre:
+ with open(srcdir + '/rust-preamble-in.rs', mode='r', encoding='UTF-8') as pre:
file.write(pre.read())
file.write('// END INCLUDE rust-preamble-in.rs\n\n')
file.write('#[cxx::bridge(namespace = "pdns::rust::settings::rec")]\n')
file.write('mod recsettings {\n')
- with open('rust-bridge-in.rs', mode='r', encoding='UTF-8') as bridge:
+ with open(srcdir + '/rust-bridge-in.rs', mode='r', encoding='UTF-8') as bridge:
file.write(' // START INCLUDE rust-bridge-in.rs\n')
for line in bridge:
file.write(' ' + line)
else:
file.write(f'.. {name}:: {vers}\n')
-def gen_oldstyle_docs(entries):
+def gen_oldstyle_docs(srcdir, entries):
"""Write old style docs"""
- with open('../docs/settings.rst', mode='w', encoding='UTF-8') as file:
+ with open(srcdir + '/../docs/settings.rst', mode='w', encoding='UTF-8') as file:
file.write('.. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
file.write(' START INCLUDE docs-old-preamble-in.rst\n\n')
- with open('docs-old-preamble-in.rst', mode='r', encoding='UTF-8') as pre:
+ with open(srcdir + '/docs-old-preamble-in.rst', mode='r', encoding='UTF-8') as pre:
file.write(pre.read())
file.write('.. END INCLUDE docs-old-preamble-in.rst\n\n')
arg = arg.replace(key, repl)
return arg
-def gen_newstyle_docs(argentries):
+def gen_newstyle_docs(srcdir, argentries):
"""Write new style docs"""
entries = sorted(argentries, key = lambda entry: [entry['section'], entry['name']])
- with open('../docs/yamlsettings.rst', 'w', encoding='utf-8') as file:
+ with open(srcdir + '/../docs/yamlsettings.rst', 'w', encoding='utf-8') as file:
file.write('.. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
file.write(' START INCLUDE docs-new-preamble-in.rst\n\n')
- with open('docs-new-preamble-in.rst', mode='r', encoding='utf-8') as pre:
+ with open(srcdir + '/docs-new-preamble-in.rst', mode='r', encoding='utf-8') as pre:
file.write(pre.read())
file.write('.. END INCLUDE docs-new-preamble-in.rst\n\n')
RUNTIME = '*runtime determined*'
def generate():
- """Read table, validate and generate C++, Rst and .rst files"""
+ """Read table, validate and generate C++, Rust and .rst files"""
+ srcdir = '.'
+ gendir = '.'
+ if len(sys.argv) == 3:
+ print("Generate: using srcdir and gendir from argumens")
+ srcdir = sys.argv[1]
+ gendir = sys.argv[2]
+
+ print("Generate cwd: " + os.getcwd())
+ print("Generate srcdir: " + srcdir + " = " + os.path.realpath(srcdir))
+ print("Generate gendir: " + gendir + " = " + os.path.realpath(gendir))
+
# read table
- with open('table.py', mode='r', encoding="utf-8") as file:
+ with open(srcdir + '/table.py', mode='r', encoding="utf-8") as file:
entries = eval(file.read())
for entry in entries:
dupcheck1[entry['oldname']] = True
dupcheck2[entry['section'] + '.' + entry['name']] = True
# And generate C++, Rust and docs code based on table
- gen_cxx(entries)
- gen_rust(entries)
+ # C++ code goes int build dir
+ gen_cxx(gendir, entries)
+ # Generate Rust code into src dir, as I did not manage to figure out the Cargo stuff
+ # with mixed sources both in build and src dir
+ gen_rust(srcdir, entries)
# Avoid generating doc files in a sdist based build
if os.path.isdir('../docs'):
- gen_oldstyle_docs(entries)
- gen_newstyle_docs(entries)
-
+ gen_oldstyle_docs(srcdir, entries)
+ gen_newstyle_docs(srcdir, entries)
+ # touch pseudo output file
+ with open(gendir + '/timestamp', mode='w', encoding="utf-8") as file:
+ file.write('')
+ file.close()
generate()
--- /dev/null
+sources = files(
+ 'generate.py',
+ 'docs-new-preamble-in.rst',
+ 'docs-old-preamble-in.rst',
+ 'rust-bridge-in.rs',
+ 'rust-preamble-in.rs',
+ 'table.py',
+)
+
+generated = [
+ 'cxxsettings-generated.cc',
+]
+
+python = find_program('python3')
+
+settings = custom_target(
+ command: [python, '@INPUT0@', '@SOURCE_ROOT@/settings', '@BUILD_ROOT@/settings'],
+ input: sources,
+ output: generated,
+)
+
+# librec_common depends on this, so the sources get linked
+dep_settings_ch = declare_dependency(
+ sources: [settings, 'cxxsupport.cc'],
+ include_directories: [include_directories('.'), ]
+)
+
+# The rust parts depend on this, no sources listed, which avoid duplicates object files
+# In turn deps (defined in the main meson.build file, includes dep_rust_settings)
+dep_settings = declare_dependency(
+ include_directories: [include_directories('.'), ]
+)
+
+subdir('rust')
+
[[package]]
name = "cc"
-version = "1.0.83"
+version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
+checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
[[package]]
name = "codespan-reporting"
[[package]]
name = "cxx"
-version = "1.0.115"
+version = "1.0.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de00f15a6fa069c99b88c5c78c4541d0e7899a33b86f7480e23df2431fce0bc"
+checksum = "bb497fad022245b29c2a0351df572e2d67c1046bcef2260ebc022aec81efea82"
dependencies = [
"cc",
"cxxbridge-flags",
[[package]]
name = "cxx-build"
-version = "1.0.115"
+version = "1.0.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a71e1e631fa2f2f5f92e8b0d860a00c198c6771623a6cefcc863e3554f0d8d6"
+checksum = "9327c7f9fbd6329a200a5d4aa6f674c60ab256525ff0084b52a889d4e4c60cee"
dependencies = [
"cc",
"codespan-reporting",
[[package]]
name = "cxxbridge-flags"
-version = "1.0.115"
+version = "1.0.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f3fed61d56ba497c4efef9144dfdbaa25aa58f2f6b3a7cf441d4591c583745c"
+checksum = "688c799a4a846f1c0acb9f36bb9c6272d9b3d9457f3633c7753c6057270df13c"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.115"
+version = "1.0.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8908e380a8efd42150c017b0cfa31509fc49b6d47f7cb6b33e93ffb8f4e3661e"
+checksum = "928bc249a7e3cd554fd2e8e08a426e9670c50bbfc9a621653cfa9accc9641783"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "hashbrown"
-version = "0.14.3"
+version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "indexmap"
-version = "2.1.0"
+version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
[[package]]
name = "itoa"
-version = "1.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
-
-[[package]]
-name = "libc"
-version = "0.2.152"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "link-cplusplus"
[[package]]
name = "proc-macro2"
-version = "1.0.78"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.35"
+version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
-version = "1.0.16"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "scratch"
[[package]]
name = "serde"
-version = "1.0.195"
+version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
+checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.195"
+version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
+checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "serde_yaml"
-version = "0.9.30"
+version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
[[package]]
name = "settings"
-version = "0.1.0"
+version = "5.1.0"
dependencies = [
"base64",
"cxx",
[[package]]
name = "syn"
-version = "2.0.48"
+version = "2.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "unicode-width"
-version = "0.1.11"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
[[package]]
name = "unsafe-libyaml"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
-name = "winapi"
-version = "0.3.9"
+name = "winapi-util"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
+ "windows-sys",
]
[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
+name = "windows-sys"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
[[package]]
-name = "winapi-util"
-version = "0.1.6"
+name = "windows-targets"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
- "winapi",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
]
[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[package]
name = "settings"
-version = "0.1.0"
+# Convention: major/minor is equal to rec's major/minor
+version = "5.1.0"
edition = "2021"
[lib]
--- /dev/null
+#!/bin/sh -e
+
+#echo "PWD=$PWD"
+#echo "srcdir=$srcdir"
+#echo "builddir=$builddir"
+
+$CARGO build --release $RUST_TARGET --target-dir=$builddir/target --manifest-path $srcdir/Cargo.toml
+
+
+cp -p target/$RUSTC_TARGET_ARCH/release/libsettings.a $builddir/settings/rust/libsettings.a
+cp -p target/$RUSTC_TARGET_ARCH/cxxbridge/settings/src/lib.rs.h $srcdir/lib.rs.h
+cp -p target/$RUSTC_TARGET_ARCH/cxxbridge/settings/src/lib.rs.h $builddir/settings/rust/lib.rs.h
+cp -p target/$RUSTC_TARGET_ARCH/cxxbridge/rust/cxx.h $srcdir/cxx.h
+cp -p target/$RUSTC_TARGET_ARCH/cxxbridge/rust/cxx.h $builddir/settings/rust/cxx.h
--- /dev/null
+
+build = find_program('build_settings')
+cargo = find_program('cargo')
+infile = 'Cargo.toml'
+outfile = 'libsettings.a'
+
+
+env = environment()
+env.append('CARGO', cargo.full_path())
+env.append('SYSCONFDIR', conf.get('SYSCONFDIR'))
+env.append('NODCACHEDIRNOD', conf.get('NODCACHEDIRNOD'))
+env.append('NODCACHEDIRUDR', conf.get('NODCACHEDIRUDR'))
+env.append('builddir', '.')
+env.append('srcdir', meson.current_source_dir())
+env.append('RUST_TARGET', '')
+env.append('RUSTC_TARGET_ARCH', '')
+
+lib_settings = custom_target('libsettings.a',
+ output: [outfile, 'cxx.h'],
+ input: infile,
+ command: [build,
+ ],
+ depend_files: [
+ 'src/bridge.hh',
+ 'src/bridge.rs',
+ 'src/helpers.rs',
+ ],
+ depends: settings,
+ env: env,
+ console: true,
+)
+
+dep_rust_settings = declare_dependency(
+ link_with: lib_settings[0],
+ sources: lib_settings[1],
+ include_directories: [include_directories('.'), include_directories('src')],
+)
pub fn validate_socket_address_or_name(field: &str, val: &String) -> Result<(), ValidationError> {
let sa = validate_socket_address(field, val);
- if sa.is_err() {
- if !isValidHostname(val) {
- let parts: Vec<&str> = val.split(':').collect();
- if parts.len() != 2
- || !isValidHostname(parts[0])
- || !is_port_number(parts[1])
- {
- let msg = format!(
- "{}: value `{}' is not an IP, IP:port, name or name:port combination",
- field, val
- );
- return Err(ValidationError { msg });
- }
+ if sa.is_err() && !isValidHostname(val) {
+ let parts: Vec<&str> = val.split(':').collect();
+ if parts.len() != 2
+ || !isValidHostname(parts[0])
+ || !is_port_number(parts[1])
+ {
+ let msg = format!(
+ "{}: value `{}' is not an IP, IP:port, name or name:port combination",
+ field, val
+ );
+ return Err(ValidationError { msg });
}
}
Ok(())
}
fn validate_address_family(addrfield: &str, localfield: &str, vec: &[String], local_address: &String) -> Result<(), ValidationError> {
- if vec.len() == 0 {
+ if vec.is_empty() {
let msg = format!("{}: cannot be empty", addrfield);
return Err(ValidationError { msg });
}
Therefore, the PowerDNS Recursor by default does not query private space IP addresses.
This setting can be used to expand or reduce the limitations.
-Queries for names in forward zones and to addresses as configured in any of the settings :ref:`setting-forward-zones`, :ref:`setting-forward-zones-file` or :ref:`setting-forward-zones-recurse` are performed regardless of these limitations.
+Queries for names in forward zones and to addresses as configured in any of the settings :ref:`setting-forward-zones`, :ref:`setting-forward-zones-file` or :ref:`setting-forward-zones-recurse` are performed regardless of these limitations. However, if NS records are learned from :ref:`setting-forward-zones` and the IP addresses of the nameservers learned in that way are included in :ref:`setting-dont-query`, lookups relying on these nameservers will fail with SERVFAIL.
''',
},
{
If an ``NS`` record set for a subzone of the forwarded zone is learned, that record set will be used to determine addresses for name servers of the subzone.
This allows e.g. a forward to a local authoritative server holding a copy of the root zone, delegations received from that server will work.
+**Note**: When an ``NS`` record for a subzone is learned and the IP address for that nameserver is included in the IP ranges in :ref:`setting-dont-query`,
+SERVFAIL is returned.
+
**IMPORTANT**: When using DNSSEC validation (which is default), forwards to non-delegated (e.g. internal) zones that have a DNSSEC signed parent zone will validate as Bogus.
To prevent this, add a Negative Trust Anchor (NTA) for this zone in the :ref:`setting-lua-config-file` with ``addNTA('your.zone', 'A comment')``.
If this forwarded zone is signed, instead of adding NTA, add the DS record to the :ref:`setting-lua-config-file`.
If an ``NS`` record set for a subzone of the forwarded zone is learned, that record set will be used to determine addresses for name servers of the subzone.
This allows e.g. a forward to a local authoritative server holding a copy of the root zone, delegations received from that server will work.
+**Note**: When an ``NS`` record for a subzone is learned and the IP address for that nameserver is included in the IP ranges in :ref:`setting-dont-query`,
+SERVFAIL is returned.
+
**IMPORTANT**: When using DNSSEC validation (which is default), forwards to non-delegated (e.g. internal) zones that have a DNSSEC signed parent zone will validate as Bogus.
To prevent this, add a Negative Trust Anchor (NTA) for this zone in the :ref:`setting-lua-config-file` with ``addNTA('your.zone', 'A comment')``.
If this forwarded zone is signed, instead of adding NTA, add the DS record to the :ref:`setting-lua-config-file`.
'section' : 'recursor',
'type' : LType.String,
'default' : '',
- 'help' : 'Include *.conf files from this directory',
+ 'help' : 'Include settings files from this directory.',
'doc' : '''
-Directory to scan for additional config files. All files that end with .conf are loaded in order using ``POSIX`` as locale.
+Directory to scan for additional config files. All files that end with ``.conf`` are loaded in order using ``POSIX`` as locale.
+ ''',
+ 'doc-new' : '''
+Directory to scan for additional config files. All files that end with ``.yml`` are loaded in order using ``POSIX`` as locale.
''',
},
{
'doc' : '''
If set, and Lua support is compiled in, this will load an additional configuration file for newer features and more complicated setups.
See :doc:`lua-config/index` for the options that can be set in this file.
+ ''',
+ },
+ {
+ 'name' : 'lua_global_include_dir',
+ 'section' : 'recursor',
+ 'type' : LType.String,
+ 'default' : '',
+ 'help' : 'More powerful configuration options',
+ 'doc' : '''
+ When creating a Lua context, all ``*.lua`` files in the directory are loaded into the Lua context.
''',
},
{
''',
'versionadded': '4.3.0'
},
+ {
+ 'name': 'max_chain_length',
+ 'section': 'recursor',
+ 'type': LType.Uint64,
+ 'default': '0',
+ 'help': 'maximum number of queries that can be chained to an outgoing request, 0 is no limit',
+ 'doc': '''
+The maximum number of queries that can be attached to an outgoing request chain. Attaching requests to a chain
+saves on outgoing queries, but the processing of a chain when the reply to the outgoing query comes in
+might result in a large outgoing traffic spike. Reducing the maximum chain length mitigates this.
+If this value is zero, no maximum is enforced, though the maximum number of mthreads (:ref:`setting-max-mthreads`)
+also limits the chain length.
+''',
+ 'versionadded': '5.1.0'
+ },
{
'name' : 'max_include_depth',
'section' : 'recursor',
'default' : '2048',
'help' : 'Maximum number of simultaneous Mtasker threads',
'doc' : '''
-Maximum number of simultaneous MTasker threads.
+Maximum number of simultaneous MTasker threads, per worker thread.
''',
},
{
''',
'versionchanged': ('5.1.0', 'The default used to be 60, with an extra allowance if qname minimization was enabled. Having better algorithms allows for a lower default limit.'),
},
+ {
+ 'name' : 'max_cnames_followed',
+ 'section' : 'recursor',
+ 'type' : LType.Uint64,
+ 'default' : '10',
+ 'help' : 'Maximum number CNAME records followed',
+ 'doc' : '''
+Maximum length of a CNAME chain. If a CNAME chain exceeds this length, a ``ServFail`` answer will be returned.
+Previously, this limit was fixed at 10.
+ ''',
+ 'versionadded': '5.1.0'
+ },
{
'name' : 'max_ns_address_qperq',
'section' : 'outgoing',
If a domain is specified, then each time a newly observed domain is
detected, the recursor will perform an A record lookup of '<newly
observed domain>.<lookup domain>'. For example if 'new-domain-lookup'
-is configured as 'nod.powerdns.com', and a new domain 'xyz123.tv' is
+is configured as 'nod.powerdns.com', and a new domain 'example.com' is
detected, then an A record lookup will be made for
-'xyz123.tv.nod.powerdns.com'. This feature gives a way to share the
+'example.com.nod.powerdns.com'. This feature gives a way to share the
newly observed domain with partners, vendors or security teams. The
result of the DNS lookup will be ignored by the recursor.
''',
Interval (in seconds) to write the NOD and UDR DB snapshots.
Set to zero to disable snapshot writing.',
''',
- 'versionadded': '5.1.0'
+ 'versionadded': '5.1.0'
},
{
'name' : 'whitelist',
'doc' : '''
This setting is a list of all domains (and implicitly all subdomains)
that will never be considered a new domain. For example, if the domain
-'xyz123.tv' is in the list, then 'foo.bar.xyz123.tv' will never be
+'example.com' is in the list, then 'foo.bar.example.com' will never be
considered a new domain. One use-case for the ignore list is to never
reveal details of internal subdomains via the new-domain-lookup
feature.
''',
'versionadded': '4.5.0'
},
+ {
+ 'name' : 'ignore_list_file',
+ 'section' : 'nod',
+ 'type' : LType.String,
+ 'oldname' : 'new-domain-ignore-list-file',
+ 'default' : '',
+ 'help' : 'File with a list of domains (and implicitly all subdomains) which will never be considered a new domain',
+ 'doc' : '''
+Path to a file with a list of domains. File should have one domain per line,
+with no extra characters or comments.
+See :ref:`setting-new-domain-ignore-list`.
+ ''',
+ 'versionadded': '5.1.0'
+ },
{
'name' : 'pb_tag',
'section' : 'nod',
'help' : 'Wait this number of milliseconds for network i/o',
'doc' : '''
Number of milliseconds to wait for a remote authoritative server to respond.
+If the number of concurrent requests is high, the :program:Recursor uses a lower value.
''',
},
{
''',
'versionadded': '4.2.0'
},
+ {
+ 'name' : 'unique_response_ignore_list',
+ 'section' : 'nod',
+ 'type' : LType.ListStrings,
+ 'default' : '',
+ 'help' : 'List of domains (and implicitly all subdomains) which will never be considered for UDR',
+ 'doc' : '''
+This setting is a list of all domains (and implicitly all subdomains)
+that will never be considered for new unique domain responses.
+For example, if the domain 'example.com' is in the list, then 'foo.bar.example.com'
+will never be considered for a new unique domain response.
+''',
+ 'versionadded': '5.1.0'
+ },
+ {
+ 'name' : 'unique_response_ignore_list_file',
+ 'section' : 'nod',
+ 'type' : LType.String,
+ 'default' : '',
+ 'help' : 'File with list of domains (and implicitly all subdomains) which will never be considered for UDR',
+ 'doc' : '''
+Path to a file with a list of domains. File should have one domain per line,
+with no extra characters or comments.
+See :ref:`setting-unique-response-ignore-list`.
+''',
+ 'versionadded': '5.1.0'
+ },
{
'name' : 'use_incoming_edns_subnet',
'section' : 'incoming',
static LockGuarded<nsspeeds_t> s_nsSpeeds;
-template <class Thing>
-class Throttle : public boost::noncopyable
+class Throttle
{
public:
+ Throttle() = default;
+ ~Throttle() = default;
+ Throttle(Throttle&&) = delete;
+ Throttle& operator=(const Throttle&) = default;
+ Throttle& operator=(Throttle&&) = delete;
+ Throttle(const Throttle&) = delete;
+
+ using Key = std::tuple<ComboAddress, DNSName, QType>;
+ using Reason = SyncRes::ThrottleReason;
+
struct entry_t
{
- entry_t(const Thing& thing_, time_t ttd_, unsigned int count_) :
- thing(thing_), ttd(ttd_), count(count_)
+ entry_t(Key thing_, time_t ttd_, unsigned int count_, Reason reason_) :
+ thing(std::move(thing_)), ttd(ttd_), count(count_), reason(reason_)
{
}
- Thing thing;
+ Key thing;
time_t ttd;
mutable unsigned int count;
+ Reason reason;
};
using cont_t = multi_index_container<entry_t,
indexed_by<
- ordered_unique<tag<Thing>, member<entry_t, Thing, &entry_t::thing>>,
+ ordered_unique<tag<Key>, member<entry_t, Key, &entry_t::thing>>,
ordered_non_unique<tag<time_t>, member<entry_t, time_t, &entry_t::ttd>>>>;
- bool shouldThrottle(time_t now, const Thing& arg)
+ bool shouldThrottle(time_t now, const Key& arg)
{
auto iter = d_cont.find(arg);
if (iter == d_cont.end()) {
return true; // still listed, still blocked
}
- void throttle(time_t now, const Thing& arg, time_t ttl, unsigned int count)
+ void throttle(time_t now, const Key& arg, time_t ttl, unsigned int count, Reason reason)
{
auto iter = d_cont.find(arg);
time_t ttd = now + ttl;
if (iter == d_cont.end()) {
- d_cont.emplace(arg, ttd, count);
+ d_cont.emplace(arg, ttd, count, reason);
}
else if (ttd > iter->ttd || count > iter->count) {
ttd = std::max(iter->ttd, ttd);
count = std::max(iter->count, count);
- auto& ind = d_cont.template get<Thing>();
- ind.modify(iter, [ttd, count](entry_t& entry) { entry.ttd = ttd; entry.count = count; });
+ auto& ind = d_cont.template get<Key>();
+ ind.modify(iter, [ttd, count, reason](entry_t& entry) {
+ entry.ttd = ttd;
+ entry.count = count;
+ entry.reason = reason;
+ });
}
}
d_cont.clear();
}
- void clear(const Thing& thing)
+ void clear(const Key& thing)
{
d_cont.erase(thing);
}
ind.erase(ind.begin(), ind.upper_bound(now));
}
+ static std::string toString(Reason reason)
+ {
+ static const std::array<std::string, 10> reasons = {
+ "None",
+ "ServerDown",
+ "PermanentError",
+ "Timeout",
+ "ParseError",
+ "RCodeServFail",
+ "RCodeRefused",
+ "RCodeOther",
+ "TCPTruncate",
+ "Lame"};
+ const auto index = static_cast<unsigned int>(reason);
+ if (index >= reasons.size()) {
+ return "?";
+ }
+ return reasons.at(index);
+ }
+
private:
cont_t d_cont;
};
-static LockGuarded<Throttle<std::tuple<ComboAddress, DNSName, QType>>> s_throttle;
+static LockGuarded<Throttle> s_throttle;
struct SavedParentEntry
{
EDNSSubnetOpts SyncRes::s_ecsScopeZero;
string SyncRes::s_serverID;
SyncRes::LogMode SyncRes::s_lm;
-const std::unordered_set<QType> SyncRes::s_redirectionQTypes = {QType::CNAME, QType::DNAME};
static LockGuarded<fails_t<ComboAddress>> s_fails;
static LockGuarded<fails_t<DNSName>> s_nonresolving;
int SyncRes::s_event_trace_enabled;
bool SyncRes::s_save_parent_ns_set;
unsigned int SyncRes::s_max_busy_dot_probes;
-unsigned int SyncRes::s_max_CNAMES_followed = 10;
+unsigned int SyncRes::s_max_CNAMES_followed;
bool SyncRes::s_addExtendedResolutionDNSErrors;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
s_throttle.lock()->clear(std::tuple(server, name, qtype));
}
-void SyncRes::doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries)
+void SyncRes::doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries, Throttle::Reason reason)
{
- s_throttle.lock()->throttle(now, std::tuple(server, g_rootdnsname, 0), duration, tries);
+ s_throttle.lock()->throttle(now, std::tuple(server, g_rootdnsname, 0), duration, tries, reason);
}
-void SyncRes::doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries)
+void SyncRes::doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries, Throttle::Reason reason)
{
- s_throttle.lock()->throttle(now, std::tuple(server, name, qtype), duration, tries);
+ s_throttle.lock()->throttle(now, std::tuple(server, name, qtype), duration, tries, reason);
}
uint64_t SyncRes::doDumpThrottleMap(int fileDesc)
return 0;
}
fprintf(filePtr.get(), "; throttle map dump follows\n");
- fprintf(filePtr.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
+ fprintf(filePtr.get(), "; remote IP\tqname\tqtype\tcount\tttd\treason\n");
uint64_t count = 0;
// Get a copy to avoid holding the lock while doing I/O
for (const auto& iter : throttleMap) {
count++;
timebuf_t tmp;
- // remote IP, dns name, qtype, count, ttd
- fprintf(filePtr.get(), "%s\t%s\t%s\t%u\t%s\n", std::get<0>(iter.thing).toString().c_str(), std::get<1>(iter.thing).toLogString().c_str(), std::get<2>(iter.thing).toString().c_str(), iter.count, timestamp(iter.ttd, tmp));
+ // remote IP, dns name, qtype, count, ttd, reason
+ fprintf(filePtr.get(), "%s\t%s\t%s\t%u\t%s\t%s\n", std::get<0>(iter.thing).toString().c_str(), std::get<1>(iter.thing).toLogString().c_str(), std::get<2>(iter.thing).toString().c_str(), iter.count, timestamp(iter.ttd, tmp), Throttle::toString(iter.reason).c_str());
}
return count;
ret = asyncresolve(address, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, d_outgoingProtobufServers, d_frameStreamServers, luaconfsLocal->outgoingProtobufExportConfig.exportTypes, res, chained);
}
- if (ret == LWResult::Result::PermanentError || ret == LWResult::Result::OSLimitError || ret == LWResult::Result::Spoofed) {
+ if (ret == LWResult::Result::PermanentError || LWResult::isLimitError(ret) || ret == LWResult::Result::Spoofed) {
break; // transport error, nothing to learn here
}
g_recCache->doWipeCache(subdomain, false, QType::NS);
}
if (!missing.empty() && missing.size() < nsVector.size()) {
- // We miss glue, but we have a chance to resolve it, since we do have address(es) for at least one NS
+ // We miss glue, but we have a chance to resolve it
+ // Pick a few and push async tasks to resolve them
+ const unsigned int max = 2;
+ unsigned int counter = 0;
+ shuffle(missing.begin(), missing.end(), pdns::dns_random_engine());
for (const auto& name : missing) {
if (s_doIPv4 && pushResolveIfNotInNegCache(name, QType::A, d_now)) {
LOG(prefix << qname << ": A glue for " << subdomain << " NS " << name << " missing, pushed task to resolve" << endl);
+ counter++;
}
if (s_doIPv6 && pushResolveIfNotInNegCache(name, QType::AAAA, d_now)) {
LOG(prefix << qname << ": AAAA glue for " << subdomain << " NS " << name << " missing, pushed task to resolve" << endl);
+ counter++;
+ }
+ if (counter >= max) {
+ break;
}
}
}
static void allowAdditionalEntry(std::unordered_set<DNSName>& allowedAdditionals, const DNSRecord& rec)
{
+ // As we only use a limited amount of NS names for resolving, limit number of additional names as
+ // well. s_maxnsperresolve is a proper limit for the NS case and is also reasonable for other
+ // qtypes. Allow one extra for qname itself, which is always in allowedAdditionals.
+ if (SyncRes::s_maxnsperresolve > 0 && allowedAdditionals.size() > SyncRes::s_maxnsperresolve + 1) {
+ return;
+ }
switch (rec.d_type) {
case QType::MX:
if (auto mxContent = getRR<MXRecordContent>(rec)) {
}
}
+static bool isRedirection(QType qtype)
+{
+ return qtype == QType::CNAME || qtype == QType::DNAME;
+}
+
void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType qtype, const DNSName& auth, bool wasForwarded, bool rdQuery)
{
const bool wasForwardRecurse = wasForwarded && rdQuery;
/* list of names for which we will allow A and AAAA records in the additional section
to remain */
std::unordered_set<DNSName> allowedAdditionals = {qname};
+ std::unordered_set<DNSName> allowedAnswerNames = {qname};
bool haveAnswers = false;
bool isNXDomain = false;
bool isNXQType = false;
- for (auto rec = lwr.d_records.begin(); rec != lwr.d_records.end();) {
+ std::vector<bool> skipvec(lwr.d_records.size(), false);
+ unsigned int counter = 0;
+ unsigned int skipCount = 0;
+
+ for (auto rec = lwr.d_records.cbegin(); rec != lwr.d_records.cend(); ++rec, ++counter) {
+ // Allow OPT record containing EDNS(0) data
if (rec->d_type == QType::OPT) {
- ++rec;
continue;
}
+ // Disallow QClass != IN
if (rec->d_class != QClass::IN) {
LOG(prefix << qname << ": Removing non internet-classed data received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
+ skipvec[counter] = true;
+ ++skipCount;
continue;
}
+ // Disallow QType ANY in responses
if (rec->d_type == QType::ANY) {
LOG(prefix << qname << ": Removing 'ANY'-typed data received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
+ skipvec[counter] = true;
+ ++skipCount;
continue;
}
+ // Disallow any name not part of auth requested (i.e. disallow x.y.z if asking a NS authoritative for x.w.z)
if (!rec->d_name.isPartOf(auth)) {
- LOG(prefix << qname << ": Removing record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the " << (int)rec->d_place << " section received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
+ LOG(prefix << qname << ": Removing record '" << rec->toString() << "' in the " << DNSResourceRecord::placeString(rec->d_place) << " section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
continue;
}
- /* dealing with the records in answer */
- if (!(lwr.d_aabit || wasForwardRecurse) && rec->d_place == DNSResourceRecord::ANSWER) {
- /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
- are sending such responses */
- if (rec->d_type != QType::CNAME || qname != rec->d_name) {
- LOG(prefix << qname << ": Removing record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the answer section without the AA bit set received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
- continue;
- }
- }
-
+ // Disallow QType DNAME in non-answer section or containing an answer that is not a parent of or equal to the question name
+ // i.e. disallowed bar.example.com. DNAME bar.example.net. when asking foo.example.com
+ // But allow it when asking for foo.bar.example.com.
if (rec->d_type == QType::DNAME && (rec->d_place != DNSResourceRecord::ANSWER || !qname.isPartOf(rec->d_name))) {
- LOG(prefix << qname << ": Removing invalid DNAME record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the " << (int)rec->d_place << " section received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
+ LOG(prefix << qname << ": Removing invalid DNAME record '" << rec->toString() << "' in the " << DNSResourceRecord::placeString(rec->d_place) << " section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
continue;
}
- if (rec->d_place == DNSResourceRecord::ANSWER && (qtype != QType::ANY && rec->d_type != qtype.getCode() && s_redirectionQTypes.count(rec->d_type) == 0 && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG)) {
- LOG(prefix << qname << ": Removing irrelevant record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the ANSWER section received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
- continue;
- }
+ /* dealing with the records in answer */
+ if (rec->d_place == DNSResourceRecord::ANSWER) {
+ // Special case for Amazon CNAME records
+ if (!(lwr.d_aabit || wasForwardRecurse)) {
+ /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
+ are sending such responses */
+ if (rec->d_type != QType::CNAME || qname != rec->d_name) {
+ LOG(prefix << qname << ": Removing record '" << rec->toString() << "' in the ANSWER section without the AA bit set received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
+ continue;
+ }
+ }
+ // Disallow answer records not answering the QType requested. ANY, CNAME, DNAME, RRSIG complicate matters here
+ if (qtype != QType::ANY && rec->d_type != qtype.getCode() && !isRedirection(rec->d_type) && rec->d_type != QType::RRSIG) {
+ LOG(prefix << qname << ": Removing irrelevant record '" << rec->toString() << "' in the ANSWER section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
+ continue;
+ }
- if (rec->d_place == DNSResourceRecord::ANSWER && !haveAnswers) {
haveAnswers = true;
- }
-
- if (rec->d_place == DNSResourceRecord::ANSWER) {
+ if (rec->d_type == QType::CNAME) {
+ if (auto cnametarget = getRR<CNAMERecordContent>(*rec); cnametarget != nullptr) {
+ allowedAnswerNames.insert(cnametarget->getTarget());
+ }
+ }
+ else if (rec->d_type == QType::DNAME) {
+ // We have checked the DNAME rec->d_name above, the actual answer will be synthesized in a later step
+ allowedAnswerNames.insert(rec->d_name);
+ }
allowAdditionalEntry(allowedAdditionals, *rec);
}
/* dealing with the records in authority */
- if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type != QType::NS && rec->d_type != QType::DS && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG && rec->d_type != QType::NSEC && rec->d_type != QType::NSEC3) {
- LOG(prefix << qname << ": Removing irrelevant record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the AUTHORITY section received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
- continue;
- }
-
- if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::SOA) {
- if (!qname.isPartOf(rec->d_name)) {
- LOG(prefix << qname << ": Removing irrelevant SOA record '" << rec->d_name << "|" << rec->getContent()->getZoneRepresentation() << "' in the AUTHORITY section received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
+ // Only allow NS, DS, SOA, RRSIG, NSEC, NSEC3 in AUTHORITY section
+ else if (rec->d_place == DNSResourceRecord::AUTHORITY) {
+ if (rec->d_type != QType::NS && rec->d_type != QType::DS && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG && rec->d_type != QType::NSEC && rec->d_type != QType::NSEC3) {
+ LOG(prefix << qname << ": Removing irrelevant record '" << rec->toString() << "' in the AUTHORITY section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
continue;
}
-
- if (!(lwr.d_aabit || wasForwardRecurse)) {
- LOG(prefix << qname << ": Removing irrelevant record (AA not set) '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the AUTHORITY section received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
+ if (rec->d_type == QType::NS && !d_updatingRootNS && rec->d_name == g_rootdnsname) {
+ /*
+ * We don't want to pick up root NS records in AUTHORITY and their associated ADDITIONAL sections of random queries.
+ * So remove them and don't add them to allowedAdditionals.
+ */
+ LOG(prefix << qname << ": Removing NS record '" << rec->toString() << "' in the AUTHORITY section of a response received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
continue;
}
- if (!haveAnswers) {
- if (lwr.d_rcode == RCode::NXDomain) {
- isNXDomain = true;
+ if (rec->d_type == QType::SOA) {
+ // Disallow a SOA record with a name that is not a parent of or equal to the name we asked
+ if (!qname.isPartOf(rec->d_name)) {
+ LOG(prefix << qname << ": Removing irrelevant SOA record '" << rec->toString() << "' in the AUTHORITY section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
+ continue;
+ }
+ // Disallow SOA without AA bit (except for forward with RD=1)
+ if (!(lwr.d_aabit || wasForwardRecurse)) {
+ LOG(prefix << qname << ": Removing irrelevant record (AA not set) '" << rec->toString() << "' in the AUTHORITY section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
+ continue;
}
- else if (lwr.d_rcode == RCode::NoError) {
- isNXQType = true;
+
+ if (!haveAnswers) {
+ switch (lwr.d_rcode) {
+ case RCode::NXDomain:
+ isNXDomain = true;
+ break;
+ case RCode::NoError:
+ isNXQType = true;
+ break;
+ }
}
}
}
+ /* dealing with records in additional */
+ else if (rec->d_place == DNSResourceRecord::ADDITIONAL) {
+ if (rec->d_type != QType::A && rec->d_type != QType::AAAA && rec->d_type != QType::RRSIG) {
+ LOG(prefix << qname << ": Removing irrelevant record '" << rec->toString() << "' in the ADDITIONAL section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
+ continue;
+ }
+ }
+ } // end of first loop, handled answer and most of authority section
- if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS && (isNXDomain || isNXQType)) {
- /*
- * We don't want to pick up NS records in AUTHORITY and their ADDITIONAL sections of NXDomain answers
- * because they are somewhat easy to insert into a large, fragmented UDP response
- * for an off-path attacker by injecting spoofed UDP fragments. So do not add these to allowedAdditionals.
- */
- LOG(prefix << qname << ": Removing NS record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the " << (int)rec->d_place << " section of a " << (isNXDomain ? "NXD" : "NXQTYPE") << " response received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
+ sanitizeRecordsPass2(prefix, lwr, qname, auth, allowedAnswerNames, allowedAdditionals, isNXDomain, isNXQType, skipvec, skipCount);
+}
+
+void SyncRes::sanitizeRecordsPass2(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, std::unordered_set<DNSName>& allowedAnswerNames, std::unordered_set<DNSName>& allowedAdditionals, bool isNXDomain, bool isNXQType, std::vector<bool>& skipvec, unsigned int& skipCount)
+{
+ // Second loop, we know now if the answer was NxDomain or NoData
+ unsigned int counter = 0;
+ for (auto rec = lwr.d_records.cbegin(); rec != lwr.d_records.cend(); ++rec, ++counter) {
+
+ if (skipvec[counter]) {
continue;
}
-
- if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS && !d_updatingRootNS && rec->d_name == g_rootdnsname) {
- /*
- * We don't want to pick up root NS records in AUTHORITY and their associated ADDITIONAL sections of random queries.
- * So don't add them to allowedAdditionals.
- */
- LOG(prefix << qname << ": Removing NS record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the " << (int)rec->d_place << " section of a response received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
+ // Allow OPT record containing EDNS(0) data
+ if (rec->d_type == QType::OPT) {
continue;
}
+ if (rec->d_place == DNSResourceRecord::ANSWER) {
+ if (allowedAnswerNames.count(rec->d_name) == 0) {
+ LOG(prefix << qname << ": Removing irrelevent record '" << rec->toString() << "' in the ANSWER section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
+ continue;
+ }
+ }
if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS) {
+ if (isNXDomain || isNXQType) {
+ /*
+ * We don't want to pick up NS records in AUTHORITY and their ADDITIONAL sections of NXDomain answers
+ * because they are somewhat easy to insert into a large, fragmented UDP response
+ * for an off-path attacker by injecting spoofed UDP fragments. So do not add these to allowedAdditionals.
+ */
+ LOG(prefix << qname << ": Removing NS record '" << rec->toString() << "' in the AUTHORITY section of a " << (isNXDomain ? "NXD" : "NXQTYPE") << " response received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
+ continue;
+ }
allowAdditionalEntry(allowedAdditionals, *rec);
}
-
/* dealing with the records in additional */
- if (rec->d_place == DNSResourceRecord::ADDITIONAL && rec->d_type != QType::A && rec->d_type != QType::AAAA && rec->d_type != QType::RRSIG) {
- LOG(prefix << qname << ": Removing irrelevant record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the ADDITIONAL section received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
- continue;
+ else if (rec->d_place == DNSResourceRecord::ADDITIONAL) {
+ if (allowedAdditionals.count(rec->d_name) == 0) {
+ LOG(prefix << qname << ": Removing irrelevant record '" << rec->toString() << "' in the ADDITIONAL section received from " << auth << endl);
+ skipvec[counter] = true;
+ ++skipCount;
+ continue;
+ }
}
-
- if (rec->d_place == DNSResourceRecord::ADDITIONAL && allowedAdditionals.count(rec->d_name) == 0) {
- LOG(prefix << qname << ": Removing irrelevant additional record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the ADDITIONAL section received from " << auth << endl);
- rec = lwr.d_records.erase(rec);
- continue;
+ }
+ if (skipCount > 0) {
+ std::vector<DNSRecord> vec;
+ vec.reserve(lwr.d_records.size() - skipCount);
+ for (counter = 0; counter < lwr.d_records.size(); ++counter) {
+ if (!skipvec[counter]) {
+ vec.emplace_back(std::move(lwr.d_records[counter]));
+ }
}
-
- ++rec;
+ lwr.d_records = std::move(vec);
}
}
negIndicHasSignatures = !negEntry.authoritySOA.signatures.empty() || !negEntry.DNSSECRecords.signatures.empty();
negindic = true;
}
- else if (rec.d_place == DNSResourceRecord::ANSWER && s_redirectionQTypes.count(rec.d_type) > 0 && // CNAME or DNAME answer
- s_redirectionQTypes.count(qtype.getCode()) == 0) { // But not in response to a CNAME or DNAME query
+ else if (rec.d_place == DNSResourceRecord::ANSWER && isRedirection(rec.d_type) && // CNAME or DNAME answer
+ !isRedirection(qtype.getCode())) { // But not in response to a CNAME or DNAME query
if (rec.d_type == QType::CNAME && rec.d_name == qname) {
if (!dnameOwner.empty()) { // We synthesize ourselves
continue;
}
}
+void SyncRes::incTimeoutStats(const ComboAddress& remoteIP)
+{
+ d_timeouts++;
+ t_Counters.at(rec::Counter::outgoingtimeouts)++;
+
+ if (remoteIP.sin4.sin_family == AF_INET) {
+ t_Counters.at(rec::Counter::outgoing4timeouts)++;
+ }
+ else {
+ t_Counters.at(rec::Counter::outgoing6timeouts)++;
+ }
+
+ if (t_timeouts) {
+ t_timeouts->push_back(remoteIP);
+ }
+}
+
bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, boost::optional<EDNSExtendedError>& extendedError, bool dontThrottle)
{
bool chained = false;
if (resolveret != LWResult::Result::Success) {
/* Error while resolving */
if (resolveret == LWResult::Result::Timeout) {
- /* Time out */
-
LOG(prefix << qname << ": Timeout resolving after " << lwr.d_usec / 1000.0 << " ms " << (doTCP ? "over TCP" : "") << endl);
- d_timeouts++;
- t_Counters.at(rec::Counter::outgoingtimeouts)++;
-
- if (remoteIP.sin4.sin_family == AF_INET) {
- t_Counters.at(rec::Counter::outgoing4timeouts)++;
- }
- else {
- t_Counters.at(rec::Counter::outgoing6timeouts)++;
- }
-
- if (t_timeouts) {
- t_timeouts->push_back(remoteIP);
- }
+ incTimeoutStats(remoteIP);
}
else if (resolveret == LWResult::Result::OSLimitError) {
/* OS resource limit reached */
LOG(prefix << qname << ": Hit a local resource limit resolving" << (doTCP ? " over TCP" : "") << ", probable error: " << stringerror() << endl);
t_Counters.at(rec::Counter::resourceLimits)++;
}
+ else if (resolveret == LWResult::Result::ChainLimitError) {
+ /* Chain resource limit reached */
+ LOG(prefix << qname << ": Hit a chain limit resolving" << (doTCP ? " over TCP" : ""));
+ t_Counters.at(rec::Counter::chainLimits)++;
+ }
else {
/* LWResult::Result::PermanentError */
t_Counters.at(rec::Counter::unreachables)++;
// don't account for resource limits, they are our own fault
// And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
- if (resolveret != LWResult::Result::OSLimitError && !chained && !dontThrottle) {
- s_nsSpeeds.lock()->find_or_enter(nsName.empty() ? DNSName(remoteIP.toStringWithPort()) : nsName, d_now).submit(remoteIP, 1000000, d_now); // 1 sec
+ if (!LWResult::isLimitError(resolveret) && !chained && !dontThrottle) {
+ uint32_t responseUsec = 1000000; // 1 sec for non-timeout cases
+ // Use the actual time if we saw a timeout
+ if (resolveret == LWResult::Result::Timeout) {
+ responseUsec = lwr.d_usec;
+ }
+
+ s_nsSpeeds.lock()->find_or_enter(nsName.empty() ? DNSName(remoteIP.toStringWithPort()) : nsName, d_now).submit(remoteIP, static_cast<int>(responseUsec), d_now);
// make sure we don't throttle the root
if (s_serverdownmaxfails > 0 && auth != g_rootdnsname && s_fails.lock()->incr(remoteIP, d_now) >= s_serverdownmaxfails) {
LOG(prefix << qname << ": Max fails reached resolving on " << remoteIP.toString() << ". Going full throttle for " << s_serverdownthrottletime << " seconds" << endl);
// mark server as down
- doThrottle(d_now.tv_sec, remoteIP, s_serverdownthrottletime, 10000);
+ doThrottle(d_now.tv_sec, remoteIP, s_serverdownthrottletime, 10000, Throttle::Reason::ServerDown);
}
else if (resolveret == LWResult::Result::PermanentError) {
// unreachable, 1 minute or 100 queries
- doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 100);
+ doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 100, Throttle::Reason::PermanentError);
}
else {
- // timeout, 10 seconds or 5 queries
- doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 10, 5);
+ // If the actual response time was more than 80% of the default timeout, we throttle. On a
+ // busy rec we reduce the time we are willing to wait for an auth, it is unfair to throttle on
+ // such a shortened timeout.
+ if (responseUsec > g_networkTimeoutMsec * 800) {
+ // timeout, 10 seconds or 5 queries
+ doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 10, 5, Throttle::Reason::Timeout);
+ }
}
}
if (doTCP) {
// we can be more heavy-handed over TCP
- doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 10);
+ doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 10, Throttle::Reason::ParseError);
}
else {
- doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 10, 2);
+ doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 10, 2, Throttle::Reason::ParseError);
}
}
return false;
s_nsSpeeds.lock()->find_or_enter(nsName.empty() ? DNSName(remoteIP.toStringWithPort()) : nsName, d_now).submit(remoteIP, 1000000, d_now); // 1 sec
}
else {
- doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 3);
+ Throttle::Reason reason{};
+ switch (lwr.d_rcode) {
+ case RCode::ServFail:
+ reason = Throttle::Reason::RCodeServFail;
+ break;
+ case RCode::Refused:
+ reason = Throttle::Reason::RCodeRefused;
+ break;
+ default:
+ reason = Throttle::Reason::RCodeOther;
+ break;
+ }
+ doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 3, reason);
}
}
return false;
LOG(prefix << qname << ": Truncated bit set, over TCP?" << endl);
if (!dontThrottle) {
/* let's treat that as a ServFail answer from this server */
- doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 3);
+ doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 3, Throttle::Reason::TCPTruncate);
}
return false;
}
}
/* was lame */
if (!shouldNotThrottle(&tns->first, &*remoteIP)) {
- doThrottle(d_now.tv_sec, *remoteIP, qname, qtype, 60, 100);
+ doThrottle(d_now.tv_sec, *remoteIP, qname, qtype, 60, 100, Throttle::Reason::Lame);
}
}
static void clearThrottle();
static bool isThrottled(time_t now, const ComboAddress& server, const DNSName& target, QType qtype);
static bool isThrottled(time_t now, const ComboAddress& server);
- static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries);
- static void doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries);
+
+ enum class ThrottleReason : uint8_t
+ {
+ None,
+ ServerDown,
+ PermanentError,
+ Timeout,
+ ParseError,
+ RCodeServFail,
+ RCodeRefused,
+ RCodeOther,
+ TCPTruncate,
+ Lame,
+ };
+ static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries, ThrottleReason reason);
+ static void doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries, ThrottleReason reason);
static void unThrottle(const ComboAddress& server, const DNSName& qname, QType qtype);
static uint64_t getFailedServersSize();
static EDNSSubnetOpts s_ecsScopeZero;
static LogMode s_lm;
static std::unique_ptr<NetmaskGroup> s_dontQuery;
- const static std::unordered_set<QType> s_redirectionQTypes;
struct GetBestNSAnswer
{
unsigned int depth, const string& prefix, set<GetBestNSAnswer>& beenthere, Context& context, StopAtDelegation* stopAtDelegation,
std::map<DNSName, std::vector<ComboAddress>>* fallback);
void ednsStats(boost::optional<Netmask>& ednsmask, const DNSName& qname, const string& prefix);
+ void incTimeoutStats(const ComboAddress& remoteIP);
bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, QType qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool sendRDQuery, bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, boost::optional<EDNSExtendedError>& extendedError, bool dontThrottle = false);
bool processAnswer(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask>& ednsmask, bool sendRDQuery, NsSet& nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP);
vector<ComboAddress> retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<std::pair<DNSName, float>>::const_iterator& tns, unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<std::pair<DNSName, float>>& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly, unsigned int& nretrieveAddressesForNS);
void sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
+ void sanitizeRecordsPass2(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, std::unordered_set<DNSName>& allowedAnswerNames, std::unordered_set<DNSName>& allowedAdditionals, bool isNXDomain, bool isNXQType, std::vector<bool>& skipvec, unsigned int& skipCount);
/* This function will check whether the answer should have the AA bit set, and will set if it should be set and isn't.
This is unfortunately needed to deal with very crappy so-called DNS servers */
void fixupAnswer(const std::string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
/* external functions, opaque to us */
LWResult::Result asendtcp(const PacketBuffer& data, shared_ptr<TCPIOHandler>&);
LWResult::Result arecvtcp(PacketBuffer& data, size_t len, shared_ptr<TCPIOHandler>&, bool incompleteOkay);
+void mthreadSleep(unsigned int jitterMsec);
enum TCPAction : uint8_t
{
PacketBuffer inMSG; // they'll go here
PacketBuffer outMSG; // the outgoing message that needs to be sent
- using chain_t = set<uint16_t>;
- mutable chain_t chain;
+ using chain_t = set<std::pair<int, uint16_t>>;
+ mutable chain_t authReqChain;
shared_ptr<TCPIOHandler> tcphandler{nullptr};
+ timeval creationTime{};
string::size_type inPos{0}; // how far are we along in the inMSG
size_t inWanted{0}; // if this is set, we'll read until inWanted bytes are read
string::size_type outPos{0}; // how far we are along in the outMSG
--- /dev/null
+../test-sholder_hh.cc
\ No newline at end of file
std::unique_ptr<MemRecursorCache> g_recCache;
std::unique_ptr<NegCache> g_negCache;
bool g_lowercaseOutgoing = false;
-#if 0
-pdns::TaskQueue g_test_tasks;
-pdns::TaskQueue g_resolve_tasks;
-#endif
+unsigned int g_networkTimeoutMsec = 1500;
+
/* Fake some required functions we didn't want the trouble to
link with */
ArgvMap& arg()
SyncRes::s_locked_ttlperc = 0;
SyncRes::s_minimize_one_label = 4;
SyncRes::s_max_minimize_count = 10;
+ SyncRes::s_max_CNAMES_followed = 10;
SyncRes::clearNSSpeeds();
BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0U);
return LWResult::Result::Success;
}
downServers.insert(address);
+ res->d_usec = g_networkTimeoutMsec * 1000;
return LWResult::Result::Timeout;
});
return LWResult::Result::Success;
}
downServers.insert(address);
+ res->d_usec = g_networkTimeoutMsec * 1000;
return LWResult::Result::Timeout;
});
if (downServers.size() < 3) {
/* only the last one will answer */
downServers.insert(address);
+ res->d_usec = g_networkTimeoutMsec * 1000;
return LWResult::Result::OSLimitError;
}
setLWResult(res, 0, true, false, true);
BOOST_CHECK_EQUAL(res, RCode::ServFail);
BOOST_CHECK_EQUAL(ret.size(), length);
BOOST_CHECK_EQUAL(length, SyncRes::s_max_CNAMES_followed + 1);
+
+ // Currently a CNAME bounds check originating from the record cache causes an ImmediateServFail
+ // exception. This is different from the non-cached case, tested above. There a ServFail is
+ // returned with a partial CNAME chain. This should be fixed one way or another. For details, see
+ // how the result of syncres.cc:scanForCNAMELoop() is handled in the two cases.
+ ret.clear();
+ length = 0;
+ BOOST_CHECK_EXCEPTION(sr->beginResolve(target, QType(QType::A), QClass::IN, ret),
+ ImmediateServFailException,
+ [&](const ImmediateServFailException& isfe) {
+ return isfe.reason == "max number of CNAMEs exceeded";
+ });
}
BOOST_AUTO_TEST_CASE(test_cname_target_servfail)
/* mark ns as down */
time_t now = sr->getNow().tv_sec;
- SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000);
+ SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000, SyncRes::ThrottleReason::Timeout);
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
const size_t blocks = 10;
/* mark ns as down for 'blocks' queries */
time_t now = sr->getNow().tv_sec;
- SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks);
+ SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks, SyncRes::ThrottleReason::Timeout);
for (size_t idx = 0; idx < blocks; idx++) {
BOOST_CHECK(SyncRes::isThrottled(now, ns));
const size_t seconds = 1;
/* mark ns as down for 'seconds' seconds */
time_t now = sr->getNow().tv_sec;
- SyncRes::doThrottle(now, ns, seconds, 10000);
+ SyncRes::doThrottle(now, ns, seconds, 10000, SyncRes::ThrottleReason::Timeout);
BOOST_CHECK(SyncRes::isThrottled(now, ns));
BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
- // The cache should also have an authoritative record for the extra in-bailiwick record
- BOOST_REQUIRE_GT(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
- BOOST_REQUIRE_EQUAL(cached.size(), 1U);
- BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
- BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.3").toString());
+ // The cache should not have an authoritative record for the extra in-bailiwick record
+ BOOST_REQUIRE_LE(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
- // But the out-of-bailiwick record should not be there
- BOOST_REQUIRE_LT(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
+ // And the out-of-bailiwick record should not be there
+ BOOST_REQUIRE_LE(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
}
BOOST_AUTO_TEST_CASE(test_dnssec_extra_answers)
BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
- // The cache should also have an authoritative record for the extra in-bailiwick record
- BOOST_REQUIRE_GT(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
- BOOST_REQUIRE_EQUAL(cached.size(), 1U);
- BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
- BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.3").toString());
+ // The cache should not have an authoritative record for the extra in-bailiwick record
+ BOOST_REQUIRE_LE(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
- // But the out-of-bailiwick record should not be there
- BOOST_REQUIRE_LT(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
+ // And the out-of-bailiwick record should not be there
+ BOOST_REQUIRE_LE(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
}
BOOST_AUTO_TEST_CASE(test_skip_opt_any)
if (domain == DNSName("powerdns.com.") && type == QType::A) {
addRecordToLW(res, domain, QType::A, "192.0.2.1");
addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
- addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400");
+ addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY);
addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
}
else if (domain == DNSName("powerdns.com.") && type == QType::AAAA) {
addRecordToLW(res, domain, QType::AAAA, "2001:db8::1");
addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
- addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400");
+ addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY);
/* no RRSIG this time! */
}
vector<DNSRecord> ret;
int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
- BOOST_REQUIRE_EQUAL(ret.size(), 3U);
+ BOOST_CHECK_EQUAL(ret.size(), 2U);
const ComboAddress who;
vector<DNSRecord> cached;
#endif
#include <boost/test/unit_test.hpp>
+#include <array>
#include <iostream>
#include <dnsrecords.hh>
#include <iomanip>
static std::string s_timestampFormat = "%s";
-static const char* toTimestampStringMilli(const struct timeval& tv, char* buf, size_t sz)
-
-{
- struct tm tm;
- size_t len = strftime(buf, sz, s_timestampFormat.c_str(), localtime_r(&tv.tv_sec, &tm));
- if (len == 0) {
- len = snprintf(buf, sz, "%lld", static_cast<long long>(tv.tv_sec));
- }
-
- snprintf(buf + len, sz - len, ".%03ld", static_cast<long>(tv.tv_usec) / 1000);
- return buf;
-}
-
static void loggerBackend(const Logging::Entry& entry)
{
static thread_local std::stringstream buf;
buf << " subsystem=" << std::quoted(entry.name.get());
}
buf << " level=" << entry.level;
- if (entry.d_priority) {
+ if (entry.d_priority != 0) {
buf << " prio=" << static_cast<int>(entry.d_priority);
}
- char timebuf[64];
- buf << " ts=" << std::quoted(toTimestampStringMilli(entry.d_timestamp, timebuf, sizeof(timebuf)));
- for (auto const& v : entry.values) {
+ std::array<char, 64> timebuf{};
+ buf << " ts=" << std::quoted(Logging::toTimestampStringMilli(entry.d_timestamp, timebuf));
+ for (auto const& val : entry.values) {
buf << " ";
- buf << v.first << "=" << std::quoted(v.second);
+ buf << val.first << "=" << std::quoted(val.second);
}
- Logger::Urgency u = entry.d_priority ? Logger::Urgency(entry.d_priority) : Logger::Info;
- g_log << u << buf.str() << endl;
+ Logger::Urgency urgency = entry.d_priority != 0 ? Logger::Urgency(entry.d_priority) : Logger::Info;
+ g_log << urgency << buf.str() << endl;
}
static bool init_unit_test()
// entry point:
int main(int argc, char* argv[])
{
+ setenv("BOOST_TEST_RANDOM", "1", 1); // NOLINT(concurrency-mt-unsafe)
return boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
}
{"kind", zone.d_servers.empty() ? "Native" : "Forwarded"},
{"servers", servers},
{"recursion_desired", zone.d_servers.empty() ? false : zone.d_rdForward},
+ {"notify_allowed", isAllowNotifyForZone(zonename)},
{"records", records}};
resp->setJsonBody(doc);
string singleIPTarget = document["single_target_ip"].string_value();
string kind = toUpper(stringFromJson(document, "kind"));
bool rdFlag = boolFromJson(document, "recursion_desired");
+ bool notifyAllowed = boolFromJson(document, "notify_allowed", false);
string confbasename = "zone-" + apiZoneNameToId(zone);
const string yamlAPiZonesFile = ::arg()["api-config-dir"] + "/apizones";
pdns::rust::settings::rec::ForwardZone forward;
forward.zone = zonename;
forward.recurse = rdFlag;
- forward.notify_allowed = false;
+ forward.notify_allowed = notifyAllowed;
for (const auto& value : document["servers"].array_items()) {
forward.forwarders.emplace_back(value.string_value());
}
throw ApiException("Need at least one upstream server when forwarding");
}
+ const string notifyAllowedConfig = notifyAllowed ? "\nallow-notify-for+=" + zonename : "";
if (rdFlag) {
- apiWriteConfigFile(confbasename, "forward-zones-recurse+=" + zonename + "=" + serverlist);
+ apiWriteConfigFile(confbasename, "forward-zones-recurse+=" + zonename + "=" + serverlist + notifyAllowedConfig);
}
else {
- apiWriteConfigFile(confbasename, "forward-zones+=" + zonename + "=" + serverlist);
+ apiWriteConfigFile(confbasename, "forward-zones+=" + zonename + "=" + serverlist + notifyAllowedConfig);
}
}
}
{"tcp-client-overflow",
MetricDefinition(PrometheusMetricType::counter,
"Number of times an IP address was denied TCP access because it already had too many connections")},
+ {"tcp-overflow",
+ MetricDefinition(PrometheusMetricType::counter,
+ "Number of times a TCP connection was denied access because too many connections")},
{"tcp-clients",
MetricDefinition(PrometheusMetricType::gauge,
"Number of currently active TCP/IP clients")},
{"udr-events",
MetricDefinition(PrometheusMetricType::counter,
"Count of UDR events")},
+
+ {"max-chain-length",
+ MetricDefinition(PrometheusMetricType::counter,
+ "Maximum chain length")},
+
+ {"max-chain-weight",
+ MetricDefinition(PrometheusMetricType::counter,
+ "Maximum chain weight")},
+
+ {"chain-limits",
+ MetricDefinition(PrometheusMetricType::counter,
+ "Chain limits reached")},
};
constexpr bool CHECK_PROMETHEUS_METRICS = false;
result->reserve(mdp.d_answers.size());
for (const auto& i: mdp.d_answers) {
- rr.qname = i.first.d_name;
- rr.qtype = i.first.d_type;
- rr.ttl = i.first.d_ttl;
- rr.content = i.first.getContent()->getZoneRepresentation(true);
+ rr.qname = i.d_name;
+ rr.qtype = i.d_type;
+ rr.ttl = i.d_ttl;
+ rr.content = i.getContent()->getZoneRepresentation(true);
result->push_back(rr);
}
*theirInception = *theirExpire = 0;
bool gotSOA=false;
for(const MOADNSParser::answers_t::value_type& drc : mdp.d_answers) {
- if(drc.first.d_type == QType::SOA && drc.first.d_name == *domain) {
- auto src = getRR<SOARecordContent>(drc.first);
+ if(drc.d_type == QType::SOA && drc.d_name == *domain) {
+ auto src = getRR<SOARecordContent>(drc);
if (src) {
*theirSerial = src->d_st.serial;
gotSOA = true;
}
}
- if(drc.first.d_type == QType::RRSIG && drc.first.d_name == *domain) {
- auto rrc = getRR<RRSIGRecordContent>(drc.first);
+ if(drc.d_type == QType::RRSIG && drc.d_name == *domain) {
+ auto rrc = getRR<RRSIGRecordContent>(drc);
if(rrc && rrc->d_type == QType::SOA) {
*theirInception= std::max(*theirInception, rrc->d_siginception);
*theirExpire = std::max(*theirExpire, rrc->d_sigexpire);
// Check if all the records provided are within the zone
for(const auto & answer : mdp.d_answers) {
- const DNSRecord *rr = &answer.first;
+ const DNSRecord *dnsRecord = &answer;
// Skip this check for other field types (like the TSIG - which is in the additional section)
// For a TSIG, the label is the dnskey, so it does not pass the endOn validation.
- if (! (rr->d_place == DNSResourceRecord::ANSWER || rr->d_place == DNSResourceRecord::AUTHORITY))
+ if (dnsRecord->d_place != DNSResourceRecord::ANSWER && dnsRecord->d_place != DNSResourceRecord::AUTHORITY) {
continue;
+ }
- if (!rr->d_name.isPartOf(di.zone)) {
+ if (!dnsRecord->d_name.isPartOf(di.zone)) {
g_log<<Logger::Error<<msgPrefix<<"Received update/record out of zone, sending NotZone."<<endl;
return RCode::NotZone;
}
// 3.2.1 and 3.2.2 - Prerequisite check
for(const auto & answer : mdp.d_answers) {
- const DNSRecord *rr = &answer.first;
- if (rr->d_place == DNSResourceRecord::ANSWER) {
- int res = checkUpdatePrerequisites(rr, &di);
+ const DNSRecord *dnsRecord = &answer;
+ if (dnsRecord->d_place == DNSResourceRecord::ANSWER) {
+ int res = checkUpdatePrerequisites(dnsRecord, &di);
if (res>0) {
- g_log<<Logger::Error<<msgPrefix<<"Failed PreRequisites check for "<<rr->d_name<<", returning "<<RCode::to_s(res)<<endl;
+ g_log<<Logger::Error<<msgPrefix<<"Failed PreRequisites check for "<<dnsRecord->d_name<<", returning "<<RCode::to_s(res)<<endl;
di.backend->abortTransaction();
return res;
}
typedef std::map<rrSetKey_t, rrVector_t> RRsetMap_t;
RRsetMap_t preReqRRsets;
for(const auto& i: mdp.d_answers) {
- const DNSRecord* rr = &i.first;
- if (rr->d_place == DNSResourceRecord::ANSWER) {
+ const DNSRecord* dnsRecord = &i;
+ if (dnsRecord->d_place == DNSResourceRecord::ANSWER) {
// Last line of 3.2.3
- if (rr->d_class != QClass::IN && rr->d_class != QClass::NONE && rr->d_class != QClass::ANY)
+ if (dnsRecord->d_class != QClass::IN && dnsRecord->d_class != QClass::NONE && dnsRecord->d_class != QClass::ANY) {
return RCode::FormErr;
+ }
- if (rr->d_class == QClass::IN) {
- rrSetKey_t key = {rr->d_name, QType(rr->d_type)};
+ if (dnsRecord->d_class == QClass::IN) {
+ rrSetKey_t key = {dnsRecord->d_name, QType(dnsRecord->d_type)};
rrVector_t *vec = &preReqRRsets[key];
- vec->push_back(DNSResourceRecord::fromWire(*rr));
+ vec->push_back(DNSResourceRecord::fromWire(*dnsRecord));
}
}
}
uint changedRecords = 0;
// 3.4.1 - Prescan section
for(const auto & answer : mdp.d_answers) {
- const DNSRecord *rr = &answer.first;
- if (rr->d_place == DNSResourceRecord::AUTHORITY) {
- int res = checkUpdatePrescan(rr);
+ const DNSRecord *dnsRecord = &answer;
+ if (dnsRecord->d_place == DNSResourceRecord::AUTHORITY) {
+ int res = checkUpdatePrescan(dnsRecord);
if (res>0) {
g_log<<Logger::Error<<msgPrefix<<"Failed prescan check, returning "<<res<<endl;
di.backend->abortTransaction();
// Another special case is the addition of both a CNAME and a non-CNAME for the same name (#6270)
set<DNSName> cn, nocn;
for (const auto &rr : mdp.d_answers) {
- if (rr.first.d_place == DNSResourceRecord::AUTHORITY && rr.first.d_class == QClass::IN && rr.first.d_ttl > 0) {
+ if (rr.d_place == DNSResourceRecord::AUTHORITY && rr.d_class == QClass::IN && rr.d_ttl > 0) {
// Addition
- if (rr.first.d_type == QType::CNAME) {
- cn.insert(rr.first.d_name);
- } else if (rr.first.d_type != QType::RRSIG) {
- nocn.insert(rr.first.d_name);
+ if (rr.d_type == QType::CNAME) {
+ cn.insert(rr.d_name);
+ } else if (rr.d_type != QType::RRSIG) {
+ nocn.insert(rr.d_name);
}
}
}
vector<const DNSRecord *> cnamesToAdd, nonCnamesToAdd;
for(const auto & answer : mdp.d_answers) {
- const DNSRecord *rr = &answer.first;
- if (rr->d_place == DNSResourceRecord::AUTHORITY) {
+ const DNSRecord *dnsRecord = &answer;
+ if (dnsRecord->d_place == DNSResourceRecord::AUTHORITY) {
/* see if it's permitted by policy */
if (this->d_update_policy_lua != nullptr) {
- if (!this->d_update_policy_lua->updatePolicy(rr->d_name, QType(rr->d_type), di.zone, packet)) {
- g_log<<Logger::Warning<<msgPrefix<<"Refusing update for " << rr->d_name << "/" << QType(rr->d_type).toString() << ": Not permitted by policy"<<endl;
+ if (!this->d_update_policy_lua->updatePolicy(dnsRecord->d_name, QType(dnsRecord->d_type), di.zone, packet)) {
+ g_log<<Logger::Warning<<msgPrefix<<"Refusing update for " << dnsRecord->d_name << "/" << QType(dnsRecord->d_type).toString() << ": Not permitted by policy"<<endl;
continue;
} else {
- g_log<<Logger::Debug<<msgPrefix<<"Accepting update for " << rr->d_name << "/" << QType(rr->d_type).toString() << ": Permitted by policy"<<endl;
+ g_log<<Logger::Debug<<msgPrefix<<"Accepting update for " << dnsRecord->d_name << "/" << QType(dnsRecord->d_type).toString() << ": Permitted by policy"<<endl;
}
}
- if (rr->d_class == QClass::NONE && rr->d_type == QType::NS && rr->d_name == di.zone)
- nsRRtoDelete.push_back(rr);
- else if (rr->d_class == QClass::IN && rr->d_ttl > 0) {
- if (rr->d_type == QType::CNAME) {
- cnamesToAdd.push_back(rr);
+ if (dnsRecord->d_class == QClass::NONE && dnsRecord->d_type == QType::NS && dnsRecord->d_name == di.zone) {
+ nsRRtoDelete.push_back(dnsRecord);
+ }
+ else if (dnsRecord->d_class == QClass::IN && dnsRecord->d_ttl > 0) {
+ if (dnsRecord->d_type == QType::CNAME) {
+ cnamesToAdd.push_back(dnsRecord);
} else {
- nonCnamesToAdd.push_back(rr);
+ nonCnamesToAdd.push_back(dnsRecord);
}
}
else
- changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
+ changedRecords += performUpdate(msgPrefix, dnsRecord, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
}
}
for (const auto &rr : cnamesToAdd) {
StatBag S;
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
int main(int argc, char** argv)
try
{
throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
}
for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
- if(i->first.d_type != QType::TKEY) continue;
+ if (i->d_type != QType::TKEY) {
+ continue;
+ }
// recover TKEY record
- tkrc = TKEYRecordContent(i->first.getContent()->getZoneRepresentation());
+ tkrc = TKEYRecordContent(i->getContent()->getZoneRepresentation());
input = tkrc.d_key;
}
}
throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
}
for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
- if (i->first.d_type == QType::TSIG) {
+ if (i->d_type == QType::TSIG) {
string message;
if (!tsig) {
std::cerr<<"Unexpected TSIG signature in data"<<endl;
}
- trc = TSIGRecordContent(i->first.getContent()->getZoneRepresentation());
+ trc = TSIGRecordContent(i->getContent()->getZoneRepresentation());
continue;
}
- if(i->first.d_type == QType::SOA)
+ if(i->d_type == QType::SOA)
{
++soacount;
}
- else if (i->first.d_type == QType::NSEC3PARAM) {
- ns3pr = NSEC3PARAMRecordContent(i->first.getContent()->getZoneRepresentation());
+ else if (i->d_type == QType::NSEC3PARAM) {
+ ns3pr = NSEC3PARAMRecordContent(i->getContent()->getZoneRepresentation());
isNSEC3 = true;
}
ostringstream o;
- o<<"\t"<<i->first.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
+ o<<"\t"<<i->d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->d_type);
if(showdetails)
{
- o<<"\t"<<i->first.getContent()->getZoneRepresentation();
+ o<<"\t"<<i->getContent()->getZoneRepresentation();
}
- else if(i->first.d_type == QType::RRSIG)
+ else if(i->d_type == QType::RRSIG)
{
- string zoneRep = i->first.getContent()->getZoneRepresentation();
+ string zoneRep = i->getContent()->getZoneRepresentation();
vector<string> parts;
stringtok(parts, zoneRep);
o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...";
}
- else if(i->first.d_type == QType::NSEC3)
+ else if(i->d_type == QType::NSEC3)
{
- string zoneRep = i->first.getContent()->getZoneRepresentation();
+ string zoneRep = i->getContent()->getZoneRepresentation();
vector<string> parts;
stringtok(parts, zoneRep);
o<<"\t"<<parts[0]<<" ";
for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
o<<" "<<*iter;
}
- else if(i->first.d_type == QType::DNSKEY)
+ else if(i->d_type == QType::DNSKEY)
{
- string zoneRep = i->first.getContent()->getZoneRepresentation();
+ string zoneRep = i->getContent()->getZoneRepresentation();
vector<string> parts;
stringtok(parts, zoneRep);
o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...";
}
else
{
- o<<"\t"<<i->first.getContent()->getZoneRepresentation();
+ o<<"\t"<<i->getContent()->getZoneRepresentation();
}
- records.emplace_back(i->first.d_name, o.str());
+ records.emplace_back(i->d_name, o.str());
- DNSName shorter(i->first.d_name);
+ DNSName shorter(i->d_name);
do {
labels.insert(shorter);
if (shorter == DNSName(argv[3]))
for (MOADNSParser::answers_t::const_iterator i = mdp.d_answers.begin();
i != mdp.d_answers.end(); ++i) {
- cout << i->first.d_place - 1 << "\t" << i->first.d_name.toString() << "\t"
- << ttl(i->first.d_ttl) << "\t" << nameForClass(i->first.d_class, i->first.d_type) << "\t"
- << DNSRecordContent::NumberToType(i->first.d_type);
+ cout << i->d_place - 1 << "\t" << i->d_name.toString() << "\t"
+ << ttl(i->d_ttl) << "\t" << nameForClass(i->d_class, i->d_type) << "\t"
+ << DNSRecordContent::NumberToType(i->d_type);
if (dumpluaraw) {
- cout<<"\t"<< makeLuaString(i->first.getContent()->serialize(DNSName(), true))<<endl;
+ cout<<"\t"<< makeLuaString(i->getContent()->serialize(DNSName(), true))<<endl;
continue;
}
- if (i->first.d_class == QClass::IN) {
- if (i->first.d_type == QType::RRSIG) {
- string zoneRep = i->first.getContent()->getZoneRepresentation();
+ if (i->d_class == QClass::IN) {
+ if (i->d_type == QType::RRSIG) {
+ string zoneRep = i->getContent()->getZoneRepresentation();
vector<string> parts;
stringtok(parts, zoneRep);
cout << "\t" << parts[0] << " "
<< " [expiry] [inception] [keytag] " << parts[7] << " ...\n";
continue;
}
- if (!showflags && i->first.d_type == QType::NSEC3) {
- string zoneRep = i->first.getContent()->getZoneRepresentation();
+ if (!showflags && i->d_type == QType::NSEC3) {
+ string zoneRep = i->getContent()->getZoneRepresentation();
vector<string> parts;
stringtok(parts, zoneRep);
cout << "\t" << parts[0] << " [flags] "
cout << "\n";
continue;
}
- if (i->first.d_type == QType::DNSKEY) {
- string zoneRep = i->first.getContent()->getZoneRepresentation();
+ if (i->d_type == QType::DNSKEY) {
+ string zoneRep = i->getContent()->getZoneRepresentation();
vector<string> parts;
stringtok(parts, zoneRep);
cout << "\t" << parts[0] << " "
<< parts[1] << " " << parts[2] << " ...\n";
continue;
}
- if (i->first.d_type == QType::SOA && hidesoadetails) {
- string zoneRep = i->first.getContent()->getZoneRepresentation();
+ if (i->d_type == QType::SOA && hidesoadetails) {
+ string zoneRep = i->getContent()->getZoneRepresentation();
vector<string> parts;
stringtok(parts, zoneRep);
cout << "\t" << parts[0] << " "
continue;
}
}
- cout << "\t" << i->first.getContent()->getZoneRepresentation() << "\n";
+ cout << "\t" << i->getContent()->getZoneRepresentation() << "\n";
}
EDNSOpts edo;
#include "lock.hh"
-/** This is sort of a light-weight RCU idea.
+/** This is sort of a light-weight RCU idea.
Suitable for when you frequently consult some "readonly" state, which infrequently
- gets changed. One way of dealing with this is fully locking access to the state, but
+ gets changed. One way of dealing with this is fully locking access to the state, but
this is rather wasteful.
- Instead, in the code below, the frequent users of the state get a "readonly" copy of it,
- which they can consult. On access, we atomically compare if the local copy is still current
+ Instead, in the code below, the frequent users of the state get a "readonly" copy of it,
+ which they can consult. On access, we atomically compare if the local copy is still current
with the global one. If it isn't we do the lock thing, and create a new local copy.
- Meanwhile, to upgrade the global state, methods are offered that do appropriate locking
+ Meanwhile, to upgrade the global state, methods are offered that do appropriate locking
and upgrade the 'generation' counter, signaling to the local copies that they need to be
refreshed on the next access.
Two ways to change the global copy are available:
getCopy(), which delivers a deep copy of the current state, followed by setState()
- modify(), which accepts a (lambda)function that modifies the state
+ modify(), which accepts a (lambda)function that modifies the state
- NOTE: The actual destruction of the 'old' state happens when the last local state
+ NOTE: The actual destruction of the 'old' state happens when the last local state
relinquishes its access to the state.
"read-only"
- Sometimes, a 'state' can contain parts that can safely be modified by multiple users, for
+ Sometimes, a 'state' can contain parts that can safely be modified by multiple users, for
example, atomic counters. In such cases, it may be useful to explicitly declare such counters
as mutable. */
-template<typename T> class GlobalStateHolder;
+template <typename T>
+class GlobalStateHolder;
-template<typename T>
+template <typename T>
class LocalStateHolder
{
public:
- explicit LocalStateHolder(GlobalStateHolder<T>* source) : d_source(source)
+ explicit LocalStateHolder(GlobalStateHolder<T>* source) :
+ d_source(source)
{}
- const T* operator->() // fast const-only access, but see "read-only" above
+ const T* operator->() // fast const-only access, but see "read-only" above
{
- if(d_source->getGeneration() != d_generation) {
- d_source->getState(&d_state, & d_generation);
+ if (d_source->getGeneration() != d_generation) {
+ d_source->getState(&d_state, &d_generation);
}
return d_state.get();
}
- const T& operator*() // fast const-only access, but see "read-only" above
+ const T& operator*() // fast const-only access, but see "read-only" above
{
return *operator->();
}
void reset()
{
- d_generation=0;
+ d_generation = 0;
d_state.reset();
}
+
private:
std::shared_ptr<T> d_state;
unsigned int d_generation{0};
const GlobalStateHolder<T>* d_source;
};
-template<typename T>
+template <typename T>
class GlobalStateHolder
{
public:
- GlobalStateHolder() : d_state(std::make_shared<T>())
+ GlobalStateHolder() :
+ d_state(std::make_shared<T>())
{}
LocalStateHolder<T> getLocal()
{
}
}
- T getCopy() const //!< Safely & slowly get a copy of the global state
+ T getCopy() const //!< Safely & slowly get a copy of the global state
{
return *(*(d_state.lock()));
}
-
+
//! Safely & slowly modify the global state
- template<typename F>
- void modify(F act) {
+ template <typename F>
+ void modify(F act)
+ {
auto state = d_state.lock();
auto newState = *(*state); // and yes, these three steps are necessary, can't ever modify state in place, even when locked!
act(newState);
++d_generation;
}
- typedef T value_type;
+ using value_type = T;
+
private:
unsigned int getGeneration() const
{
// shuffle, maintaining some semblance of order
void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
{
- std::vector<DNSZoneRecord>::iterator first, second;
+ std::vector<DNSZoneRecord>::iterator first;
+ std::vector<DNSZoneRecord>::iterator second;
// We assume the CNAMES are listed first in the ANSWER section and the the other records
// and we want to shuffle the other records only
}
}
// And then for one past the last ANSWER record
- for (second = first; second != rrs.end(); ++second)
- if (second->dr.d_place != DNSResourceRecord::ANSWER)
+ for (second = first; second != rrs.end(); ++second) {
+ if (second->dr.d_place != DNSResourceRecord::ANSWER) {
break;
+ }
+ }
// Now shuffle the non-CNAME ANSWER records
- dns_random_engine r;
+ dns_random_engine randomEngine;
if (second - first > 1) {
- shuffle(first, second, r);
+ shuffle(first, second, randomEngine);
}
// now shuffle the ADDITIONAL records in the same manner as the ANSWER records
}
if (second - first > 1) {
- shuffle(first, second, r);
+ shuffle(first, second, randomEngine);
}
// we don't shuffle the rest
}
static void shuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals)
{
// This shuffles in the same style as the above method, keeping CNAME in the front and RRSIGs at the end
- std::vector<DNSRecord>::iterator first, second;
+ std::vector<DNSRecord>::iterator first;
+ std::vector<DNSRecord>::iterator second;
+
for (first = rrs.begin(); first != rrs.end(); ++first) {
if (first->d_place == DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) {
break;
}
}
- pdns::dns_random_engine r;
+ pdns::dns_random_engine randomEngine;
if (second - first > 1) {
- shuffle(first, second, r);
+ shuffle(first, second, randomEngine);
}
if (!includingAdditionals) {
}
if (second - first > 1) {
- shuffle(first, second, r);
+ shuffle(first, second, randomEngine);
}
// we don't shuffle the rest
}
static uint16_t mapTypesToOrder(uint16_t type)
{
- if (type == QType::CNAME)
+ if (type == QType::CNAME) {
return 0;
- if (type == QType::RRSIG)
+ }
+ if (type == QType::RRSIG) {
return 65535;
- else
- return 1;
+ }
+ return 1;
}
// make sure rrs is sorted in d_place order to avoid surprises later
// then shuffle the parts that desire shuffling
void pdns::orderAndShuffle(vector<DNSRecord>& rrs, bool includingAdditionals)
{
- std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& a, const DNSRecord& b) {
- return std::tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::tuple(b.d_place, mapTypesToOrder(b.d_type));
+ std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& lhs, const DNSRecord& rhs) {
+ return std::tuple(lhs.d_place, mapTypesToOrder(lhs.d_type)) < std::tuple(rhs.d_place, mapTypesToOrder(rhs.d_type));
});
shuffle(rrs, includingAdditionals);
}
+#include "threadname.hh"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
void* ChunkedSigningPipe::helperWorker(ChunkedSigningPipe* csp, int fd)
try {
+ setThreadName("pdns/signer");
csp->worker(fd);
return nullptr;
}
#ifdef HAVE_NET_SNMP
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/definitions.h>
+#include <net-snmp/types.h>
+#include <net-snmp/utilities.h>
+#include <net-snmp/config_api.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#undef INET6 /* SRSLY? */
+
#ifndef HAVE_SNMP_SELECT_INFO2
/* that's terrible, because it means we are going to have trouble with large
FD numbers at some point.. */
# include <net-snmp/library/large_fd_set.h>
#endif
-const std::array<oid, 11> SNMPAgent::snmpTrapOID = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
+static const std::array<oid, 11> s_snmpTrapOID = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
int SNMPAgent::setCounter64Value(netsnmp_request_info* request,
uint64_t value)
return SNMP_ERR_NOERROR;
}
+void SNMPAgent::addSNMPTrapOID(netsnmp_variable_list** varList, const void* value, size_t len)
+{
+ snmp_varlist_add_variable(varList,
+ s_snmpTrapOID.data(),
+ s_snmpTrapOID.size(),
+ ASN_OBJECT_ID,
+ value,
+ len);
+}
+
bool SNMPAgent::sendTrap(pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>& sender,
netsnmp_variable_list* varList)
{
#include <thread>
#include <unistd.h>
-#ifdef HAVE_NET_SNMP
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/definitions.h>
-#include <net-snmp/types.h>
-#include <net-snmp/utilities.h>
-#include <net-snmp/config_api.h>
-#include <net-snmp/agent/net-snmp-agent-includes.h>
-#undef INET6 /* SRSLY? */
-#endif /* HAVE_NET_SNMP */
-
#include "mplexer.hh"
#include "channel.hh"
+typedef struct netsnmp_request_info_s netsnmp_request_info;
+typedef struct variable_list netsnmp_variable_list;
+
class SNMPAgent
{
public:
#endif /* HAVE_NET_SNMP */
protected:
#ifdef HAVE_NET_SNMP
- /* OID for snmpTrapOID.0 */
- static const std::array<oid, 11> snmpTrapOID;
+ static void addSNMPTrapOID(netsnmp_variable_list** varList, const void* value, size_t len);
static bool sendTrap(pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>& sender,
netsnmp_variable_list* varList);
} lwr;
for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
DNSResourceRecord rr;
- rr.qtype=i->first.d_type;
- rr.qname=i->first.d_name;
+ rr.qtype=i->d_type;
+ rr.qname=i->d_name;
- rr.ttl=i->first.d_ttl;
- rr.content=i->first.getContent()->getZoneRepresentation(); // this should be the serialised form
+ rr.ttl=i->d_ttl;
+ rr.content=i->getContent()->getZoneRepresentation(); // this should be the serialised form
lwr.d_result.push_back(rr);
}
void SSQLite3::startTransaction()
{
- execute("begin");
+ execute("begin immediate");
m_in_transaction = true;
}
#include <fcntl.h>
#include <stdexcept>
-#include <boost/utility.hpp>
#include <csignal>
#include "namespaces.hh"
#include "noinitvector.hh"
using ProtocolType = int; //!< Supported protocol types
//! Representation of a Socket and many of the Berkeley functions available
-class Socket : public boost::noncopyable
+class Socket
{
public:
- Socket(int fd): d_socket(fd)
+ Socket(const Socket&) = delete;
+ Socket& operator=(const Socket&) = delete;
+
+ Socket(int socketDesc) :
+ d_socket(socketDesc)
{
}
//! Construct a socket of specified address family and socket type.
- Socket(int af, int st, ProtocolType pt=0)
+ Socket(int addressFamily, int socketType, ProtocolType protocolType = 0) :
+ d_socket(socket(addressFamily, socketType, protocolType))
{
- if((d_socket=socket(af, st, pt))<0)
+ if (d_socket < 0) {
throw NetworkError(stringerror());
+ }
setCloseOnExec(d_socket);
}
closesocket(d_socket);
}
}
- catch(const PDNSException& e) {
+ catch (const PDNSException& e) {
}
}
//! If the socket is capable of doing so, this function will wait for a connection
- std::unique_ptr<Socket> accept()
+ [[nodiscard]] std::unique_ptr<Socket> accept() const
{
- struct sockaddr_in remote;
- socklen_t remlen=sizeof(remote);
+ sockaddr_in remote{};
+ socklen_t remlen = sizeof(remote);
memset(&remote, 0, sizeof(remote));
- int s=::accept(d_socket, reinterpret_cast<sockaddr *>(&remote), &remlen);
- if(s<0) {
- if(errno==EAGAIN)
+ int sock = ::accept(d_socket, reinterpret_cast<sockaddr*>(&remote), &remlen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+ if (sock < 0) {
+ if (errno == EAGAIN) {
return nullptr;
+ }
- throw NetworkError("Accepting a connection: "+stringerror());
+ throw NetworkError("Accepting a connection: " + stringerror());
}
- return std::make_unique<Socket>(s);
+ return std::make_unique<Socket>(sock);
}
//! Get remote address
- bool getRemote(ComboAddress &remote) {
- socklen_t remotelen=sizeof(remote);
- return (getpeername(d_socket, reinterpret_cast<struct sockaddr *>(&remote), &remotelen) >= 0);
+ bool getRemote(ComboAddress& remote) const
+ {
+ socklen_t remotelen = sizeof(remote);
+ return getpeername(d_socket, reinterpret_cast<struct sockaddr*>(&remote), &remotelen) >= 0; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
}
//! Check remote address against netmaskgroup ng
- bool acl(const NetmaskGroup &ng)
+ [[nodiscard]] bool acl(const NetmaskGroup& netmaskGroup) const
{
ComboAddress remote;
- if (getRemote(remote))
- return ng.match(remote);
+ if (getRemote(remote)) {
+ return netmaskGroup.match(remote);
+ }
return false;
}
//! Set the socket to non-blocking
- void setNonBlocking()
+ void setNonBlocking() const
{
::setNonBlocking(d_socket);
}
//! Set the socket to blocking
- void setBlocking()
+ void setBlocking() const
{
::setBlocking(d_socket);
}
- void setReuseAddr()
+ void setReuseAddr() const
{
try {
::setReuseAddr(d_socket);
- } catch (const PDNSException &e) {
+ }
+ catch (const PDNSException& e) {
throw NetworkError(e.reason);
}
}
throw NetworkError("While setting TCP_FASTOPEN_CONNECT: " + stringerror());
}
#else
- throw NetworkError("While setting TCP_FASTOPEN_CONNECT: not compiled in");
+ throw NetworkError("While setting TCP_FASTOPEN_CONNECT: not compiled in");
#endif
}
//! Bind the socket to a specified endpoint
- void bind(const ComboAddress &local, bool reuseaddr=true)
+ void bind(const ComboAddress& local, bool reuseaddr = true) const
{
- int tmp=1;
- if(reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp)<0)
- throw NetworkError("Setsockopt failed: "+stringerror());
-
- if(::bind(d_socket, reinterpret_cast<const struct sockaddr *>(&local), local.getSocklen())<0)
- throw NetworkError("While binding: "+stringerror());
+ int tmp = 1;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp) < 0) {
+ throw NetworkError("Setsockopt failed: " + stringerror());
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (::bind(d_socket, reinterpret_cast<const struct sockaddr*>(&local), local.getSocklen()) < 0) {
+ throw NetworkError("While binding: " + stringerror());
+ }
}
//! Connect the socket to a specified endpoint
- void connect(const ComboAddress &ep, int timeout=0)
+ void connect(const ComboAddress& address, int timeout = 0) const
{
- SConnectWithTimeout(d_socket, ep, timeval{timeout,0});
+ SConnectWithTimeout(d_socket, address, timeval{timeout, 0});
}
-
//! For datagram sockets, receive a datagram and learn where it came from
/** For datagram sockets, receive a datagram and learn where it came from
\param dgram Will be filled with the datagram
\param ep Will be filled with the origin of the datagram */
- void recvFrom(string &dgram, ComboAddress& remote)
+ void recvFrom(string& dgram, ComboAddress& remote) const
{
socklen_t remlen = sizeof(remote);
if (dgram.size() < s_buflen) {
dgram.resize(s_buflen);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr *>(&remote) , &remlen);
+ auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr*>(&remote), &remlen);
if (bytes < 0) {
throw NetworkError("After recvfrom: " + stringerror());
}
dgram.resize(static_cast<size_t>(bytes));
}
- bool recvFromAsync(PacketBuffer& dgram, ComboAddress& remote)
+ bool recvFromAsync(PacketBuffer& dgram, ComboAddress& remote) const
{
socklen_t remlen = sizeof(remote);
if (dgram.size() < s_buflen) {
dgram.resize(s_buflen);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr *>(&remote), &remlen);
+ auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr*>(&remote), &remlen);
if (bytes < 0) {
if (errno != EAGAIN) {
throw NetworkError("After async recvfrom: " + stringerror());
}
- else {
- return false;
- }
+ return false;
}
dgram.resize(static_cast<size_t>(bytes));
return true;
}
//! For datagram sockets, send a datagram to a destination
- void sendTo(const char* msg, size_t len, const ComboAddress& remote)
+ void sendTo(const char* msg, size_t len, const ComboAddress& remote) const
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- if (sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr *>(&remote), remote.getSocklen()) < 0) {
+ if (sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr*>(&remote), remote.getSocklen()) < 0) {
throw NetworkError("After sendto: " + stringerror());
}
}
//! For connected datagram sockets, send a datagram
- void send(const std::string& msg)
+ void send(const std::string& msg) const
{
if (::send(d_socket, msg.data(), msg.size(), 0) < 0) {
- throw NetworkError("After send: "+stringerror());
+ throw NetworkError("After send: " + stringerror());
}
}
-
/** For datagram sockets, send a datagram to a destination
\param dgram The datagram
\param remote The intended destination of the datagram */
- void sendTo(const string& dgram, const ComboAddress& remote)
+ void sendTo(const string& dgram, const ComboAddress& remote) const
{
sendTo(dgram.data(), dgram.length(), remote);
}
-
//! Write this data to the socket, taking care that all bytes are written out
- void writen(const string &data)
+ void writen(const string& data) const
{
- if(data.empty())
+ if (data.empty()) {
return;
+ }
- size_t toWrite=data.length();
- ssize_t res;
- const char *ptr=data.c_str();
+ size_t toWrite = data.length();
+ const char* ptr = data.data();
do {
- res=::send(d_socket, ptr, toWrite, 0);
- if(res<0)
- throw NetworkError("Writing to a socket: "+stringerror());
- if(!res)
+ auto res = ::send(d_socket, ptr, toWrite, 0);
+ if (res < 0) {
+ throw NetworkError("Writing to a socket: " + stringerror());
+ }
+ if (res == 0) {
throw NetworkError("EOF on socket");
+ }
toWrite -= static_cast<size_t>(res);
- ptr += static_cast<size_t>(res);
- } while(toWrite);
-
+ ptr += static_cast<size_t>(res); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ } while (toWrite > 0);
}
//! tries to write toWrite bytes from ptr to the socket
\param ptr Location to write from
\param toWrite number of bytes to try
*/
- size_t tryWrite(const char *ptr, size_t toWrite)
+ size_t tryWrite(const char* ptr, size_t toWrite) const
{
- ssize_t res;
- res=::send(d_socket,ptr,toWrite,0);
- if(res==0)
+ auto res = ::send(d_socket, ptr, toWrite, 0);
+ if (res == 0) {
throw NetworkError("EOF on writing to a socket");
-
- if(res>0)
+ }
+ if (res > 0) {
return res;
+ }
- if(errno==EAGAIN)
+ if (errno == EAGAIN) {
return 0;
+ }
- throw NetworkError("Writing to a socket: "+stringerror());
+ throw NetworkError("Writing to a socket: " + stringerror());
}
//! Writes toWrite bytes from ptr to the socket
/** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
- size_t write(const char *ptr, size_t toWrite)
+ size_t write(const char* ptr, size_t toWrite) const
{
- ssize_t res;
- res=::send(d_socket,ptr,toWrite,0);
- if(res<0) {
- throw NetworkError("Writing to a socket: "+stringerror());
+ auto res = ::send(d_socket, ptr, toWrite, 0);
+ if (res < 0) {
+ throw NetworkError("Writing to a socket: " + stringerror());
}
return res;
}
- void writenWithTimeout(const void *buffer, size_t n, int timeout)
+ void writenWithTimeout(const void* buffer, size_t n, int timeout) const
{
- size_t bytes=n;
- const char *ptr = reinterpret_cast<const char*>(buffer);
- ssize_t ret;
- while(bytes) {
- ret=::write(d_socket, ptr, bytes);
- if(ret < 0) {
- if(errno == EAGAIN) {
- ret=waitForRWData(d_socket, false, timeout, 0);
- if(ret < 0)
+ size_t bytes = n;
+ const char* ptr = static_cast<const char*>(buffer);
+
+ while (bytes > 0) {
+ auto ret = ::write(d_socket, ptr, bytes);
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ ret = waitForRWData(d_socket, false, timeout, 0);
+ if (ret < 0) {
throw NetworkError("Waiting for data write");
- if(!ret)
+ }
+ if (ret == 0) {
throw NetworkError("Timeout writing data");
+ }
continue;
}
- else
- throw NetworkError("Writing data: "+stringerror());
+ throw NetworkError("Writing data: " + stringerror());
}
- if(!ret) {
+ if (ret == 0) {
throw NetworkError("Did not fulfill TCP write due to EOF");
}
- ptr += static_cast<size_t>(ret);
+ ptr += static_cast<size_t>(ret); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
bytes -= static_cast<size_t>(ret);
}
}
//! reads one character from the socket
- int getChar()
+ [[nodiscard]] int getChar() const
{
- char c;
+ char character{};
- ssize_t res=::recv(d_socket,&c,1,0);
- if(res)
- return c;
+ ssize_t res = ::recv(d_socket, &character, 1, 0);
+ if (res == 0) {
+ return character;
+ }
return -1;
}
- void getline(string &data)
+ void getline(string& data) const
{
- data="";
- int c;
- while((c=getChar())!=-1) {
- data+=(char)c;
- if(c=='\n')
+ data.clear();
+ while (true) {
+ int character = getChar();
+ if (character == -1) {
break;
+ }
+ data += (char)character;
+ if (character == '\n') {
+ break;
+ }
}
}
//! Reads a block of data from the socket to a string
- void read(string &data)
+ void read(string& data)
{
d_buffer.resize(s_buflen);
- ssize_t res=::recv(d_socket, &d_buffer[0], s_buflen, 0);
- if(res<0)
- throw NetworkError("Reading from a socket: "+stringerror());
+ ssize_t res = ::recv(d_socket, d_buffer.data(), s_buflen, 0);
+ if (res < 0) {
+ throw NetworkError("Reading from a socket: " + stringerror());
+ }
data.assign(d_buffer, 0, static_cast<size_t>(res));
}
//! Reads a block of data from the socket to a block of memory
- size_t read(char *buffer, size_t bytes)
+ size_t read(char* buffer, size_t bytes) const
{
- ssize_t res=::recv(d_socket, buffer, bytes, 0);
- if(res<0)
- throw NetworkError("Reading from a socket: "+stringerror());
+ auto res = ::recv(d_socket, buffer, bytes, 0);
+ if (res < 0) {
+ throw NetworkError("Reading from a socket: " + stringerror());
+ }
return static_cast<size_t>(res);
}
/** Read a bock of data from the socket to a block of memory,
- * waiting at most 'timeout' seconds for the data to become
- * available. Be aware that this does _NOT_ handle partial reads
- * for you.
- */
- ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
+ * waiting at most 'timeout' seconds for the data to become
+ * available. Be aware that this does _NOT_ handle partial reads
+ * for you.
+ */
+ size_t readWithTimeout(char* buffer, size_t n, int timeout) const
{
int err = waitForRWData(d_socket, true, timeout, 0);
- if(err == 0)
+ if (err == 0) {
throw NetworkError("timeout reading");
- if(err < 0)
- throw NetworkError("nonblocking read failed: "+stringerror());
+ }
+ if (err < 0) {
+ throw NetworkError("nonblocking read failed: " + stringerror());
+ }
return read(buffer, n);
}
//! Sets the socket to listen with a default listen backlog of 10 pending connections
- void listen(unsigned int length=10)
+ void listen(int length = 10) const
{
- if(::listen(d_socket,length)<0)
- throw NetworkError("Setting socket to listen: "+stringerror());
+ if (::listen(d_socket, length) < 0) {
+ throw NetworkError("Setting socket to listen: " + stringerror());
+ }
}
//! Returns the internal file descriptor of the socket
- int getHandle() const
+ [[nodiscard]] int getHandle() const
{
return d_socket;
}
}
private:
- static const size_t s_buflen{4096};
+ static constexpr size_t s_buflen{4096};
std::string d_buffer;
int d_socket;
};
}
typename std::aligned_storage_t<sizeof(atomic_t), CPU_LEVEL1_DCACHE_LINESIZE> counter;
};
-
- using stat_t = stat_t_trait<uint64_t>;
- using stat32_t = stat_t_trait<uint32_t>;
- using stat16_t = stat_t_trait<uint16_t>;
}
#else
namespace pdns {
- using stat_t = std::atomic<uint64_t>;
- using stat32_t = std::atomic<uint32_t>;
- using stat16_t = std::atomic<uint16_t>;
template <class T>
using stat_t_trait = std::atomic<T>;
}
#endif
+
+namespace pdns {
+ using stat_t = stat_t_trait<uint64_t>;
+ using stat32_t = stat_t_trait<uint32_t>;
+ using stat16_t = stat_t_trait<uint16_t>;
+ using stat_double_t = stat_t_trait<double>;
+}
}
for (const auto& answer : mdp.d_answers) {
- if (answer.first.d_place == 1 && answer.first.d_type == qtype) {
+ if (answer.d_place == 1 && answer.d_type == qtype) {
DNSZoneRecord zrr;
- zrr.dr = answer.first;
+ zrr.dr = answer;
zrr.auth = true;
ret.push_back(zrr);
}
const bool TCPIOHandler::s_disableConnectForUnitTests = false;
+namespace {
+bool shouldDoVerboseLogging()
+{
+#ifdef DNSDIST
+ return dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+#elif defined(RECURSOR)
+ return false;
+#else
+ return true;
+#endif
+}
+}
+
#ifdef HAVE_LIBSODIUM
#include <sodium.h>
#endif /* HAVE_LIBSODIUM */
+TLSCtx::tickets_key_added_hook TLSCtx::s_ticketsKeyAddedHook{nullptr};
+
+static std::vector<std::vector<uint8_t>> getALPNVector(TLSFrontend::ALPN alpn, bool client)
+{
+ if (alpn == TLSFrontend::ALPN::DoT) {
+ /* we want to set the ALPN to dot (RFC7858), if only to mitigate the ALPACA attack */
+ return std::vector<std::vector<uint8_t>>{{'d', 'o', 't'}};
+ }
+ if (alpn == TLSFrontend::ALPN::DoH) {
+ if (client) {
+ /* we want to set the ALPN to h2, if only to mitigate the ALPACA attack */
+ return std::vector<std::vector<uint8_t>>{{'h', '2'}};
+ }
+ /* For server contexts, we want to set the ALPN for DoH (note that h2o sets it own ALPN values):
+ - HTTP/1.1 so that the OpenSSL callback ALPN accepts it, letting us later return a static response
+ - HTTP/2
+ */
+ return std::vector<std::vector<uint8_t>>{{'h', '2'},{'h', 't', 't', 'p', '/', '1', '.', '1'}};
+ }
+ return {};
+}
+
#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
#ifdef HAVE_LIBSSL
std::unique_ptr<SSL_SESSION, void(*)(SSL_SESSION*)> d_sess;
};
+class OpenSSLTLSIOCtx;
+
class OpenSSLTLSConnection: public TLSConnection
{
public:
/* server side connection */
- OpenSSLTLSConnection(int socket, const struct timeval& timeout, std::shared_ptr<OpenSSLFrontendContext> feContext): d_feContext(std::move(feContext)), d_conn(std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(d_feContext->d_tlsCtx.get()), SSL_free)), d_timeout(timeout)
+ OpenSSLTLSConnection(int socket, const struct timeval& timeout, std::shared_ptr<const OpenSSLTLSIOCtx> tlsCtx, std::unique_ptr<SSL, void(*)(SSL*)>&& conn): d_tlsCtx(std::move(tlsCtx)), d_conn(std::move(conn)), d_timeout(timeout)
{
d_socket = socket;
if (!d_conn) {
vinfolog("Error creating TLS object");
- if (g_verbose) {
+ if (shouldDoVerboseLogging()) {
ERR_print_errors_fp(stderr);
}
throw std::runtime_error("Error creating TLS object");
}
/* client-side connection */
- OpenSSLTLSConnection(const std::string& hostname, bool hostIsAddr, int socket, const struct timeval& timeout, std::shared_ptr<SSL_CTX>& tlsCtx): d_tlsCtx(tlsCtx), d_conn(std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(tlsCtx.get()), SSL_free)), d_hostname(hostname), d_timeout(timeout)
+ OpenSSLTLSConnection(std::string hostname, bool hostIsAddr, int socket, const struct timeval& timeout, std::shared_ptr<const OpenSSLTLSIOCtx> tlsCtx, std::unique_ptr<SSL, void(*)(SSL*)>&& conn): d_tlsCtx(std::move(tlsCtx)), d_conn(std::move(conn)), d_hostname(std::move(hostname)), d_timeout(timeout), d_isClient(true)
{
d_socket = socket;
if (!d_conn) {
vinfolog("Error creating TLS object");
- if (g_verbose) {
+ if (shouldDoVerboseLogging()) {
ERR_print_errors_fp(stderr);
}
throw std::runtime_error("Error creating TLS object");
}
#endif
else {
- if (g_verbose) {
+ if (shouldDoVerboseLogging()) {
throw std::runtime_error("Error while processing TLS connection: (" + std::to_string(error) + ") " + libssl_get_error_string());
} else {
throw std::runtime_error("Error while processing TLS connection: " + std::to_string(error));
IOState tryHandshake() override
{
- if (!d_feContext) {
+ if (isClient()) {
/* In client mode, the handshake is initiated by the call to SSL_connect()
done from connect()/tryConnect().
In blocking mode it does not return before the handshake has been finished,
void doHandshake() override
{
- if (!d_feContext) {
+ if (isClient()) {
/* we are a client, nothing to do, see the non-blocking version */
return;
}
IOState tryWrite(const PacketBuffer& buffer, size_t& pos, size_t toWrite) override
{
- if (!d_feContext && !d_connected) {
+ if (isClient() && !d_connected) {
if (d_ktls) {
/* work-around to get kTLS to be started, as we cannot do that until after the socket has been connected */
SSL_set_fd(d_conn.get(), SSL_get_fd(d_conn.get()));
const unsigned char* alpn = nullptr;
unsigned int alpnLen = 0;
-#ifndef DISABLE_NPN
-#ifdef HAVE_SSL_GET0_NEXT_PROTO_NEGOTIATED
- SSL_get0_next_proto_negotiated(d_conn.get(), &alpn, &alpnLen);
-#endif /* HAVE_SSL_GET0_NEXT_PROTO_NEGOTIATED */
-#endif /* DISABLE_NPN */
#ifdef HAVE_SSL_GET0_ALPN_SELECTED
if (alpn == nullptr) {
SSL_get0_alpn_selected(d_conn.get(), &alpn, &alpnLen);
d_ktls = true;
}
+ [[nodiscard]] bool isClient() const
+ {
+ return d_isClient;
+ }
+
static void generateConnectionIndexIfNeeded()
{
auto init = s_initTLSConnIndex.lock();
static LockGuarded<bool> s_initTLSConnIndex;
static int s_tlsConnIndex;
std::vector<std::unique_ptr<TLSSession>> d_tlsSessions;
- /* server context */
- std::shared_ptr<OpenSSLFrontendContext> d_feContext;
- /* client context */
- std::shared_ptr<SSL_CTX> d_tlsCtx;
+ const std::shared_ptr<const OpenSSLTLSIOCtx> d_tlsCtx; // we need to hold a reference to this to make sure that the context exists for as long as the connection, even if a reload happens in the meantime
std::unique_ptr<SSL, void(*)(SSL*)> d_conn;
- std::string d_hostname;
- struct timeval d_timeout;
+ const std::string d_hostname;
+ const timeval d_timeout;
bool d_connected{false};
bool d_ktls{false};
+ const bool d_isClient{false};
};
LockGuarded<bool> OpenSSLTLSConnection::s_initTLSConnIndex{false};
int OpenSSLTLSConnection::s_tlsConnIndex{-1};
-class OpenSSLTLSIOCtx: public TLSCtx
+class OpenSSLTLSIOCtx: public TLSCtx, public std::enable_shared_from_this<OpenSSLTLSIOCtx>
{
+ struct Private
+ {
+ explicit Private() = default;
+ };
+
public:
+ static std::shared_ptr<OpenSSLTLSIOCtx> createServerSideContext(TLSFrontend& frontend)
+ {
+ return std::make_shared<OpenSSLTLSIOCtx>(frontend, Private());
+ }
+
+ static std::shared_ptr<OpenSSLTLSIOCtx> createClientSideContext(const TLSContextParameters& params)
+ {
+ return std::make_shared<OpenSSLTLSIOCtx>(params, Private());
+ }
+
/* server side context */
- OpenSSLTLSIOCtx(TLSFrontend& fe): d_feContext(std::make_shared<OpenSSLFrontendContext>(fe.d_addr, fe.d_tlsConfig))
+ OpenSSLTLSIOCtx(TLSFrontend& frontend, [[maybe_unused]] Private priv): d_alpnProtos(getALPNVector(frontend.d_alpn, false)), d_feContext(std::make_unique<OpenSSLFrontendContext>(frontend.d_addr, frontend.d_tlsConfig))
{
OpenSSLTLSConnection::generateConnectionIndexIfNeeded();
- d_ticketsKeyRotationDelay = fe.d_tlsConfig.d_ticketsKeyRotationDelay;
+ d_ticketsKeyRotationDelay = frontend.d_tlsConfig.d_ticketsKeyRotationDelay;
- if (fe.d_tlsConfig.d_enableTickets && fe.d_tlsConfig.d_numberOfTicketsKeys > 0) {
+ if (frontend.d_tlsConfig.d_enableTickets && frontend.d_tlsConfig.d_numberOfTicketsKeys > 0) {
/* use our own ticket keys handler so we can rotate them */
#if OPENSSL_VERSION_MAJOR >= 3
SSL_CTX_set_tlsext_ticket_key_evp_cb(d_feContext->d_tlsCtx.get(), &OpenSSLTLSIOCtx::ticketKeyCb);
}
#endif /* DISABLE_OCSP_STAPLING */
- if (fe.d_tlsConfig.d_readAhead) {
+ if (frontend.d_tlsConfig.d_readAhead) {
SSL_CTX_set_read_ahead(d_feContext->d_tlsCtx.get(), 1);
}
- libssl_set_error_counters_callback(d_feContext->d_tlsCtx, &fe.d_tlsCounters);
+ libssl_set_error_counters_callback(d_feContext->d_tlsCtx, &frontend.d_tlsCounters);
+
+ libssl_set_alpn_select_callback(d_feContext->d_tlsCtx.get(), alpnServerSelectCallback, this);
- if (!fe.d_tlsConfig.d_keyLogFile.empty()) {
- d_feContext->d_keyLogFile = libssl_set_key_log_file(d_feContext->d_tlsCtx, fe.d_tlsConfig.d_keyLogFile);
+ if (!frontend.d_tlsConfig.d_keyLogFile.empty()) {
+ d_feContext->d_keyLogFile = libssl_set_key_log_file(d_feContext->d_tlsCtx, frontend.d_tlsConfig.d_keyLogFile);
}
try {
- if (fe.d_tlsConfig.d_ticketKeyFile.empty()) {
+ if (frontend.d_tlsConfig.d_ticketKeyFile.empty()) {
handleTicketsKeyRotation(time(nullptr));
}
else {
- OpenSSLTLSIOCtx::loadTicketsKeys(fe.d_tlsConfig.d_ticketKeyFile);
+ OpenSSLTLSIOCtx::loadTicketsKeys(frontend.d_tlsConfig.d_ticketKeyFile);
}
}
catch (const std::exception& e) {
}
/* client side context */
- OpenSSLTLSIOCtx(const TLSContextParameters& params)
+ OpenSSLTLSIOCtx(const TLSContextParameters& params, [[maybe_unused]] Private priv)
{
int sslOptions =
SSL_OP_NO_SSLv2 |
SSL_CTX_set_session_cache_mode(d_tlsCtx.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE);
SSL_CTX_sess_set_new_cb(d_tlsCtx.get(), &OpenSSLTLSIOCtx::newTicketFromServerCb);
+ libssl_set_alpn_protos(d_tlsCtx.get(), getALPNVector(params.d_alpn, true));
+
#ifdef SSL_MODE_RELEASE_BUFFERS
if (params.d_releaseBuffers) {
SSL_CTX_set_mode(d_tlsCtx.get(), SSL_MODE_RELEASE_BUFFERS);
#endif
}
+ OpenSSLTLSIOCtx(const OpenSSLTLSIOCtx&) = delete;
+ OpenSSLTLSIOCtx(OpenSSLTLSIOCtx&&) = delete;
+ OpenSSLTLSIOCtx& operator=(const OpenSSLTLSIOCtx&) = delete;
+ OpenSSLTLSIOCtx& operator=(OpenSSLTLSIOCtx&&) = delete;
+
~OpenSSLTLSIOCtx() override
{
d_tlsCtx.reset();
return 1;
}
+ SSL_CTX* getOpenSSLContext() const
+ {
+ if (d_feContext) {
+ return d_feContext->d_tlsCtx.get();
+ }
+ return d_tlsCtx.get();
+ }
+
std::unique_ptr<TLSConnection> getConnection(int socket, const struct timeval& timeout, time_t now) override
{
handleTicketsKeyRotation(now);
- return std::make_unique<OpenSSLTLSConnection>(socket, timeout, d_feContext);
+ return std::make_unique<OpenSSLTLSConnection>(socket, timeout, shared_from_this(), std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(getOpenSSLContext()), SSL_free));
}
std::unique_ptr<TLSConnection> getClientConnection(const std::string& host, bool hostIsAddr, int socket, const struct timeval& timeout) override
{
- auto conn = std::make_unique<OpenSSLTLSConnection>(host, hostIsAddr, socket, timeout, d_tlsCtx);
+ auto conn = std::make_unique<OpenSSLTLSConnection>(host, hostIsAddr, socket, timeout, shared_from_this(), std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(getOpenSSLContext()), SSL_free));
if (d_ktls) {
conn->enableKTLS();
}
return "openssl";
}
- bool setALPNProtos(const std::vector<std::vector<uint8_t>>& protos) override
- {
- if (d_feContext && d_feContext->d_tlsCtx) {
- d_alpnProtos = protos;
- libssl_set_alpn_select_callback(d_feContext->d_tlsCtx.get(), alpnServerSelectCallback, this);
- return true;
- }
- if (d_tlsCtx) {
- return libssl_set_alpn_protos(d_tlsCtx.get(), protos);
- }
- return false;
- }
-
-#ifndef DISABLE_NPN
- bool setNextProtocolSelectCallback(bool(*cb)(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen)) override
+ bool isServerContext() const
{
- d_nextProtocolSelectCallback = cb;
- libssl_set_npn_select_callback(d_tlsCtx.get(), npnSelectCallback, this);
- return true;
+ return d_feContext != nullptr;
}
-#endif /* DISABLE_NPN */
private:
- /* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
-#ifndef DISABLE_NPN
- static int npnSelectCallback(SSL* /* s */, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg)
- {
- if (!arg) {
- return SSL_TLSEXT_ERR_ALERT_WARNING;
- }
- OpenSSLTLSIOCtx* obj = reinterpret_cast<OpenSSLTLSIOCtx*>(arg);
- if (obj->d_nextProtocolSelectCallback) {
- return (*obj->d_nextProtocolSelectCallback)(out, outlen, in, inlen) ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_ALERT_WARNING;
- }
-
- return SSL_TLSEXT_ERR_OK;
- }
-#endif /* NPN */
-
+ /* called in a client context, if the client advertised more than one ALPN value and the server returned more than one as well, to select the one to use. */
static int alpnServerSelectCallback(SSL*, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg)
{
if (!arg) {
return SSL_TLSEXT_ERR_NOACK;
}
- std::vector<std::vector<uint8_t>> d_alpnProtos; // store the supported ALPN protocols, so that the server can select based on what the client sent
- std::shared_ptr<OpenSSLFrontendContext> d_feContext{nullptr};
+ const std::vector<std::vector<uint8_t>> d_alpnProtos; // store the supported ALPN protocols, so that the server can select based on what the client sent
std::shared_ptr<SSL_CTX> d_tlsCtx{nullptr}; // client context, on a server-side the context is stored in d_feContext->d_tlsCtx
- bool (*d_nextProtocolSelectCallback)(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen){nullptr};
+ std::unique_ptr<OpenSSLFrontendContext> d_feContext{nullptr};
bool d_ktls{false};
};
throw;
}
}
+ [[nodiscard]] std::string content() const
+ {
+ std::string result{};
+ if (d_key.data != nullptr && d_key.size > 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ result.append(reinterpret_cast<const char*>(d_key.data), d_key.size);
+ safe_memory_lock(result.data(), result.size());
+ }
+ return result;
+ }
~GnuTLSTicketsKey()
{
std::unique_ptr<gnutls_session_int, void(*)(gnutls_session_t)> d_conn;
std::vector<std::unique_ptr<TLSSession>> d_tlsSessions;
std::string d_host;
- bool d_client{false};
+ const bool d_client{false};
bool d_handshakeDone{false};
};
{
public:
/* server side context */
- GnuTLSIOCtx(TLSFrontend& fe): d_enableTickets(fe.d_tlsConfig.d_enableTickets)
+ GnuTLSIOCtx(TLSFrontend& frontend): d_protos(getALPNVector(frontend.d_alpn, false)), d_enableTickets(frontend.d_tlsConfig.d_enableTickets)
{
int rc = 0;
- d_ticketsKeyRotationDelay = fe.d_tlsConfig.d_ticketsKeyRotationDelay;
+ d_ticketsKeyRotationDelay = frontend.d_tlsConfig.d_ticketsKeyRotationDelay;
gnutls_certificate_credentials_t creds;
rc = gnutls_certificate_allocate_credentials(&creds);
if (rc != GNUTLS_E_SUCCESS) {
- throw std::runtime_error("Error allocating credentials for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
+ throw std::runtime_error("Error allocating credentials for TLS context on " + frontend.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
}
d_creds = std::shared_ptr<gnutls_certificate_credentials_st>(creds, gnutls_certificate_free_credentials);
creds = nullptr;
- for (const auto& pair : fe.d_tlsConfig.d_certKeyPairs) {
+ for (const auto& pair : frontend.d_tlsConfig.d_certKeyPairs) {
rc = gnutls_certificate_set_x509_key_file(d_creds.get(), pair.d_cert.c_str(), pair.d_key->c_str(), GNUTLS_X509_FMT_PEM);
if (rc != GNUTLS_E_SUCCESS) {
- throw std::runtime_error("Error loading certificate ('" + pair.d_cert + "') and key ('" + pair.d_key.value() + "') for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
+ throw std::runtime_error("Error loading certificate ('" + pair.d_cert + "') and key ('" + pair.d_key.value() + "') for TLS context on " + frontend.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
}
}
#ifndef DISABLE_OCSP_STAPLING
size_t count = 0;
- for (const auto& file : fe.d_tlsConfig.d_ocspFiles) {
+ for (const auto& file : frontend.d_tlsConfig.d_ocspFiles) {
rc = gnutls_certificate_set_ocsp_status_request_file(d_creds.get(), file.c_str(), count);
if (rc != GNUTLS_E_SUCCESS) {
- warnlog("Error loading OCSP response from file '%s' for certificate ('%s') and key ('%s') for TLS context on %s: %s", file, fe.d_tlsConfig.d_certKeyPairs.at(count).d_cert, fe.d_tlsConfig.d_certKeyPairs.at(count).d_key.value(), fe.d_addr.toStringWithPort(), gnutls_strerror(rc));
+ warnlog("Error loading OCSP response from file '%s' for certificate ('%s') and key ('%s') for TLS context on %s: %s", file, frontend.d_tlsConfig.d_certKeyPairs.at(count).d_cert, frontend.d_tlsConfig.d_certKeyPairs.at(count).d_key.value(), frontend.d_addr.toStringWithPort(), gnutls_strerror(rc));
}
++count;
}
#if GNUTLS_VERSION_NUMBER >= 0x030600
rc = gnutls_certificate_set_known_dh_params(d_creds.get(), GNUTLS_SEC_PARAM_HIGH);
if (rc != GNUTLS_E_SUCCESS) {
- throw std::runtime_error("Error setting DH params for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
+ throw std::runtime_error("Error setting DH params for TLS context on " + frontend.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
}
#endif
- rc = gnutls_priority_init(&d_priorityCache, fe.d_tlsConfig.d_ciphers.empty() ? "NORMAL" : fe.d_tlsConfig.d_ciphers.c_str(), nullptr);
+ rc = gnutls_priority_init(&d_priorityCache, frontend.d_tlsConfig.d_ciphers.empty() ? "NORMAL" : frontend.d_tlsConfig.d_ciphers.c_str(), nullptr);
if (rc != GNUTLS_E_SUCCESS) {
- throw std::runtime_error("Error setting up TLS cipher preferences to '" + fe.d_tlsConfig.d_ciphers + "' (" + gnutls_strerror(rc) + ") on " + fe.d_addr.toStringWithPort());
+ throw std::runtime_error("Error setting up TLS cipher preferences to '" + frontend.d_tlsConfig.d_ciphers + "' (" + gnutls_strerror(rc) + ") on " + frontend.d_addr.toStringWithPort());
}
try {
- if (fe.d_tlsConfig.d_ticketKeyFile.empty()) {
+ if (frontend.d_tlsConfig.d_ticketKeyFile.empty()) {
handleTicketsKeyRotation(time(nullptr));
}
else {
- GnuTLSIOCtx::loadTicketsKeys(fe.d_tlsConfig.d_ticketKeyFile);
+ GnuTLSIOCtx::loadTicketsKeys(frontend.d_tlsConfig.d_ticketKeyFile);
}
}
catch(const std::runtime_error& e) {
- throw std::runtime_error("Error generating tickets key for TLS context on " + fe.d_addr.toStringWithPort() + ": " + e.what());
+ throw std::runtime_error("Error generating tickets key for TLS context on " + frontend.d_addr.toStringWithPort() + ": " + e.what());
}
}
/* client side context */
- GnuTLSIOCtx(const TLSContextParameters& params): d_contextParameters(std::make_unique<TLSContextParameters>(params)), d_enableTickets(true), d_validateCerts(params.d_validateCertificates)
+ GnuTLSIOCtx(const TLSContextParameters& params): d_protos(getALPNVector(params.d_alpn, true)), d_contextParameters(std::make_unique<TLSContextParameters>(params)), d_validateCerts(params.d_validateCertificates)
{
int rc = 0;
return connection;
}
- void rotateTicketsKey(time_t now) override
+ void addTicketsKey(time_t now, std::shared_ptr<GnuTLSTicketsKey>&& newKey)
{
if (!d_enableTickets) {
return;
}
- auto newKey = std::make_shared<GnuTLSTicketsKey>();
-
{
*(d_ticketsKey.write_lock()) = std::move(newKey);
}
if (d_ticketsKeyRotationDelay > 0) {
d_ticketsKeyNextRotation = now + d_ticketsKeyRotationDelay;
}
+
+ if (TLSCtx::hasTicketsKeyAddedHook()) {
+ auto ticketsKey = *(d_ticketsKey.read_lock());
+ auto content = ticketsKey->content();
+ TLSCtx::getTicketsKeyAddedHook()(content);
+ safe_memory_release(content.data(), content.size());
+ }
}
+ void rotateTicketsKey(time_t now) override
+ {
+ if (!d_enableTickets) {
+ return;
+ }
+ auto newKey = std::make_shared<GnuTLSTicketsKey>();
+ addTicketsKey(now, std::move(newKey));
+ }
void loadTicketsKeys(const std::string& file) final
{
if (!d_enableTickets) {
}
auto newKey = std::make_shared<GnuTLSTicketsKey>(file);
- {
- *(d_ticketsKey.write_lock()) = std::move(newKey);
- }
-
- if (d_ticketsKeyRotationDelay > 0) {
- d_ticketsKeyNextRotation = time(nullptr) + d_ticketsKeyRotationDelay;
- }
+ addTicketsKey(time(nullptr), std::move(newKey));
}
size_t getTicketsKeysCount() override
return "gnutls";
}
- bool setALPNProtos(const std::vector<std::vector<uint8_t>>& protos) override
- {
-#ifdef HAVE_GNUTLS_ALPN_SET_PROTOCOLS
- d_protos = protos;
- return true;
-#else
- return false;
-#endif
- }
-
private:
/* client context parameters */
- std::unique_ptr<TLSContextParameters> d_contextParameters{nullptr};
std::shared_ptr<gnutls_certificate_credentials_st> d_creds;
- std::vector<std::vector<uint8_t>> d_protos;
+ const std::vector<std::vector<uint8_t>> d_protos;
+ std::unique_ptr<TLSContextParameters> d_contextParameters{nullptr};
gnutls_priority_t d_priorityCache{nullptr};
SharedLockGuarded<std::shared_ptr<GnuTLSTicketsKey>> d_ticketsKey{nullptr};
bool d_enableTickets{true};
#endif /* HAVE_DNS_OVER_TLS || HAVE_DNS_OVER_HTTPS */
-bool setupDoTProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
-{
- if (ctx == nullptr) {
- return false;
- }
- /* we want to set the ALPN to dot (RFC7858), if only to mitigate the ALPACA attack */
- const std::vector<std::vector<uint8_t>> dotAlpns = {{'d', 'o', 't'}};
- ctx->setALPNProtos(dotAlpns);
- return true;
-}
-
-bool setupDoHProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
-{
- if (ctx == nullptr) {
- return false;
- }
- /* This code is only called for incoming/server TLS contexts (not outgoing/client),
- and h2o sets it own ALPN values.
- We want to set the ALPN for DoH:
- - HTTP/1.1 so that the OpenSSL callback ALPN accepts it, letting us later return a static response
- - HTTP/2
- */
- const std::vector<std::vector<uint8_t>> dohAlpns{{'h', '2'},{'h', 't', 't', 'p', '/', '1', '.', '1'}};
- ctx->setALPNProtos(dohAlpns);
-
- return true;
-}
-
bool TLSFrontend::setupTLS()
{
#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
#endif /* HAVE_GNUTLS */
#if defined(HAVE_LIBSSL)
if (d_provider == "openssl") {
- newCtx = std::make_shared<OpenSSLTLSIOCtx>(*this);
+ newCtx = OpenSSLTLSIOCtx::createServerSideContext(*this);
}
#endif /* HAVE_LIBSSL */
if (!newCtx) {
#if defined(HAVE_LIBSSL)
- newCtx = std::make_shared<OpenSSLTLSIOCtx>(*this);
+ newCtx = OpenSSLTLSIOCtx::createServerSideContext(*this);
#elif defined(HAVE_GNUTLS)
newCtx = std::make_shared<GnuTLSIOCtx>(*this);
#else
#endif
}
- if (d_alpn == ALPN::DoT) {
- setupDoTProtocolNegotiation(newCtx);
- }
- else if (d_alpn == ALPN::DoH) {
- setupDoHProtocolNegotiation(newCtx);
- }
-
std::atomic_store_explicit(&d_ctx, std::move(newCtx), std::memory_order_release);
#endif /* HAVE_DNS_OVER_TLS || HAVE_DNS_OVER_HTTPS */
return true;
#endif /* HAVE_GNUTLS */
#if defined(HAVE_LIBSSL)
if (params.d_provider == "openssl") {
- return std::make_shared<OpenSSLTLSIOCtx>(params);
+ return OpenSSLTLSIOCtx::createClientSideContext(params);
}
#endif /* HAVE_LIBSSL */
}
#if defined(HAVE_LIBSSL)
- return std::make_shared<OpenSSLTLSIOCtx>(params);
+ return OpenSSLTLSIOCtx::createClientSideContext(params);
#elif defined(HAVE_GNUTLS)
return std::make_shared<GnuTLSIOCtx>(params);
#else
{
throw std::runtime_error("This TLS backend does not have the capability to load a tickets key from a file");
}
-
void handleTicketsKeyRotation(time_t now)
{
if (d_ticketsKeyRotationDelay != 0 && now > d_ticketsKeyNextRotation) {
virtual size_t getTicketsKeysCount() = 0;
virtual std::string getName() const = 0;
- /* set the advertised ALPN protocols, in client or server context */
- virtual bool setALPNProtos(const std::vector<std::vector<uint8_t>>& /* protos */)
+ using tickets_key_added_hook = std::function<void(const std::string& key)>;
+
+ static void setTicketsKeyAddedHook(const tickets_key_added_hook& hook)
{
- return false;
+ TLSCtx::s_ticketsKeyAddedHook = hook;
}
-
- /* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
- virtual bool setNextProtocolSelectCallback(bool(*)(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen))
+ static const tickets_key_added_hook& getTicketsKeyAddedHook()
{
- return false;
+ return TLSCtx::s_ticketsKeyAddedHook;
+ }
+ static bool hasTicketsKeyAddedHook()
+ {
+ return TLSCtx::s_ticketsKeyAddedHook != nullptr;
}
-
protected:
std::atomic_flag d_rotatingTicketsKey;
std::atomic<time_t> d_ticketsKeyNextRotation{0};
time_t d_ticketsKeyRotationDelay{0};
+
+private:
+ static tickets_key_added_hook s_ticketsKeyAddedHook;
};
class TLSFrontend
return d_conn->getAsyncFDs();
}
- const static bool s_disableConnectForUnitTests;
+ static const bool s_disableConnectForUnitTests;
private:
std::unique_ptr<TLSConnection> d_conn{nullptr};
std::string d_ciphers;
std::string d_ciphers13;
std::string d_caStore;
+ TLSFrontend::ALPN d_alpn{TLSFrontend::ALPN::Unset};
bool d_validateCertificates{true};
bool d_releaseBuffers{true};
bool d_enableRenegotiation{false};
uint32_t serial = 0;
MOADNSParser mdp(false, q->getString());
for(const auto & answer : mdp.d_answers) {
- const DNSRecord *rr = &answer.first;
- if (rr->d_type == QType::SOA && rr->d_place == DNSResourceRecord::AUTHORITY) {
+ const DNSRecord *dnsRecord = &answer;
+ if (dnsRecord->d_type == QType::SOA && dnsRecord->d_place == DNSResourceRecord::AUTHORITY) {
vector<string>parts;
- stringtok(parts, rr->getContent()->getZoneRepresentation());
+ stringtok(parts, dnsRecord->getContent()->getZoneRepresentation());
if (parts.size() >= 3) {
try {
pdns::checked_stoi_into(serial, parts[2]);
sendPacket(outpacket,outsock);
return 0;
}
- } else if (rr->d_type != QType::TSIG && rr->d_type != QType::OPT) {
- g_log<<Logger::Warning<<logPrefix<<"additional records in IXFR query, type: "<<QType(rr->d_type).toString()<<endl;
+ } else if (dnsRecord->d_type != QType::TSIG && dnsRecord->d_type != QType::OPT) {
+ g_log<<Logger::Warning<<logPrefix<<"additional records in IXFR query, type: "<<QType(dnsRecord->d_type).toString()<<endl;
outpacket->setRcode(RCode::FormErr);
sendPacket(outpacket,outsock);
return 0;
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include <stdlib.h>
+#include <cstdlib>
#include <unistd.h>
#include <boost/test/unit_test.hpp>
#include "distributor.hh"
struct BackendSlow
{
- std::unique_ptr<DNSPacket> question(Question&)
+ std::unique_ptr<DNSPacket> question([[maybe_unused]] Question& query)
{
if (d_shouldSleep) {
/* only sleep once per distributor thread, otherwise
bool d_shouldSleep{true};
};
-static std::atomic<int> g_receivedAnswers1;
+static std::atomic<size_t> s_receivedAnswers;
static void report1(std::unique_ptr<DNSPacket>& /* A */, int /* B */)
{
- g_receivedAnswers1++;
+ s_receivedAnswers++;
}
BOOST_AUTO_TEST_CASE(test_distributor_queue) {
S.declare("servfail-packets","Number of times a server-failed packet was sent out");
S.declare("timedout-packets", "timedout-packets");
- auto d=Distributor<DNSPacket, Question, BackendSlow>::Create(2);
+ s_receivedAnswers.store(0);
+ auto* distributor = Distributor<DNSPacket, Question, BackendSlow>::Create(2);
+ size_t queued = 0;
BOOST_CHECK_EXCEPTION( {
- int n;
// bound should be higher than max-queue-length
- for(n=0; n < 2000; ++n) {
- Question q;
- q.d_dt.set();
- d->question(q, report1);
+ const size_t bound = 2000;
+ for (size_t idx = 0; idx < bound; ++idx) {
+ Question query;
+ query.d_dt.set();
+ ++queued;
+ distributor->question(query, report1);
}
}, DistributorFatal, [](DistributorFatal) { return true; });
+
+ BOOST_CHECK_GT(queued, 1000U);
+
+ // now we want to make sure that all queued queries have been processed
+ // otherwise LeakSanitizer will report a leak, but we are only willing to
+ // wait up to 3 seconds (3000 milliseconds)
+ size_t remainingMs = 3000;
+ while (s_receivedAnswers.load() < queued && remainingMs > 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ remainingMs -= 10;
+ }
};
struct BackendDies
MOADNSParser parser(false, reinterpret_cast<const char*>(packet.data()), packet.size());
BOOST_REQUIRE_EQUAL(parser.d_answers.size(), 1U);
- const auto& record = parser.d_answers.at(0).first;
+ const auto& record = parser.d_answers.at(0);
BOOST_REQUIRE(record.d_type == QType::NSEC3);
BOOST_REQUIRE(record.d_class == QClass::IN);
auto content = getRR<NSEC3RecordContent>(record);
struct TestObject
{
string name;
- uint64_t number;
+ uint64_t number{0};
};
-static GlobalStateHolder<TestObject> g_to;
-std::atomic<bool> g_failed;
+static GlobalStateHolder<TestObject> s_to;
+static std::atomic<bool> s_failed;
BOOST_AUTO_TEST_SUITE(test_sholder_hh)
-void treader()
+static void treader()
{
- auto local = g_to.getLocal();
- for(int n=0; n < 10000000; ++n) {
- auto g = *local;
- if(g.name != std::to_string(g.number)) {
- g_failed=1;
+ auto local = s_to.getLocal();
+ for (uint64_t counter = 0; counter < 10000000U; ++counter) {
+ auto copy = *local;
+ if (copy.name != std::to_string(copy.number)) {
+ s_failed.store(true);
break;
}
}
}
-BOOST_AUTO_TEST_CASE(test_sholder) {
- g_to.setState({"1", 1});
+BOOST_AUTO_TEST_CASE(test_sholder)
+{
+ s_to.setState({"1", 1});
- std::thread t1(treader);
- for(unsigned int n=0; n < 1000000; ++n) {
- g_to.setState({std::to_string(n), n});
- g_to.modify([n](TestObject& to) { to.number = 2*n; to.name=std::to_string(to.number);} );
+ std::thread thread1(treader);
+ for (uint64_t counter = 0; counter < 1000000U; ++counter) {
+ s_to.setState({std::to_string(counter), counter});
+ s_to.modify([counter](TestObject& toValue) { toValue.number = 2*counter; toValue.name = std::to_string(toValue.number); });
}
- t1.join();
- BOOST_CHECK_EQUAL(g_failed, 0);
+ thread1.join();
+ BOOST_CHECK_EQUAL(s_failed, 0);
}
-
BOOST_AUTO_TEST_SUITE_END()
-
TSIGRecordContent trc;
for(const auto& answer: mdp.d_answers) {
- if(answer.first.d_type == QType::TSIG) {
- BOOST_CHECK_EQUAL(answer.first.d_place, DNSResourceRecord::ADDITIONAL);
- BOOST_CHECK_EQUAL(answer.first.d_class, QClass::ANY);
- BOOST_CHECK_EQUAL(answer.first.d_ttl, 0U);
+ if(answer.d_type == QType::TSIG) {
+ BOOST_CHECK_EQUAL(answer.d_place, DNSResourceRecord::ADDITIONAL);
+ BOOST_CHECK_EQUAL(answer.d_class, QClass::ANY);
+ BOOST_CHECK_EQUAL(answer.d_ttl, 0U);
BOOST_CHECK_EQUAL(tsigFound, false);
- auto rectrc = getRR<TSIGRecordContent>(answer.first);
+ auto rectrc = getRR<TSIGRecordContent>(answer);
if (rectrc) {
trc = *rectrc;
theirMac = rectrc->d_mac;
- keyName = answer.first.d_name;
+ keyName = answer.d_name;
tsigFound = true;
}
}
// entry point:
int main(int argc, char* argv[])
{
+ setenv("BOOST_TEST_RANDOM", "1", 1); // NOLINT(concurrency-mt-unsafe)
S.d_allowRedeclare = true;
return boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
}
}
for(const auto& answer : mdp.d_answers) {
- if (answer.first.d_type == QType::SOA) {
+ if (answer.d_type == QType::SOA) {
// A SOA is either the first or the last record. We need to check TSIG if that's the case.
checkTSIG = true;
}
- if(answer.first.d_type == QType::TSIG) {
- auto trc = getRR<TSIGRecordContent>(answer.first);
+ if(answer.d_type == QType::TSIG) {
+ auto trc = getRR<TSIGRecordContent>(answer);
if(trc) {
theirMac = trc->d_mac;
d_trc.d_time = trc->d_time;
return false;
}
+void UeberBackend::lookupEnd()
+{
+ if (!d_negcached && !d_cached) {
+ DNSZoneRecord zoneRecord;
+ while (d_handle.get(zoneRecord)) {
+ // Read all answers so the backends will close any database handles they might have allocated.
+ // One day this could be optimized.
+ }
+ }
+
+ d_answers.clear();
+ d_cached = d_negcached = false;
+}
+
// TSIG
//
bool UeberBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
};
void lookup(const QType& qtype, const DNSName& qname, int zoneId, DNSPacket* pkt_p = nullptr);
+ /** Read a single record from a lookup(...) result. */
+ bool get(DNSZoneRecord& resourceRecord);
+ /** Close state created by lookup(...). */
+ void lookupEnd();
/** Determines if we are authoritative for a zone, and at what level */
bool getAuth(const DNSName& target, const QType& qtype, SOAData* soaData, bool cachedOk = true);
/** Load SOA info from backends, ignoring the cache.*/
bool getSOAUncached(const DNSName& domain, SOAData& soaData);
- bool get(DNSZoneRecord& resourceRecord);
void getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled);
void getUnfreshSecondaryInfos(vector<DomainInfo>* domains);
#endif /* BOOST_PENDING_INTEGER_LOG2_HPP */
#endif /* BOOST_VERSION */
+#include <boost/random/mersenne_twister.hpp>
#include <boost/uuid/uuid_generators.hpp>
// The default of:
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifdef HAVE_CONFIG_H
+
#include "config.h"
-#endif
-#include "logger.hh"
#include "version.hh"
+#include "namespaces.hh"
+
+#ifdef PDNS_MODULES
#include "dnsbackend.hh"
+#endif
+#include <sstream>
#include <boost/algorithm/string/join.hpp>
static ProductType productType;
string compilerVersion()
{
#if defined(__clang__)
- return string("clang " __clang_version__ );
+ return "clang " __clang_version__;
#elif defined(__GNUC__)
- return string("gcc " __VERSION__ );
-#else // add other compilers here
- return string("Unknown compiler");
+ return "gcc " __VERSION__;
+#else // add other compilers here
+ return "Unknown compiler";
#endif
}
// Human-readable product name
-string productName() {
+string productName()
+{
switch (productType) {
case ProductAuthoritative:
return "PowerDNS Authoritative Server";
}
// REST API product type
-string productTypeApiType() {
+string productTypeApiType()
+{
switch (productType) {
case ProductAuthoritative:
return "authoritative";
return "unknown";
}
-void showProductVersion()
+vector<string> getProductVersionLines()
+{
+ vector<string> ret;
+ std::istringstream istr(getProductVersion());
+ for (string line; std::getline(istr, line);) {
+ ret.emplace_back(line);
+ }
+ return ret;
+}
+
+string getProductVersion()
{
- g_log<<Logger::Warning<<productName()<<" "<< VERSION << " (C) "
- "PowerDNS.COM BV" << endl;
- g_log<<Logger::Warning<<"Using "<<(sizeof(unsigned long)*8)<<"-bits mode. "
- "Built using " << compilerVersion()
+ ostringstream ret;
+ ret << productName() << " " << VERSION << " (C) "
+ "PowerDNS.COM BV"
+ << endl;
+ ret << "Using " << (sizeof(unsigned long) * 8) << "-bits mode. "
+ "Built using "
+ << compilerVersion()
#ifndef REPRODUCIBLE
- <<" on " __DATE__ " " __TIME__ " by " BUILD_HOST
-#endif
- <<"."<< endl;
- g_log<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
- "This is free software, and you are welcome to redistribute it "
- "according to the terms of the GPL version 2." << endl;
+ << " on " __DATE__ " " __TIME__ " by " BUILD_HOST
+#endif
+ << "." << endl;
+ ret << "PowerDNS comes with ABSOLUTELY NO WARRANTY. "
+ "This is free software, and you are welcome to redistribute it "
+ "according to the terms of the GPL version 2."
+ << endl;
+ return ret.str();
}
-void showBuildConfiguration()
+string getBuildConfiguration()
{
- g_log<<Logger::Warning<<"Features: "<<
+ ostringstream ret;
+ ret << "Features:"
#ifdef HAVE_LIBDECAF
- "decaf " <<
-#endif
-#ifdef HAVE_BOOST_CONTEXT
- "fcontext " <<
+ << " decaf"
#endif
#ifdef HAVE_LIBCRYPTO_ECDSA
- "libcrypto-ecdsa " <<
+ << " libcrypto-ecdsa"
#endif
#ifdef HAVE_LIBCRYPTO_ED25519
- "libcrypto-ed25519 " <<
+ << " libcrypto-ed25519"
#endif
#ifdef HAVE_LIBCRYPTO_ED448
- "libcrypto-ed448 " <<
+ << " libcrypto-ed448"
#endif
#ifdef HAVE_LIBCRYPTO_EDDSA
- "libcrypto-eddsa " <<
+ << " libcrypto-eddsa"
#endif
#ifdef HAVE_LIBDL
- "libdl " <<
+ << " libdl"
#endif
#ifdef HAVE_GEOIP
- "libgeoip " <<
+ << " libgeoip"
#endif
#ifdef HAVE_MMDB
- "libmaxminddb " <<
+ << " libmaxminddb"
#endif
#ifdef HAVE_LUA
- "lua " <<
+ << " lua"
#endif
#ifdef HAVE_LUA_RECORDS
- "lua-records " <<
+ << " lua-records"
#endif
#ifdef NOD_ENABLED
- "nod " <<
+ << " nod"
#endif
#ifdef HAVE_P11KIT1
- "PKCS#11 " <<
+ << " PKCS#11"
#endif
-"protobuf " <<
+ << " protobuf"
#ifdef HAVE_FSTRM
-"dnstap-framestream " <<
+ << " dnstap-framestream"
#endif
#ifdef REMOTEBACKEND_ZEROMQ
- "remotebackend-zeromq " <<
+ << " remotebackend-zeromq"
#endif
#ifdef HAVE_NET_SNMP
- "snmp " <<
+ << " snmp"
#endif
#ifdef HAVE_LIBSODIUM
- "sodium " <<
+ << " sodium"
#endif
#ifdef HAVE_LIBCURL
- "curl " <<
+ << " curl"
#endif
#ifdef HAVE_DNS_OVER_TLS
- "DoT " <<
+ << " DoT"
#endif
#ifdef HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT
- "scrypt " <<
+ << " scrypt"
#endif
#ifdef ENABLE_GSS_TSIG
- "gss-tsig " <<
+ << " gss-tsig"
#endif
#ifdef VERBOSELOG
- "verboselog" <<
+ << " verboselog"
#endif
- endl;
+ << endl;
#ifdef PDNS_MODULES
// Auth only
- g_log << Logger::Warning << "Built-in modules: " << PDNS_MODULES << endl;
+ ret << "Built-in modules: " << PDNS_MODULES << endl;
const auto& modules = BackendMakers().getModules();
- g_log << Logger::Warning << "Loaded modules: " << boost::join(modules, " ") << endl;
+ ret << "Loaded modules: " << boost::join(modules, " ") << endl;
#endif
+// NOLINTBEGIN(cppcoreguidelines-macro-usage)
#ifdef PDNS_CONFIG_ARGS
#define double_escape(s) #s
#define escape_quotes(s) double_escape(s)
- g_log<<Logger::Warning<<"Configured with: "<<escape_quotes(PDNS_CONFIG_ARGS)<<endl;
+ // NOLINTEND(cppcoreguidelines-macro-usage)
+ ret << "Configured with: " << escape_quotes(PDNS_CONFIG_ARGS) << endl;
#undef escape_quotes
#undef double_escape
#endif
+ return ret.str();
}
string fullVersionString()
{
- ostringstream s;
- s<<productName()<<" " VERSION;
+ ostringstream ret;
+ ret << productName() << " " VERSION;
#ifndef REPRODUCIBLE
- s<<" (built " __DATE__ " " __TIME__ " by " BUILD_HOST ")";
+ ret << " (built " __DATE__ " " __TIME__ " by " BUILD_HOST ")";
#endif
- return s.str();
+ return ret.str();
}
-void versionSetProduct(ProductType pt)
+void versionSetProduct(ProductType productType_)
{
- productType = pt;
+ productType = productType_;
}
ProductType versionGetProduct()
#pragma once
#include "namespaces.hh"
-enum ProductType { ProductAuthoritative, ProductRecursor };
+enum ProductType
+{
+ ProductAuthoritative,
+ ProductRecursor
+};
-string compilerVersion();
-void showProductVersion();
-void showBuildConfiguration();
-string fullVersionString();
-string getPDNSVersion();
-string productName();
-string productTypeApiType();
-void versionSetProduct(ProductType pt);
-ProductType versionGetProduct();
+[[nodiscard]] std::string compilerVersion();
+[[nodiscard]] std::vector<std::string> getProductVersionLines();
+[[nodiscard]] std::string getProductVersion();
+[[nodiscard]] std::string getBuildConfiguration();
+[[nodiscard]] std::string fullVersionString();
+[[nodiscard]] std::string getPDNSVersion();
+[[nodiscard]] std::string productName();
+[[nodiscard]] std::string productTypeApiType();
+void versionSetProduct(ProductType productType_);
+[[nodiscard]] ProductType versionGetProduct();
view(data_, size_)
{
}
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): No unsigned char view in C++17
+ // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast): No unsigned char view in C++17
UnsignedCharView(const unsigned char* data_, size_t size_) :
view(reinterpret_cast<const char*>(data_), size_)
{
}
- const unsigned char& at(std::string_view::size_type pos) const
+ using size_type = std::string_view::size_type;
+
+ [[nodiscard]] const unsigned char& at(size_type pos) const
{
return reinterpret_cast<const unsigned char&>(view.at(pos));
}
- size_t size() const
+ [[nodiscard]] const unsigned char& operator[](size_type pos) const
+ {
+ return reinterpret_cast<const unsigned char&>(view[pos]);
+ }
+
+ [[nodiscard]] const unsigned char* data() const
+ {
+ return reinterpret_cast<const unsigned char*>(view.data());
+ }
+ // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast): No unsigned char view in C++17
+
+ [[nodiscard]] size_t size() const
{
return view.size();
}
+ [[nodiscard]] size_t length() const
+ {
+ return view.length();
+ }
+
private:
std::string_view view;
};
catch(PDNSException &e) {
SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": Exception: " << e.reason << endl,
log->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("PDNSException")));
- throw HttpInternalServerErrorException();
+ throw HttpInternalServerErrorException(e.reason);
}
catch(std::exception &e) {
SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": STL Exception: " << e.what() << endl,
log->error(Logr::Error, e.what(), msg, "exception", Logging::Loggable("std::exception")));
- throw HttpInternalServerErrorException();
+ throw HttpInternalServerErrorException(e.what());
}
catch(...) {
SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": Unknown Exception" << endl,
YaHTTP::AsyncRequestLoader yarl;
yarl.initialize(&req);
req.max_request_size=d_maxbodysize;
- int timeout = 5;
+ int timeout = d_connectiontimeout;
client->setNonBlocking();
try {
while(!req.complete) {
- int bytes;
- char buf[16000];
- bytes = client->readWithTimeout(buf, sizeof(buf), timeout);
+ std::array<char, 16000> buf{};
+ auto bytes = client->readWithTimeout(buf.data(), buf.size(), timeout);
if (bytes > 0) {
- string data = string(buf, bytes);
+ string data = string(buf.data(), bytes);
req.complete = yarl.feed(data);
} else {
// read error OR EOF
d_listenaddress(std::move(listenaddress)),
d_port(port),
d_server(nullptr),
- d_maxbodysize(2*1024*1024)
+ d_maxbodysize(2*1024*1024),
+ d_connectiontimeout(5)
{
YaHTTP::Router::Map("OPTIONS", "/<*url>", [](YaHTTP::Request *req, YaHTTP::Response *resp) {
// look for url in routes
d_maxbodysize = s * 1024 * 1024;
}
+ void setConnectionTimeout(int t) { // in seconds
+ d_connectiontimeout = t;
+ }
+
void setACL(const NetmaskGroup &nmg) {
d_acl = nmg;
}
std::unique_ptr<CredentialsHolder> d_webserverPassword{nullptr};
ssize_t d_maxbodysize; // in bytes
+ int d_connectiontimeout; // in seconds
NetmaskGroup d_acl;
d_ws->setACL(acl);
d_ws->setMaxBodySize(::arg().asNum("webserver-max-bodysize"));
+ d_ws->setConnectionTimeout(::arg().asNum("webserver-connection-timeout"));
d_ws->bind();
}
vector<DNSResourceRecord> records;
vector<Comment> comments;
+ QType qType = QType::ANY;
+ DNSName qName;
+
// load all records + sort
{
DNSResourceRecord resourceRecord;
domainInfo.backend->list(zonename, static_cast<int>(domainInfo.id), true); // incl. disabled
}
else {
- QType qType;
- if (req->getvars.count("rrset_type") == 0) {
- qType = QType::ANY;
- }
- else {
+ qName = DNSName(req->getvars["rrset_name"]);
+ if (req->getvars.count("rrset_type") != 0) {
qType = req->getvars["rrset_type"];
}
- domainInfo.backend->lookup(qType, DNSName(req->getvars["rrset_name"]), static_cast<int>(domainInfo.id));
+ domainInfo.backend->lookup(qType, qName, static_cast<int>(domainInfo.id));
}
while (domainInfo.backend->get(resourceRecord)) {
if (resourceRecord.qtype.getCode() == 0) {
Comment comment;
domainInfo.backend->listComments(domainInfo.id);
while (domainInfo.backend->getComment(comment)) {
- comments.push_back(comment);
+ if ((qName.empty() || comment.qname == qName) && (qType == QType::ANY || comment.qtype == qType)) {
+ comments.push_back(comment);
+ }
}
sort(comments.begin(), comments.end(), [](const Comment& rrA, const Comment& rrB) {
/* if you ever want to update this comparison function,
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#ifdef HAVE_XSK
-
-#include <algorithm>
-#include <cstdint>
-#include <cstring>
-#include <fcntl.h>
-#include <iterator>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <poll.h>
-#include <stdexcept>
-#include <sys/eventfd.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
-#include <vector>
-
-#include <bpf/bpf.h>
-#include <bpf/libbpf.h>
-extern "C"
-{
-#include <xdp/libxdp.h>
-}
-
-#include "gettime.hh"
-#include "xsk.hh"
-
-/* we need to include the linux specific headers AFTER the regular
- ones, because it then detects that some types have already been
- defined (sockaddr_in6 for example) and does not attempt to
- re-define them, which otherwise breaks the C++ One Definition Rule
-*/
-#include <linux/bpf.h>
-#include <linux/if_ether.h>
-#include <linux/if_link.h>
-#include <linux/if_xdp.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/udp.h>
-
-#ifdef DEBUG_UMEM
-namespace
-{
-struct UmemEntryStatus
-{
- enum class Status : uint8_t
- {
- Free,
- FillQueue,
- Received,
- TXQueue
- };
- Status status{Status::Free};
-};
-
-LockGuarded<std::unordered_map<uint64_t, UmemEntryStatus>> s_umems;
-
-void checkUmemIntegrity(const char* function, int line, uint64_t offset, const std::set<UmemEntryStatus::Status>& validStatuses, UmemEntryStatus::Status newStatus)
-{
- auto umems = s_umems.lock();
- if (validStatuses.count(umems->at(offset).status) == 0) {
- std::cerr << "UMEM integrity check failed at " << function << ": " << line << ": status is " << static_cast<int>(umems->at(offset).status) << ", expected: ";
- for (const auto status : validStatuses) {
- std::cerr << static_cast<int>(status) << " ";
- }
- std::cerr << std::endl;
- abort();
- }
- (*umems)[offset].status = newStatus;
-}
-}
-#endif /* DEBUG_UMEM */
-
-constexpr bool XskSocket::isPowOfTwo(uint32_t value) noexcept
-{
- return value != 0 && (value & (value - 1)) == 0;
-}
-
-int XskSocket::firstTimeout()
-{
- if (waitForDelay.empty()) {
- return -1;
- }
- timespec now{};
- gettime(&now);
- const auto& firstTime = waitForDelay.top().getSendTime();
- const auto res = timeDifference(now, firstTime);
- if (res <= 0) {
- return 0;
- }
- return res;
-}
-
-XskSocket::XskSocket(size_t frameNum_, std::string ifName_, uint32_t queue_id, const std::string& xskMapPath) :
- frameNum(frameNum_), ifName(std::move(ifName_)), socket(nullptr, xsk_socket__delete), sharedEmptyFrameOffset(std::make_shared<LockGuarded<vector<uint64_t>>>())
-{
- if (!isPowOfTwo(frameNum_) || !isPowOfTwo(frameSize)
- || !isPowOfTwo(fqCapacity) || !isPowOfTwo(cqCapacity) || !isPowOfTwo(rxCapacity) || !isPowOfTwo(txCapacity)) {
- throw std::runtime_error("The number of frame , the size of frame and the capacity of rings must is a pow of 2");
- }
- getMACFromIfName();
-
- memset(&cq, 0, sizeof(cq));
- memset(&fq, 0, sizeof(fq));
- memset(&tx, 0, sizeof(tx));
- memset(&rx, 0, sizeof(rx));
-
- xsk_umem_config umemCfg{};
- umemCfg.fill_size = fqCapacity;
- umemCfg.comp_size = cqCapacity;
- umemCfg.frame_size = frameSize;
- umemCfg.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
- umemCfg.flags = 0;
- umem.umemInit(frameNum_ * frameSize, &cq, &fq, &umemCfg);
-
- {
- xsk_socket_config socketCfg{};
- socketCfg.rx_size = rxCapacity;
- socketCfg.tx_size = txCapacity;
- socketCfg.bind_flags = XDP_USE_NEED_WAKEUP;
- socketCfg.xdp_flags = XDP_FLAGS_SKB_MODE;
- socketCfg.libxdp_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
- xsk_socket* tmp = nullptr;
- auto ret = xsk_socket__create(&tmp, ifName.c_str(), queue_id, umem.umem, &rx, &tx, &socketCfg);
- if (ret != 0) {
- throw std::runtime_error("Error creating a xsk socket of if_name " + ifName + ": " + stringerror(ret));
- }
- socket = std::unique_ptr<xsk_socket, decltype(&xsk_socket__delete)>(tmp, xsk_socket__delete);
- }
-
- uniqueEmptyFrameOffset.reserve(frameNum);
- {
- for (uint64_t idx = 0; idx < frameNum; idx++) {
- uniqueEmptyFrameOffset.push_back(idx * frameSize + XDP_PACKET_HEADROOM);
-#ifdef DEBUG_UMEM
- {
- auto umems = s_umems.lock();
- (*umems)[idx * frameSize + XDP_PACKET_HEADROOM] = UmemEntryStatus();
- }
-#endif /* DEBUG_UMEM */
- }
- }
-
- fillFq(fqCapacity);
-
- const auto xskfd = xskFd();
- fds.push_back(pollfd{
- .fd = xskfd,
- .events = POLLIN,
- .revents = 0});
-
- const auto xskMapFd = FDWrapper(bpf_obj_get(xskMapPath.c_str()));
-
- if (xskMapFd.getHandle() < 0) {
- throw std::runtime_error("Error getting BPF map from path '" + xskMapPath + "'");
- }
-
- auto ret = bpf_map_update_elem(xskMapFd.getHandle(), &queue_id, &xskfd, 0);
- if (ret != 0) {
- throw std::runtime_error("Error inserting into xsk_map '" + xskMapPath + "': " + std::to_string(ret));
- }
-}
-
-// see xdp.h in contrib/
-struct IPv4AndPort
-{
- uint32_t addr;
- uint16_t port;
-};
-struct IPv6AndPort
-{
- struct in6_addr addr;
- uint16_t port;
-};
-
-static FDWrapper getDestinationMap(const std::string& mapPath)
-{
- auto destMapFd = FDWrapper(bpf_obj_get(mapPath.c_str()));
- if (destMapFd.getHandle() < 0) {
- throw std::runtime_error("Error getting the XSK destination addresses map path '" + mapPath + "'");
- }
- return destMapFd;
-}
-
-void XskSocket::clearDestinationMap(const std::string& mapPath, bool isV6)
-{
- auto destMapFd = getDestinationMap(mapPath);
- if (!isV6) {
- IPv4AndPort prevKey{};
- IPv4AndPort key{};
- while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
- bpf_map_delete_elem(destMapFd.getHandle(), &key);
- prevKey = key;
- }
- }
- else {
- IPv6AndPort prevKey{};
- IPv6AndPort key{};
- while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
- bpf_map_delete_elem(destMapFd.getHandle(), &key);
- prevKey = key;
- }
- }
-}
-
-void XskSocket::addDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
-{
- auto destMapFd = getDestinationMap(mapPath);
- bool value = true;
- if (destination.isIPv4()) {
- IPv4AndPort key{};
- key.addr = destination.sin4.sin_addr.s_addr;
- key.port = destination.sin4.sin_port;
- auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
- if (ret != 0) {
- throw std::runtime_error("Error inserting into xsk_map '" + mapPath + "': " + std::to_string(ret));
- }
- }
- else {
- IPv6AndPort key{};
- key.addr = destination.sin6.sin6_addr;
- key.port = destination.sin6.sin6_port;
- auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
- if (ret != 0) {
- throw std::runtime_error("Error inserting into XSK destination addresses map '" + mapPath + "': " + std::to_string(ret));
- }
- }
-}
-
-void XskSocket::removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
-{
- auto destMapFd = getDestinationMap(mapPath);
- if (destination.isIPv4()) {
- IPv4AndPort key{};
- key.addr = destination.sin4.sin_addr.s_addr;
- key.port = destination.sin4.sin_port;
- bpf_map_delete_elem(destMapFd.getHandle(), &key);
- }
- else {
- IPv6AndPort key{};
- key.addr = destination.sin6.sin6_addr;
- key.port = destination.sin6.sin6_port;
- bpf_map_delete_elem(destMapFd.getHandle(), &key);
- }
-}
-
-void XskSocket::fillFq(uint32_t fillSize) noexcept
-{
- {
- // if we have less than holdThreshold frames in the shared queue (which might be an issue
- // when the XskWorker needs empty frames), move frames from the unique container into the
- // shared one. This might not be optimal right now.
- auto frames = sharedEmptyFrameOffset->lock();
- if (frames->size() < holdThreshold) {
- const auto moveSize = std::min(holdThreshold - frames->size(), uniqueEmptyFrameOffset.size());
- if (moveSize > 0) {
- // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
- frames->insert(frames->end(), std::make_move_iterator(uniqueEmptyFrameOffset.end() - moveSize), std::make_move_iterator(uniqueEmptyFrameOffset.end()));
- uniqueEmptyFrameOffset.resize(uniqueEmptyFrameOffset.size() - moveSize);
- }
- }
- }
-
- if (uniqueEmptyFrameOffset.size() < fillSize) {
- return;
- }
-
- uint32_t idx{0};
- auto toFill = xsk_ring_prod__reserve(&fq, fillSize, &idx);
- if (toFill == 0) {
- return;
- }
- uint32_t processed = 0;
- for (; processed < toFill; processed++) {
- *xsk_ring_prod__fill_addr(&fq, idx++) = uniqueEmptyFrameOffset.back();
-#ifdef DEBUG_UMEM
- checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Free}, UmemEntryStatus::Status::FillQueue);
-#endif /* DEBUG_UMEM */
- uniqueEmptyFrameOffset.pop_back();
- }
-
- xsk_ring_prod__submit(&fq, processed);
-}
-
-int XskSocket::wait(int timeout)
-{
- auto waitAtMost = std::min(timeout, firstTimeout());
- return poll(fds.data(), fds.size(), waitAtMost);
-}
-
-[[nodiscard]] uint64_t XskSocket::frameOffset(const XskPacket& packet) const noexcept
-{
- return packet.getFrameOffsetFrom(umem.bufBase);
-}
-
-[[nodiscard]] int XskSocket::xskFd() const noexcept
-{
- return xsk_socket__fd(socket.get());
-}
-
-void XskSocket::send(std::vector<XskPacket>& packets)
-{
- while (!packets.empty()) {
- auto packetSize = packets.size();
- if (packetSize > std::numeric_limits<uint32_t>::max()) {
- packetSize = std::numeric_limits<uint32_t>::max();
- }
- size_t toSend = std::min(static_cast<uint32_t>(packetSize), txCapacity);
- uint32_t idx{0};
- auto toFill = xsk_ring_prod__reserve(&tx, toSend, &idx);
- if (toFill == 0) {
- return;
- }
-
- size_t queued = 0;
- for (const auto& packet : packets) {
- if (queued == toFill) {
- break;
- }
- *xsk_ring_prod__tx_desc(&tx, idx++) = {
- .addr = frameOffset(packet),
- .len = packet.getFrameLen(),
- .options = 0};
-#ifdef DEBUG_UMEM
- checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, frameOffset(packet), {UmemEntryStatus::Status::Free, UmemEntryStatus::Status::Received}, UmemEntryStatus::Status::TXQueue);
-#endif /* DEBUG_UMEM */
- queued++;
- }
- xsk_ring_prod__submit(&tx, toFill);
- packets.erase(packets.begin(), packets.begin() + toFill);
- }
-}
-
-std::vector<XskPacket> XskSocket::recv(uint32_t recvSizeMax, uint32_t* failedCount)
-{
- uint32_t idx{0};
- std::vector<XskPacket> res;
- // how many descriptors to packets have been filled
- const auto recvSize = xsk_ring_cons__peek(&rx, recvSizeMax, &idx);
- if (recvSize == 0) {
- return res;
- }
-
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- const auto baseAddr = reinterpret_cast<uint64_t>(umem.bufBase);
- uint32_t failed = 0;
- uint32_t processed = 0;
- res.reserve(recvSize);
- for (; processed < recvSize; processed++) {
- try {
- const auto* desc = xsk_ring_cons__rx_desc(&rx, idx++);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr)
- XskPacket packet = XskPacket(reinterpret_cast<uint8_t*>(desc->addr + baseAddr), desc->len, frameSize);
-#ifdef DEBUG_UMEM
- checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, frameOffset(packet), {UmemEntryStatus::Status::Free, UmemEntryStatus::Status::FillQueue}, UmemEntryStatus::Status::Received);
-#endif /* DEBUG_UMEM */
-
- if (!packet.parse(false)) {
- ++failed;
- markAsFree(packet);
- }
- else {
- res.push_back(packet);
- }
- }
- catch (const std::exception& exp) {
- std::cerr << "Exception while processing the XSK RX queue: " << exp.what() << std::endl;
- break;
- }
- catch (...) {
- std::cerr << "Exception while processing the XSK RX queue" << std::endl;
- break;
- }
- }
-
- // this releases the descriptor, but not the packet (umem entries)
- // which will only be made available again when pushed into the fill
- // queue
- xsk_ring_cons__release(&rx, processed);
- if (failedCount != nullptr) {
- *failedCount = failed;
- }
-
- return res;
-}
-
-void XskSocket::pickUpReadyPacket(std::vector<XskPacket>& packets)
-{
- timespec now{};
- gettime(&now);
- while (!waitForDelay.empty() && timeDifference(now, waitForDelay.top().getSendTime()) <= 0) {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
- auto& top = const_cast<XskPacket&>(waitForDelay.top());
- packets.push_back(top);
- waitForDelay.pop();
- }
-}
-
-void XskSocket::recycle(size_t size) noexcept
-{
- uint32_t idx{0};
- const auto completeSize = xsk_ring_cons__peek(&cq, size, &idx);
- if (completeSize == 0) {
- return;
- }
- uniqueEmptyFrameOffset.reserve(uniqueEmptyFrameOffset.size() + completeSize);
- uint32_t processed = 0;
- for (; processed < completeSize; ++processed) {
- uniqueEmptyFrameOffset.push_back(*xsk_ring_cons__comp_addr(&cq, idx++));
-#ifdef DEBUG_UMEM
- checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
-#endif /* DEBUG_UMEM */
- }
- xsk_ring_cons__release(&cq, processed);
-}
-
-void XskSocket::XskUmem::umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config)
-{
- size = memSize;
- bufBase = static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
- if (bufBase == MAP_FAILED) {
- throw std::runtime_error("mmap failed");
- }
- auto ret = xsk_umem__create(&umem, bufBase, size, fillQueue, completionQueue, config);
- if (ret != 0) {
- munmap(bufBase, size);
- throw std::runtime_error("Error creating a umem of size " + std::to_string(size) + ": " + stringerror(ret));
- }
-}
-
-std::string XskSocket::getMetrics() const
-{
- xdp_statistics stats{};
- socklen_t optlen = sizeof(stats);
- int err = getsockopt(xskFd(), SOL_XDP, XDP_STATISTICS, &stats, &optlen);
- if (err != 0) {
- return "";
- }
- if (optlen != sizeof(struct xdp_statistics)) {
- return "";
- }
-
- ostringstream ret;
- ret << "RX dropped: " << std::to_string(stats.rx_dropped) << std::endl;
- ret << "RX invalid descs: " << std::to_string(stats.rx_invalid_descs) << std::endl;
- ret << "TX invalid descs: " << std::to_string(stats.tx_invalid_descs) << std::endl;
- ret << "RX ring full: " << std::to_string(stats.rx_ring_full) << std::endl;
- ret << "RX fill ring empty descs: " << std::to_string(stats.rx_fill_ring_empty_descs) << std::endl;
- ret << "TX ring empty descs: " << std::to_string(stats.tx_ring_empty_descs) << std::endl;
- return ret.str();
-}
-
-[[nodiscard]] std::string XskSocket::getXDPMode() const
-{
-#ifdef HAVE_BPF_XDP_QUERY
- unsigned int itfIdx = if_nametoindex(ifName.c_str());
- if (itfIdx == 0) {
- return "unable to get interface index";
- }
- bpf_xdp_query_opts info{};
- info.sz = sizeof(info);
- int ret = bpf_xdp_query(static_cast<int>(itfIdx), 0, &info);
- if (ret != 0) {
- return {};
- }
- switch (info.attach_mode) {
- case XDP_ATTACHED_DRV:
- case XDP_ATTACHED_HW:
- return "native";
- case XDP_ATTACHED_SKB:
- return "emulated";
- default:
- return "unknown";
- }
-#else /* HAVE_BPF_XDP_QUERY */
- return "undetected";
-#endif /* HAVE_BPF_XDP_QUERY */
-}
-
-void XskSocket::markAsFree(const XskPacket& packet)
-{
- auto offset = frameOffset(packet);
-#ifdef DEBUG_UMEM
- checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
-#endif /* DEBUG_UMEM */
-
- uniqueEmptyFrameOffset.push_back(offset);
-}
-
-XskSocket::XskUmem::~XskUmem()
-{
- if (umem != nullptr) {
- xsk_umem__delete(umem);
- }
- if (bufBase != nullptr) {
- munmap(bufBase, size);
- }
-}
-
-[[nodiscard]] size_t XskPacket::getL4HeaderOffset() const noexcept
-{
- return sizeof(ethhdr) + (v6 ? (sizeof(ipv6hdr)) : sizeof(iphdr));
-}
-
-[[nodiscard]] size_t XskPacket::getDataOffset() const noexcept
-{
- return getL4HeaderOffset() + sizeof(udphdr);
-}
-
-[[nodiscard]] size_t XskPacket::getDataSize() const noexcept
-{
- return frameLength - getDataOffset();
-}
-
-[[nodiscard]] ethhdr XskPacket::getEthernetHeader() const noexcept
-{
- ethhdr ethHeader{};
- if (frameLength >= sizeof(ethHeader)) {
- memcpy(ðHeader, frame, sizeof(ethHeader));
- }
- return ethHeader;
-}
-
-void XskPacket::setEthernetHeader(const ethhdr& ethHeader) noexcept
-{
- if (frameLength < sizeof(ethHeader)) {
- frameLength = sizeof(ethHeader);
- }
- memcpy(frame, ðHeader, sizeof(ethHeader));
-}
-
-[[nodiscard]] iphdr XskPacket::getIPv4Header() const noexcept
-{
- iphdr ipv4Header{};
- assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv4Header)));
- assert(!v6);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(&ipv4Header, frame + sizeof(ethhdr), sizeof(ipv4Header));
- return ipv4Header;
-}
-
-void XskPacket::setIPv4Header(const iphdr& ipv4Header) noexcept
-{
- assert(frameLength >= (sizeof(ethhdr) + sizeof(iphdr)));
- assert(!v6);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(frame + sizeof(ethhdr), &ipv4Header, sizeof(ipv4Header));
-}
-
-[[nodiscard]] ipv6hdr XskPacket::getIPv6Header() const noexcept
-{
- ipv6hdr ipv6Header{};
- assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
- assert(v6);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(&ipv6Header, frame + sizeof(ethhdr), sizeof(ipv6Header));
- return ipv6Header;
-}
-
-void XskPacket::setIPv6Header(const ipv6hdr& ipv6Header) noexcept
-{
- assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
- assert(v6);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(frame + sizeof(ethhdr), &ipv6Header, sizeof(ipv6Header));
-}
-
-[[nodiscard]] udphdr XskPacket::getUDPHeader() const noexcept
-{
- udphdr udpHeader{};
- assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(&udpHeader, frame + getL4HeaderOffset(), sizeof(udpHeader));
- return udpHeader;
-}
-
-void XskPacket::setUDPHeader(const udphdr& udpHeader) noexcept
-{
- assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(frame + getL4HeaderOffset(), &udpHeader, sizeof(udpHeader));
-}
-
-bool XskPacket::parse(bool fromSetHeader)
-{
- if (frameLength <= sizeof(ethhdr)) {
- return false;
- }
-
- auto ethHeader = getEthernetHeader();
- uint8_t l4Protocol{0};
- if (ethHeader.h_proto == htons(ETH_P_IP)) {
- if (frameLength < (sizeof(ethhdr) + sizeof(iphdr) + sizeof(udphdr))) {
- return false;
- }
- v6 = false;
- auto ipHeader = getIPv4Header();
- if (ipHeader.ihl != (static_cast<uint8_t>(sizeof(iphdr) / 4))) {
- // ip options is not supported now!
- return false;
- }
- // check ip.check == ipv4Checksum() is not needed!
- // We check it in BPF program
- // we don't, actually.
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- from = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- to = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
- l4Protocol = ipHeader.protocol;
- if (!fromSetHeader && (frameLength - sizeof(ethhdr)) != ntohs(ipHeader.tot_len)) {
- // too small, or too large (trailing data), go away
- return false;
- }
- }
- else if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
- if (frameLength < (sizeof(ethhdr) + sizeof(ipv6hdr) + sizeof(udphdr))) {
- return false;
- }
- v6 = true;
- auto ipHeader = getIPv6Header();
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- from = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- to = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
- l4Protocol = ipHeader.nexthdr;
- if (!fromSetHeader && (frameLength - (sizeof(ethhdr) + sizeof(ipv6hdr))) != ntohs(ipHeader.payload_len)) {
- return false;
- }
- }
- else {
- return false;
- }
-
- if (l4Protocol != IPPROTO_UDP) {
- return false;
- }
-
- // check udp.check == ipv4Checksum() is not needed!
- // We check it in BPF program
- // we don't, actually.
- auto udpHeader = getUDPHeader();
- if (!fromSetHeader) {
- // Because of XskPacket::setHeader
- if (getDataOffset() > frameLength) {
- return false;
- }
-
- if (getDataSize() + sizeof(udphdr) != ntohs(udpHeader.len)) {
- return false;
- }
- }
-
- from.setPort(ntohs(udpHeader.source));
- to.setPort(ntohs(udpHeader.dest));
- return true;
-}
-
-uint32_t XskPacket::getDataLen() const noexcept
-{
- return getDataSize();
-}
-
-uint32_t XskPacket::getFrameLen() const noexcept
-{
- return frameLength;
-}
-
-size_t XskPacket::getCapacity() const noexcept
-{
- return frameSize;
-}
-
-void XskPacket::changeDirectAndUpdateChecksum() noexcept
-{
- auto ethHeader = getEthernetHeader();
- {
- std::array<uint8_t, ETH_ALEN> tmp{};
- static_assert(tmp.size() == sizeof(ethHeader.h_dest), "Size Error");
- static_assert(tmp.size() == sizeof(ethHeader.h_source), "Size Error");
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- memcpy(tmp.data(), ethHeader.h_dest, tmp.size());
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- memcpy(ethHeader.h_dest, ethHeader.h_source, tmp.size());
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- memcpy(ethHeader.h_source, tmp.data(), tmp.size());
- }
- if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
- // IPV6
- auto ipv6 = getIPv6Header();
- std::swap(ipv6.daddr, ipv6.saddr);
- assert(ipv6.nexthdr == IPPROTO_UDP);
-
- auto udp = getUDPHeader();
- std::swap(udp.dest, udp.source);
- udp.len = htons(getDataSize() + sizeof(udp));
- udp.check = 0;
- /* needed to get the correct checksum */
- setIPv6Header(ipv6);
- setUDPHeader(udp);
- udp.check = tcp_udp_v6_checksum(&ipv6);
- rewriteIpv6Header(&ipv6, getFrameLen());
- setIPv6Header(ipv6);
- setUDPHeader(udp);
- }
- else {
- // IPV4
- auto ipv4 = getIPv4Header();
- std::swap(ipv4.daddr, ipv4.saddr);
- assert(ipv4.protocol == IPPROTO_UDP);
-
- auto udp = getUDPHeader();
- std::swap(udp.dest, udp.source);
- udp.len = htons(getDataSize() + sizeof(udp));
- udp.check = 0;
- /* needed to get the correct checksum */
- setIPv4Header(ipv4);
- setUDPHeader(udp);
- udp.check = tcp_udp_v4_checksum(&ipv4);
- rewriteIpv4Header(&ipv4, getFrameLen());
- setIPv4Header(ipv4);
- setUDPHeader(udp);
- }
- setEthernetHeader(ethHeader);
-}
-
-void XskPacket::rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept
-{
- ipv4header->version = 4;
- ipv4header->ihl = sizeof(iphdr) / 4;
- ipv4header->tos = 0;
- ipv4header->tot_len = htons(frameLen - sizeof(ethhdr));
- ipv4header->id = 0;
- ipv4header->frag_off = 0;
- ipv4header->ttl = DefaultTTL;
- ipv4header->check = 0;
- ipv4header->check = ipv4Checksum(ipv4header);
-}
-
-void XskPacket::rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept
-{
- ipv6header->version = 6;
- ipv6header->priority = 0;
- ipv6header->payload_len = htons(frameLen - sizeof(ethhdr) - sizeof(ipv6hdr));
- ipv6header->hop_limit = DefaultTTL;
- memset(&ipv6header->flow_lbl, 0, sizeof(ipv6header->flow_lbl));
-}
-
-bool XskPacket::isIPV6() const noexcept
-{
- return v6;
-}
-
-XskPacket::XskPacket(uint8_t* frame_, size_t dataSize, size_t frameSize_) :
- frame(frame_), frameLength(dataSize), frameSize(frameSize_ - XDP_PACKET_HEADROOM)
-{
-}
-
-PacketBuffer XskPacket::clonePacketBuffer() const
-{
- const auto size = getDataSize();
- PacketBuffer tmp(size);
- if (size > 0) {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(tmp.data(), frame + getDataOffset(), size);
- }
- return tmp;
-}
-
-bool XskPacket::setPayload(const PacketBuffer& buf)
-{
- const auto bufSize = buf.size();
- const auto currentCapacity = getCapacity();
- if (bufSize == 0 || bufSize > currentCapacity) {
- return false;
- }
- flags |= UPDATE;
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(frame + getDataOffset(), buf.data(), bufSize);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- frameLength = getDataOffset() + bufSize;
- return true;
-}
-
-void XskPacket::addDelay(const int relativeMilliseconds) noexcept
-{
- gettime(&sendTime);
- sendTime.tv_nsec += static_cast<int64_t>(relativeMilliseconds) * 1000000L;
- sendTime.tv_sec += sendTime.tv_nsec / 1000000000L;
- sendTime.tv_nsec %= 1000000000L;
-}
-
-bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept
-{
- return lhs.getSendTime() < rhs.getSendTime();
-}
-
-const ComboAddress& XskPacket::getFromAddr() const noexcept
-{
- return from;
-}
-
-const ComboAddress& XskPacket::getToAddr() const noexcept
-{
- return to;
-}
-
-void XskWorker::notify(int desc)
-{
- uint64_t value = 1;
- ssize_t res = 0;
- while ((res = write(desc, &value, sizeof(value))) == EINTR) {
- }
- if (res != sizeof(value)) {
- throw runtime_error("Unable Wake Up XskSocket Failed");
- }
-}
-
-XskWorker::XskWorker() :
- workerWaker(createEventfd()), xskSocketWaker(createEventfd())
-{
-}
-
-void XskWorker::pushToProcessingQueue(XskPacket& packet)
-{
-#if defined(__SANITIZE_THREAD__)
- if (!incomingPacketsQueue.lock()->push(packet)) {
-#else
- if (!incomingPacketsQueue.push(packet)) {
-#endif
- markAsFree(packet);
- }
-}
-
-void XskWorker::pushToSendQueue(XskPacket& packet)
-{
-#if defined(__SANITIZE_THREAD__)
- if (!outgoingPacketsQueue.lock()->push(packet)) {
-#else
- if (!outgoingPacketsQueue.push(packet)) {
-#endif
- markAsFree(packet);
- }
-}
-
-const void* XskPacket::getPayloadData() const
-{
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- return frame + getDataOffset();
-}
-
-void XskPacket::setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept
-{
- auto ethHeader = getEthernetHeader();
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- memcpy(ethHeader.h_dest, toMAC.data(), toMAC.size());
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- memcpy(ethHeader.h_source, fromMAC.data(), fromMAC.size());
- setEthernetHeader(ethHeader);
- to = to_;
- from = from_;
- v6 = !to.isIPv4();
- flags = 0;
-}
-
-void XskPacket::rewrite() noexcept
-{
- flags |= REWRITE;
- auto ethHeader = getEthernetHeader();
- if (!v6) {
- ethHeader.h_proto = htons(ETH_P_IP);
-
- auto ipHeader = getIPv4Header();
- ipHeader.daddr = to.sin4.sin_addr.s_addr;
- ipHeader.saddr = from.sin4.sin_addr.s_addr;
-
- auto udpHeader = getUDPHeader();
- ipHeader.protocol = IPPROTO_UDP;
- udpHeader.source = from.sin4.sin_port;
- udpHeader.dest = to.sin4.sin_port;
- udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
- udpHeader.check = 0;
- /* needed to get the correct checksum */
- setIPv4Header(ipHeader);
- setUDPHeader(udpHeader);
- udpHeader.check = tcp_udp_v4_checksum(&ipHeader);
- rewriteIpv4Header(&ipHeader, getFrameLen());
- setIPv4Header(ipHeader);
- setUDPHeader(udpHeader);
- }
- else {
- ethHeader.h_proto = htons(ETH_P_IPV6);
-
- auto ipHeader = getIPv6Header();
- memcpy(&ipHeader.daddr, &to.sin6.sin6_addr, sizeof(ipHeader.daddr));
- memcpy(&ipHeader.saddr, &from.sin6.sin6_addr, sizeof(ipHeader.saddr));
-
- auto udpHeader = getUDPHeader();
- ipHeader.nexthdr = IPPROTO_UDP;
- udpHeader.source = from.sin6.sin6_port;
- udpHeader.dest = to.sin6.sin6_port;
- udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
- udpHeader.check = 0;
- /* needed to get the correct checksum */
- setIPv6Header(ipHeader);
- setUDPHeader(udpHeader);
- udpHeader.check = tcp_udp_v6_checksum(&ipHeader);
- setIPv6Header(ipHeader);
- setUDPHeader(udpHeader);
- }
-
- setEthernetHeader(ethHeader);
-}
-
-[[nodiscard]] __be16 XskPacket::ipv4Checksum(const struct iphdr* ipHeader) noexcept
-{
- auto partial = ip_checksum_partial(ipHeader, sizeof(iphdr), 0);
- return ip_checksum_fold(partial);
-}
-
-[[nodiscard]] __be16 XskPacket::tcp_udp_v4_checksum(const struct iphdr* ipHeader) const noexcept
-{
- // ip options is not supported !!!
- const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
- auto sum = tcp_udp_v4_header_checksum_partial(ipHeader->saddr, ipHeader->daddr, ipHeader->protocol, l4Length);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
- return ip_checksum_fold(sum);
-}
-
-[[nodiscard]] __be16 XskPacket::tcp_udp_v6_checksum(const struct ipv6hdr* ipv6) const noexcept
-{
- const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
- uint64_t sum = tcp_udp_v6_header_checksum_partial(&ipv6->saddr, &ipv6->daddr, ipv6->nexthdr, l4Length);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
- return ip_checksum_fold(sum);
-}
-
-[[nodiscard]] uint64_t XskPacket::ip_checksum_partial(const void* ptr, const size_t len, uint64_t sum) noexcept
-{
- size_t position{0};
- /* Main loop: 32 bits at a time */
- for (position = 0; position < len; position += sizeof(uint32_t)) {
- uint32_t value{};
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
- sum += value;
- }
-
- /* Handle un-32bit-aligned trailing bytes */
- if ((len - position) >= 2) {
- uint16_t value{};
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
- sum += value;
- position += sizeof(value);
- }
-
- if ((len - position) > 0) {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- const auto* ptr8 = static_cast<const uint8_t*>(ptr) + position;
- sum += ntohs(*ptr8 << 8); /* RFC says pad last byte */
- }
-
- return sum;
-}
-
-[[nodiscard]] __be16 XskPacket::ip_checksum_fold(uint64_t sum) noexcept
-{
- while ((sum & ~0xffffffffULL) != 0U) {
- sum = (sum >> 32) + (sum & 0xffffffffULL);
- }
- while ((sum & 0xffff0000ULL) != 0U) {
- sum = (sum >> 16) + (sum & 0xffffULL);
- }
-
- return static_cast<__be16>(~sum);
-}
-
-#ifndef __packed
-#define packed_attribute __attribute__((packed))
-#else
-#define packed_attribute __packed
-#endif
-
-// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
-[[nodiscard]] uint64_t XskPacket::tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept
-{
- struct header
- {
- __be32 src_ip;
- __be32 dst_ip;
- __uint8_t mbz;
- __uint8_t protocol;
- __be16 length;
- };
- /* The IPv4 pseudo-header is defined in RFC 793, Section 3.1. */
- struct ipv4_pseudo_header_t
- {
- /* We use a union here to avoid aliasing issues with gcc -O2 */
- union
- {
- header packed_attribute fields;
- // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
- uint32_t words[3];
- };
- };
- ipv4_pseudo_header_t pseudo_header{};
- static_assert(sizeof(pseudo_header) == 12, "IPv4 pseudo-header size is incorrect");
-
- /* Fill in the pseudo-header. */
- pseudo_header.fields.src_ip = src_ip;
- pseudo_header.fields.dst_ip = dst_ip;
- pseudo_header.fields.mbz = 0;
- pseudo_header.fields.protocol = protocol;
- pseudo_header.fields.length = htons(len);
- return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
-}
-
-[[nodiscard]] uint64_t XskPacket::tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept
-{
- struct header
- {
- struct in6_addr src_ip;
- struct in6_addr dst_ip;
- __be32 length;
- // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
- __uint8_t mbz[3];
- __uint8_t next_header;
- };
- /* The IPv6 pseudo-header is defined in RFC 2460, Section 8.1. */
- struct ipv6_pseudo_header_t
- {
- /* We use a union here to avoid aliasing issues with gcc -O2 */
- union
- {
- header packed_attribute fields;
- // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
- uint32_t words[10];
- };
- };
- ipv6_pseudo_header_t pseudo_header{};
- static_assert(sizeof(pseudo_header) == 40, "IPv6 pseudo-header size is incorrect");
-
- /* Fill in the pseudo-header. */
- pseudo_header.fields.src_ip = *src_ip;
- pseudo_header.fields.dst_ip = *dst_ip;
- pseudo_header.fields.length = htonl(len);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- memset(pseudo_header.fields.mbz, 0, sizeof(pseudo_header.fields.mbz));
- pseudo_header.fields.next_header = protocol;
- return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
-}
-
-void XskPacket::setHeader(PacketBuffer& buf)
-{
- memcpy(frame, buf.data(), buf.size());
- frameLength = buf.size();
- buf.clear();
- flags = 0;
- if (!parse(true)) {
- throw std::runtime_error("Error setting the XSK frame header");
- }
-}
-
-PacketBuffer XskPacket::cloneHeaderToPacketBuffer() const
-{
- const auto size = getFrameLen() - getDataSize();
- PacketBuffer tmp(size);
- memcpy(tmp.data(), frame, size);
- return tmp;
-}
-
-int XskWorker::createEventfd()
-{
- auto desc = ::eventfd(0, EFD_CLOEXEC);
- if (desc < 0) {
- throw runtime_error("Unable create eventfd");
- }
- return desc;
-}
-
-void XskWorker::waitForXskSocket() const noexcept
-{
- uint64_t value = read(workerWaker, &value, sizeof(value));
-}
-
-void XskWorker::notifyXskSocket() const
-{
- notify(xskSocketWaker);
-}
-
-std::shared_ptr<XskWorker> XskWorker::create()
-{
- return std::make_shared<XskWorker>();
-}
-
-void XskSocket::addWorker(std::shared_ptr<XskWorker> worker)
-{
- const auto socketWaker = worker->xskSocketWaker.getHandle();
- worker->umemBufBase = umem.bufBase;
- d_workers.insert({socketWaker, std::move(worker)});
- fds.push_back(pollfd{
- .fd = socketWaker,
- .events = POLLIN,
- .revents = 0});
-};
-
-void XskSocket::addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest)
-{
- d_workerRoutes.lock()->insert({dest, worker});
-}
-
-void XskSocket::removeWorkerRoute(const ComboAddress& dest)
-{
- d_workerRoutes.lock()->erase(dest);
-}
-
-uint64_t XskWorker::frameOffset(const XskPacket& packet) const noexcept
-{
- return packet.getFrameOffsetFrom(umemBufBase);
-}
-
-void XskWorker::notifyWorker() const
-{
- notify(workerWaker);
-}
-
-void XskSocket::getMACFromIfName()
-{
- ifreq ifr{};
- auto desc = FDWrapper(::socket(AF_INET, SOCK_DGRAM, 0));
- if (desc < 0) {
- throw std::runtime_error("Error creating a socket to get the MAC address of interface " + ifName);
- }
-
- if (ifName.size() >= IFNAMSIZ) {
- throw std::runtime_error("Unable to get MAC address for interface " + ifName + ": name too long");
- }
-
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- strncpy(ifr.ifr_name, ifName.c_str(), ifName.length() + 1);
- if (ioctl(desc.getHandle(), SIOCGIFHWADDR, &ifr) < 0 || ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
- throw std::runtime_error("Error getting MAC address for interface " + ifName);
- }
- static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= std::tuple_size<decltype(source)>{}, "The size of an ARPHRD_ETHER MAC address is smaller than expected");
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
- memcpy(source.data(), ifr.ifr_hwaddr.sa_data, source.size());
-}
-
-[[nodiscard]] int XskSocket::timeDifference(const timespec& lhs, const timespec& rhs) noexcept
-{
- const auto res = lhs.tv_sec * 1000 + lhs.tv_nsec / 1000000L - (rhs.tv_sec * 1000 + rhs.tv_nsec / 1000000L);
- return static_cast<int>(res);
-}
-
-void XskWorker::cleanWorkerNotification() const noexcept
-{
- uint64_t value = read(xskSocketWaker, &value, sizeof(value));
-}
-
-void XskWorker::cleanSocketNotification() const noexcept
-{
- uint64_t value = read(workerWaker, &value, sizeof(value));
-}
-
-std::vector<pollfd> getPollFdsForWorker(XskWorker& info)
-{
- std::vector<pollfd> fds;
- int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
- if (timerfd < 0) {
- throw std::runtime_error("create_timerfd failed");
- }
- fds.push_back(pollfd{
- .fd = info.workerWaker,
- .events = POLLIN,
- .revents = 0,
- });
- fds.push_back(pollfd{
- .fd = timerfd,
- .events = POLLIN,
- .revents = 0,
- });
- return fds;
-}
-
-void XskWorker::fillUniqueEmptyOffset()
-{
- auto frames = sharedEmptyFrameOffset->lock();
- const auto moveSize = std::min(static_cast<size_t>(32), frames->size());
- if (moveSize > 0) {
- // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
- uniqueEmptyFrameOffset.insert(uniqueEmptyFrameOffset.end(), std::make_move_iterator(frames->end() - moveSize), std::make_move_iterator(frames->end()));
- frames->resize(frames->size() - moveSize);
- }
-}
-
-std::optional<XskPacket> XskWorker::getEmptyFrame()
-{
- if (!uniqueEmptyFrameOffset.empty()) {
- auto offset = uniqueEmptyFrameOffset.back();
- uniqueEmptyFrameOffset.pop_back();
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- return XskPacket(offset + umemBufBase, 0, frameSize);
- }
- fillUniqueEmptyOffset();
- if (!uniqueEmptyFrameOffset.empty()) {
- auto offset = uniqueEmptyFrameOffset.back();
- uniqueEmptyFrameOffset.pop_back();
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- return XskPacket(offset + umemBufBase, 0, frameSize);
- }
- return std::nullopt;
-}
-
-void XskWorker::markAsFree(const XskPacket& packet)
-{
- auto offset = frameOffset(packet);
-#ifdef DEBUG_UMEM
- checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
-#endif /* DEBUG_UMEM */
- uniqueEmptyFrameOffset.push_back(offset);
-}
-
-uint32_t XskPacket::getFlags() const noexcept
-{
- return flags;
-}
-
-void XskPacket::updatePacket() noexcept
-{
- if ((flags & UPDATE) == 0U) {
- return;
- }
- if ((flags & REWRITE) == 0U) {
- changeDirectAndUpdateChecksum();
- }
-}
-#endif /* HAVE_XSK */
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#pragma once
-#include "config.h"
-
-#ifdef HAVE_XSK
-#include <array>
-#include <bits/types/struct_timespec.h>
-#include <boost/lockfree/spsc_queue.hpp>
-#include <boost/multi_index/hashed_index.hpp>
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/member.hpp>
-#include <cstdint>
-#include <memory>
-#include <poll.h>
-#include <queue>
-#include <stdexcept>
-#include <string>
-#include <unistd.h>
-#include <unordered_map>
-#include <vector>
-
-#include <xdp/xsk.h>
-
-#include "iputils.hh"
-#include "lock.hh"
-#include "misc.hh"
-#include "noinitvector.hh"
-
-class XskPacket;
-class XskWorker;
-class XskSocket;
-
-using MACAddr = std::array<uint8_t, 6>;
-
-// We use an XskSocket to manage an AF_XDP Socket corresponding to a NIC queue.
-// The XDP program running in the kernel redirects the data to the XskSocket in userspace.
-// We allocate frames that are placed into the descriptors in the fill queue, allowing the kernel to put incoming packets into the frames and place descriptors into the rx queue.
-// Once we have read the descriptors from the rx queue we release them, but we own the frames.
-// After we are done with the frame, we place them into descriptors of either the fill queue (empty frames) or tx queues (packets to be sent).
-// Once the kernel is done, it places descriptors referencing these frames into the cq where we can recycle them (packets destined to the tx queue or empty frame to the fill queue queue).
-
-// XskSocket routes packets to multiple worker threads registered on XskSocket via XskSocket::addWorker based on the destination port number of the packet.
-// The kernel and the worker thread holding XskWorker will wake up the XskSocket through XskFd and the Eventfd corresponding to each worker thread, respectively.
-
-class XskSocket
-{
- struct XskUmem
- {
- xsk_umem* umem{nullptr};
- uint8_t* bufBase{nullptr};
- size_t size{0};
- void umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config);
- ~XskUmem();
- XskUmem() = default;
- };
- using WorkerContainer = std::unordered_map<int, std::shared_ptr<XskWorker>>;
- WorkerContainer d_workers;
- using WorkerRoutesMap = std::unordered_map<ComboAddress, std::shared_ptr<XskWorker>, ComboAddress::addressPortOnlyHash>;
- // it might be better to move to a StateHolder for performance
- LockGuarded<WorkerRoutesMap> d_workerRoutes;
- // number of frames to keep in sharedEmptyFrameOffset
- static constexpr size_t holdThreshold = 256;
- // number of frames to insert into the fill queue
- static constexpr size_t fillThreshold = 128;
- static constexpr size_t frameSize = 2048;
- // number of entries (frames) in the umem
- const size_t frameNum;
- // responses that have been delayed
- std::priority_queue<XskPacket> waitForDelay;
- MACAddr source{};
- const std::string ifName;
- // AF_XDP socket then worker waker sockets
- vector<pollfd> fds;
- // list of frames, aka (indexes of) umem entries that can be reused to fill fq,
- // collected from packets that we could not route (unknown destination),
- // could not parse, were dropped during processing (!UPDATE), or
- // simply recycled from cq after being processed by the kernel
- vector<uint64_t> uniqueEmptyFrameOffset;
- // completion ring: queue where sent packets are stored by the kernel
- xsk_ring_cons cq{};
- // rx ring: queue where the incoming packets are stored, read by XskRouter
- xsk_ring_cons rx{};
- // fill ring: queue where umem entries available to be filled (put into rx) are stored
- xsk_ring_prod fq{};
- // tx ring: queue where outgoing packets are stored
- xsk_ring_prod tx{};
- std::unique_ptr<xsk_socket, void (*)(xsk_socket*)> socket;
- XskUmem umem;
-
- static constexpr uint32_t fqCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 4;
- static constexpr uint32_t cqCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 4;
- static constexpr uint32_t rxCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 2;
- static constexpr uint32_t txCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 2;
-
- constexpr static bool isPowOfTwo(uint32_t value) noexcept;
- [[nodiscard]] static int timeDifference(const timespec& lhs, const timespec& rhs) noexcept;
-
- [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
- [[nodiscard]] int firstTimeout();
- void getMACFromIfName();
-
-public:
- static void clearDestinationMap(const std::string& mapPath, bool isV6);
- static void addDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
- static void removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
- static constexpr size_t getFrameSize()
- {
- return frameSize;
- }
- // list of free umem entries that can be reused
- std::shared_ptr<LockGuarded<vector<uint64_t>>> sharedEmptyFrameOffset;
- XskSocket(size_t frameNum, std::string ifName, uint32_t queue_id, const std::string& xskMapPath);
- [[nodiscard]] int xskFd() const noexcept;
- // wait until one event has occurred
- [[nodiscard]] int wait(int timeout);
- // add as many packets as possible to the rx queue for sending */
- void send(std::vector<XskPacket>& packets);
- // look at incoming packets in rx, return them if parsing succeeeded
- [[nodiscard]] std::vector<XskPacket> recv(uint32_t recvSizeMax, uint32_t* failedCount);
- void addWorker(std::shared_ptr<XskWorker> worker);
- void addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest);
- void removeWorkerRoute(const ComboAddress& dest);
- [[nodiscard]] std::string getMetrics() const;
- [[nodiscard]] std::string getXDPMode() const;
- void markAsFree(const XskPacket& packet);
- [[nodiscard]] const std::shared_ptr<XskWorker>& getWorkerByDescriptor(int desc) const
- {
- return d_workers.at(desc);
- }
- [[nodiscard]] std::shared_ptr<XskWorker> getWorkerByDestination(const ComboAddress& destination)
- {
- auto routes = d_workerRoutes.lock();
- auto workerIt = routes->find(destination);
- if (workerIt == routes->end()) {
- return nullptr;
- }
- return workerIt->second;
- }
- [[nodiscard]] const std::vector<pollfd>& getDescriptors() const
- {
- return fds;
- }
- [[nodiscard]] MACAddr getSourceMACAddress() const
- {
- return source;
- }
- [[nodiscard]] const std::string& getInterfaceName() const
- {
- return ifName;
- }
- // pick ups available frames from uniqueEmptyFrameOffset
- // insert entries from uniqueEmptyFrameOffset into fq
- void fillFq(uint32_t fillSize = fillThreshold) noexcept;
- // picks up entries that have been processed (sent) from cq and push them into uniqueEmptyFrameOffset
- void recycle(size_t size) noexcept;
- // look at delayed packets, and send the ones that are ready
- void pickUpReadyPacket(std::vector<XskPacket>& packets);
- void pushDelayed(XskPacket& packet)
- {
- waitForDelay.push(packet);
- }
-};
-
-struct ethhdr;
-struct iphdr;
-struct ipv6hdr;
-struct udphdr;
-
-class XskPacket
-{
-public:
- enum Flags : uint32_t
- {
- UPDATE = 1 << 0,
- DELAY = 1 << 1,
- REWRITE = 1 << 2
- };
-
-private:
- ComboAddress from;
- ComboAddress to;
- timespec sendTime{};
- uint8_t* frame{nullptr};
- size_t frameLength{0};
- size_t frameSize{0};
- uint32_t flags{0};
- bool v6{false};
-
- // You must set ipHeader.check = 0 before calling this method
- [[nodiscard]] static __be16 ipv4Checksum(const struct iphdr*) noexcept;
- [[nodiscard]] static uint64_t ip_checksum_partial(const void* p, size_t len, uint64_t sum) noexcept;
- [[nodiscard]] static __be16 ip_checksum_fold(uint64_t sum) noexcept;
- [[nodiscard]] static uint64_t tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept;
- [[nodiscard]] static uint64_t tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept;
- static void rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept;
- static void rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept;
-
- // You must set l4Header.check = 0 before calling this method
- // ip options is not supported
- [[nodiscard]] __be16 tcp_udp_v4_checksum(const struct iphdr*) const noexcept;
- // You must set l4Header.check = 0 before calling this method
- [[nodiscard]] __be16 tcp_udp_v6_checksum(const struct ipv6hdr*) const noexcept;
- /* offset of the L4 (udphdr) header (after ethhdr and iphdr/ipv6hdr) */
- [[nodiscard]] size_t getL4HeaderOffset() const noexcept;
- /* offset of the data after the UDP header */
- [[nodiscard]] size_t getDataOffset() const noexcept;
- [[nodiscard]] size_t getDataSize() const noexcept;
- [[nodiscard]] ethhdr getEthernetHeader() const noexcept;
- void setEthernetHeader(const ethhdr& ethHeader) noexcept;
- [[nodiscard]] iphdr getIPv4Header() const noexcept;
- void setIPv4Header(const iphdr& ipv4Header) noexcept;
- [[nodiscard]] ipv6hdr getIPv6Header() const noexcept;
- void setIPv6Header(const ipv6hdr& ipv6Header) noexcept;
- [[nodiscard]] udphdr getUDPHeader() const noexcept;
- void setUDPHeader(const udphdr& udpHeader) noexcept;
- void changeDirectAndUpdateChecksum() noexcept;
-
- constexpr static uint8_t DefaultTTL = 64;
-
-public:
- [[nodiscard]] const ComboAddress& getFromAddr() const noexcept;
- [[nodiscard]] const ComboAddress& getToAddr() const noexcept;
- [[nodiscard]] const void* getPayloadData() const;
- [[nodiscard]] bool isIPV6() const noexcept;
- [[nodiscard]] size_t getCapacity() const noexcept;
- [[nodiscard]] uint32_t getDataLen() const noexcept;
- [[nodiscard]] uint32_t getFrameLen() const noexcept;
- [[nodiscard]] PacketBuffer clonePacketBuffer() const;
- [[nodiscard]] PacketBuffer cloneHeaderToPacketBuffer() const;
- void setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept;
- bool setPayload(const PacketBuffer& buf);
- void rewrite() noexcept;
- void setHeader(PacketBuffer& buf);
- XskPacket(uint8_t* frame, size_t dataSize, size_t frameSize);
- void addDelay(int relativeMilliseconds) noexcept;
- void updatePacket() noexcept;
- // parse IP and UDP payloads
- bool parse(bool fromSetHeader);
- [[nodiscard]] uint32_t getFlags() const noexcept;
- [[nodiscard]] timespec getSendTime() const noexcept
- {
- return sendTime;
- }
- [[nodiscard]] uint64_t getFrameOffsetFrom(const uint8_t* base) const noexcept
- {
- return frame - base;
- }
-};
-bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept;
-
-/* g++ defines __SANITIZE_THREAD__
- clang++ supports the nice __has_feature(thread_sanitizer),
- let's merge them */
-#if defined(__has_feature)
-#if __has_feature(thread_sanitizer)
-#define __SANITIZE_THREAD__ 1
-#endif
-#endif
-
-// XskWorker obtains XskPackets of specific ports in the NIC from XskSocket through cq.
-// After finishing processing the packet, XskWorker puts the packet into sq so that XskSocket decides whether to send it through the network card according to XskPacket::flags.
-// XskWorker wakes up XskSocket via xskSocketWaker after putting the packets in sq.
-class XskWorker
-{
-#if defined(__SANITIZE_THREAD__)
- using XskPacketRing = LockGuarded<boost::lockfree::spsc_queue<XskPacket, boost::lockfree::capacity<XSK_RING_CONS__DEFAULT_NUM_DESCS * 2>>>;
-#else
- using XskPacketRing = boost::lockfree::spsc_queue<XskPacket, boost::lockfree::capacity<XSK_RING_CONS__DEFAULT_NUM_DESCS * 2>>;
-#endif
-
-public:
- // queue of packets to be processed by this worker
- XskPacketRing incomingPacketsQueue;
- // queue of packets processed by this worker (to be sent, or discarded)
- XskPacketRing outgoingPacketsQueue;
-
- uint8_t* umemBufBase{nullptr};
- // list of frames that are shared with the XskRouter
- std::shared_ptr<LockGuarded<vector<uint64_t>>> sharedEmptyFrameOffset;
- // list of frames that we own, used to generate new packets (health-check)
- vector<uint64_t> uniqueEmptyFrameOffset;
- const size_t frameSize{XskSocket::getFrameSize()};
- FDWrapper workerWaker;
- FDWrapper xskSocketWaker;
-
- XskWorker();
- static int createEventfd();
- static void notify(int desc);
- static std::shared_ptr<XskWorker> create();
- void pushToProcessingQueue(XskPacket& packet);
- void pushToSendQueue(XskPacket& packet);
- void markAsFree(const XskPacket& packet);
- // notify worker that at least one packet is available for processing
- void notifyWorker() const;
- // notify the router that packets are ready to be sent
- void notifyXskSocket() const;
- void waitForXskSocket() const noexcept;
- void cleanWorkerNotification() const noexcept;
- void cleanSocketNotification() const noexcept;
- [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
- // reap empty umem entry from sharedEmptyFrameOffset into uniqueEmptyFrameOffset
- void fillUniqueEmptyOffset();
- // look for an empty umem entry in uniqueEmptyFrameOffset
- // then sharedEmptyFrameOffset if needed
- std::optional<XskPacket> getEmptyFrame();
-};
-std::vector<pollfd> getPollFdsForWorker(XskWorker& info);
-#else
-class XskSocket
-{
-};
-class XskPacket
-{
-};
-class XskWorker
-{
-};
-
-#endif /* HAVE_XSK */
def test_zone_comment_create(self):
name, payload, zone = self.create_zone()
- rrset = {
+ rrset1 = {
'changetype': 'replace',
'name': name,
'type': 'NS',
}
]
}
- payload = {'rrsets': [rrset]}
+ rrset2 = {
+ 'changetype': 'replace',
+ 'name': name,
+ 'type': 'SOA',
+ 'ttl': 3600,
+ 'comments': [
+ {
+ 'account': 'test3',
+ 'content': 'this should not show up later'
+ }
+ ]
+ }
+ payload = {'rrsets': [rrset1, rrset2]}
r = self.session.patch(
self.url("/api/v1/servers/localhost/zones/" + name),
data=json.dumps(payload),
self.assert_success(r)
# make sure the comments have been set, and that the NS
# records are still present
- data = self.get_zone(name)
+ data = self.get_zone(name, rrset_name=name, rrset_type="NS")
serverset = get_rrset(data, name, 'NS')
print(serverset)
self.assertNotEqual(serverset['records'], [])
self.assertNotEqual(serverset['comments'], [])
# verify that modified_at has been set by pdns
self.assertNotEqual([c for c in serverset['comments']][0]['modified_at'], 0)
+ # verify that unrelated comments do not leak into the result
+ self.assertEqual(get_rrset(data, name, 'SOA'), None)
# verify that TTL is correct (regression test)
self.assertEqual(serverset['ttl'], 3600)
@unittest.skipIf(is_auth_lmdb(), "No comments in LMDB")
def test_zone_comment_out_of_range_modified_at(self):
- # Test if comments on an rrset stay intact if the rrset is replaced
+ # Test if a modified_at outside of the 32 bit range throws an error
name, payload, zone = self.create_zone()
rrset = {
'changetype': 'replace',
@unittest.skipIf(not is_recursor(), "Not applicable")
class RecursorZones(ApiTestCase):
- def create_zone(self, name=None, kind=None, rd=False, servers=None):
+ def create_zone(self, name=None, kind=None, rd=False, servers=None, notify_allowed=False):
if name is None:
name = unique_zone_name()
if servers is None:
'name': name,
'kind': kind,
'servers': servers,
- 'recursion_desired': rd
+ 'recursion_desired': rd,
+ 'notify_allowed': notify_allowed
}
r = self.session.post(
self.url("/api/v1/servers/localhost/zones"),
for k in payload.keys():
self.assertEqual(data[k], payload[k])
+ def test_create_forwarded_zone_notify_allowed(self):
+ payload, data = self.create_zone(kind='Forwarded', rd=False, servers=['8.8.8.8'], notify_allowed=True)
+ # return values are normalized
+ payload['servers'][0] += ':53'
+ for k in payload.keys():
+ self.assertEqual(data[k], payload[k])
+
def test_create_forwarded_rd_zone(self):
payload, data = self.create_zone(name='google.com.', kind='Forwarded', rd=True, servers=['8.8.8.8'])
# return values are normalized
_config_params = []
_config_template_default = """
-module-dir=../regression-tests/modules
+module-dir={PDNS_MODULE_DIR}
daemon=no
bind-config={confdir}/named.conf
bind-dnssec-db={bind_dnssec_db}
""",
}
- _auth_cmd = ['authbind',
- os.environ['PDNS']]
+ _auth_cmd = [os.environ['PDNS']]
+ if sys.platform != 'darwin':
+ _auth_cmd = ['authbind'] + _auth_cmd
+
_auth_env = {}
_auths = {}
_PREFIX = os.environ['PREFIX']
+ _PDNS_MODULE_DIR = os.environ['PDNS_MODULE_DIR']
@classmethod
with open(os.path.join(confdir, 'pdns.conf'), 'w') as pdnsconf:
pdnsconf.write(cls._config_template_default.format(
confdir=confdir, prefix=cls._PREFIX,
- bind_dnssec_db=bind_dnssec_db))
+ bind_dnssec_db=bind_dnssec_db,
+ PDNS_MODULE_DIR=cls._PDNS_MODULE_DIR,
+ ))
pdnsconf.write(cls._config_template % params)
os.system("sqlite3 ./configs/auth/powerdns.sqlite < ../modules/gsqlite3backend/schema.sqlite3.sql")
[ -f ./vars ] && . ./vars
-export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
-export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
-export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+if [ -z "$PDNS_BUILD_PATH" ]; then
+ # PDNS_BUILD_PATH is unset or empty. Assume an autotools build.
+ PDNS_BUILD_PATH=.
+
+ export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
+ export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
+ export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+ export PDNS_MODULE_DIR=${PDNS_MODULE_DIR:-${PWD}/modules}
+else
+ export PDNS=${PDNS:-$PDNS_BUILD_PATH/pdns-auth}
+ export PDNSUTIL=${PDNSUTIL:-$PDNS_BUILD_PATH/pdns-auth-util}
+ export PDNSCONTROL=${PDNSCONTROL:-$PDNS_BUILD_PATH/pdns-auth-control}
+ export PDNS_MODULE_DIR=${PDNS_MODULE_DIR:-$PDNS_BUILD_PATH/modules}
+fi
export PREFIX=127.0.0
ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 48)
- query = dns.message.make_query('subnet.example.org', 'A', use_edns=True, options=[ecso])
+ query = dns.message.make_query('subnet.example.org', 'AAAA', use_edns=True, options=[ecso])
res = self.sendUDPQuery(query)
self.assertRcodeEqual(res, dns.rcode.NOERROR)
- self.assertAnyRRsetInAnswer(res, expected_a)
+ self.assertAnyRRsetInAnswer(res, expected_aaaa)
self.assertEqual(res.options[0], ecso2)
def testECSWrong(self):
ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 48)
- query = dns.message.make_query('subnetwrong.example.org', 'A', use_edns=True, options=[ecso])
+ query = dns.message.make_query('subnetwrong.example.org', 'AAAA', use_edns=True, options=[ecso])
res = self.sendUDPQuery(query)
self.assertRcodeEqual(res, dns.rcode.NOERROR)
- self.assertAnyRRsetInAnswer(res, expected_a)
+ self.assertAnyRRsetInAnswer(res, expected_aaaa)
self.assertEqual(res.options[0], ecso2)
def testECSNone(self):
ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 0)
- query = dns.message.make_query('noerror.example.org', 'A', use_edns=True, options=[ecso])
+ query = dns.message.make_query('noerror.example.org', 'AAAA', use_edns=True, options=[ecso])
res = self.sendUDPQuery(query)
self.assertRcodeEqual(res, dns.rcode.NOERROR)
- self.assertAnyRRsetInAnswer(res, expected_a)
+ self.assertAnyRRsetInAnswer(res, expected_aaaa)
self.assertEqual(res.options[0], ecso2)
class AliasUDPResponder(DatagramProtocol):
class GSSTSIGBase(AuthTest):
_config_template_default = """
-module-dir=../regression-tests/modules
+module-dir={PDNS_MODULE_DIR}
daemon=no
socket-dir={confdir}
cache-ttl=0
def checkMessageEDNSWithoutOptions(self, expected, received):
self.assertEqual(expected, received)
self.assertEqual(received.edns, 0)
+ self.assertEqual(expected.ednsflags, received.ednsflags)
self.assertEqual(expected.payload, received.payload)
def checkMessageEDNSWithoutECS(self, expected, received, withCookies=0):
self.assertEqual(expected, received)
self.assertEqual(received.edns, 0)
+ self.assertEqual(expected.ednsflags, received.ednsflags)
self.assertEqual(expected.payload, received.payload)
self.assertEqual(len(received.options), withCookies)
if withCookies:
def checkMessageEDNSWithECS(self, expected, received, additionalOptions=0):
self.assertEqual(expected, received)
self.assertEqual(received.edns, 0)
+ self.assertEqual(expected.ednsflags, received.ednsflags)
self.assertEqual(expected.payload, received.payload)
self.assertEqual(len(received.options), 1 + additionalOptions)
hasECS = False
def checkMessageEDNS(self, expected, received):
self.assertEqual(expected, received)
self.assertEqual(received.edns, 0)
+ self.assertEqual(expected.ednsflags, received.ednsflags)
self.assertEqual(expected.payload, received.payload)
self.assertEqual(len(expected.options), len(received.options))
self.compareOptions(expected.options, received.options)
requests>=2.1.0
protobuf>=3.0
pyasn1==0.4.8
-pysnmp>=4.3.4
+pysnmp>=5,<6
future>=0.17.1
pycurl>=7.43.0
lmdb>=0.95
if [ `uname -s` == Darwin ]
then
- if [ ! -e /usr/local/opt/curl-openssl ]
+ BREW_CURL_PREFIX=$(brew --prefix curl)
+ if [ ! -e "${BREW_CURL_PREFIX}" ]
then
- echo Please run: brew install curl-openssl, and try again
+ echo Please run: brew install curl, and try again
exit 1
else
- export PYCURL_CURL_CONFIG=/usr/local/opt/curl-openssl/bin/curl-config
- export LDFLAGS=-L/usr/local/opt/openssl/lib
- export CPPFLAGS=-I/usr/local/opt/openssl/include
+ export PYCURL_CURL_CONFIG="${BREW_CURL_PREFIX}/bin/curl-config"
+ export LDFLAGS="-L${BREW_CURL_PREFIX}/lib${LDFLAGS+ $LDFLAGS}"
+ export CPPFLAGS="-I${BREW_CURL_PREFIX}/include${CPPFLAGS+ $CPPFLAGS}"
+ export PKG_CONFIG_PATH="${BREW_CURL_PREFIX}/lib/pkgconfig"
fi
fi
pip install -U pip wheel | cat
query.id = 0
response = dns.message.make_response(query)
response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
+ response.want_dnssec(True)
rrset = dns.rrset.from_text(name,
3600,
dns.rdataclass.IN,
rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[ecso], want_dnssec=True)
query.id = 0
- expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[rewrittenEcso])
+ expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[rewrittenEcso], want_dnssec=True)
response = dns.message.make_response(query)
response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
+ response.want_dnssec(True)
rrset = dns.rrset.from_text(name,
3600,
dns.rdataclass.IN,
(_, receivedResponse) = sender(query, response=None, useQueue=False)
self.checkMessageEDNS(expectedResponse, receivedResponse)
+ def testExtendedErrorBackendResponse(self):
+ """
+ EDE: Backend response (DO)
+ """
+ name = 'backend-response-do.ede.tests.powerdns.com.'
+ ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=True, want_dnssec=True)
+
+ backendResponse = dns.message.make_response(query)
+ backendResponse.use_edns(edns=True, payload=4096, options=[])
+ backendResponse.want_dnssec(True)
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '127.0.0.1')
+
+ backendResponse.answer.append(rrset)
+ expectedResponse = dns.message.make_response(query)
+ expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
+ expectedResponse.want_dnssec(True)
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '127.0.0.1')
+ expectedResponse.answer.append(rrset)
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (receivedQuery, receivedResponse) = sender(query, backendResponse)
+ receivedQuery.id = query.id
+ self.assertEqual(query, receivedQuery)
+ self.checkMessageEDNS(expectedResponse, receivedResponse)
+
+ # testing the cache
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.checkMessageEDNS(expectedResponse, receivedResponse)
+
def testExtendedErrorBackendResponseWithExistingEDE(self):
"""
EDE: Backend response with existing EDE
query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
query.flags &= ~dns.flags.RD
expectedResponse = dns.message.make_response(query, our_payload=1042)
+ expectedResponse.want_dnssec(True)
expectedResponse.set_rcode(dns.rcode.REFUSED)
for method in ("sendUDPQuery", "sendTCPQuery"):
# dnsdist sets RA = RD for TC responses
query.flags &= ~dns.flags.RD
expectedResponse = dns.message.make_response(query, our_payload=1042)
+ expectedResponse.want_dnssec(True)
expectedResponse.flags |= dns.flags.TC
(_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
name = 'edns-do.lua.edns-self.tests.powerdns.com.'
query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
expectedResponse = dns.message.make_response(query, our_payload=1042)
+ expectedResponse.want_dnssec(True)
expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
for method in ("sendUDPQuery", "sendTCPQuery"):
# dnsdist set RA = RD for spoofed responses
query.flags &= ~dns.flags.RD
expectedResponse = dns.message.make_response(query, our_payload=1042)
+ expectedResponse.want_dnssec(True)
expectedResponse.answer.append(dns.rrset.from_text(name,
60,
dns.rdataclass.IN,
query.flags &= ~dns.flags.RD
expectedResponse = dns.message.make_response(query, our_payload=1042)
expectedResponse.set_rcode(dns.rcode.REFUSED)
+ expectedResponse.want_dnssec(True)
for method in ("sendUDPQuery", "sendTCPQuery"):
sender = getattr(self, method)
# dnsdist sets RA = RD for TC responses
query.flags &= ~dns.flags.RD
expectedResponse = dns.message.make_response(query, our_payload=1042)
+ expectedResponse.want_dnssec(True)
expectedResponse.flags |= dns.flags.TC
(_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
name = 'edns-options.lua.edns-self.tests.powerdns.com.'
query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512, want_dnssec=True)
expectedResponse = dns.message.make_response(query, our_payload=1042)
+ expectedResponse.want_dnssec(True)
expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
for method in ("sendUDPQuery", "sendTCPQuery"):
# dnsdist set RA = RD for spoofed responses
query.flags &= ~dns.flags.RD
expectedResponse = dns.message.make_response(query, our_payload=1042)
+ expectedResponse.want_dnssec(True)
expectedResponse.answer.append(dns.rrset.from_text(name,
60,
dns.rdataclass.IN,
return false
end
+ local ednsVersion = ffi.C.dnsdist_ffi_dnsquestion_get_edns_version(dq)
+ if ednsVersion ~= 0 then
+ print('invalid EDNS version')
+ return false
+ end
+
+ local ednsExtendedRCode = ffi.C.dnsdist_ffi_dnsquestion_get_edns_extended_rcode(dq)
+ if ednsExtendedRCode ~= 0 then
+ print('invalid EDNS Extended RCode')
+ return false
+ end
+
local len = ffi.C.dnsdist_ffi_dnsquestion_get_len(dq)
if len ~= 52 then
print('invalid length')
return false
end
- local len = ffi.C.dnsdist_ffi_dnsquestion_get_len(dq)
+ local ednsVersion = ffi.C.dnsdist_ffi_dnsquestion_get_edns_version(dq)
+ if ednsVersion ~= 0 then
+ print('invalid EDNS version')
+ return false
+ end
+
+ local ednsExtendedRCode = ffi.C.dnsdist_ffi_dnsquestion_get_edns_extended_rcode(dq)
+ if ednsExtendedRCode ~= 0 then
+ print('invalid EDNS Extended RCode')
+ return false
+ end
+
+ local len = ffi.C.dnsdist_ffi_dnsquestion_get_len(dq)
if len ~= 61 then
print('invalid length')
print(len)
declareMetric('custom-metric2', 'gauge', 'Custom gauge')
-- and custom names
declareMetric('custom-metric3', 'counter', 'Custom counter', 'custom_prometheus_name')
+
+ -- test prometheus labels in custom metrics
+ declareMetric('custom-metric-foo-x-bar-y-xyz', 'counter', 'Custom counter with labels', 'custom_metric_foo{x="bar",y="xyz"}')
+ declareMetric('custom-metric-foo-x-baz-y-abc', 'counter', 'Custom counter with labels', 'custom_metric_foo{x="baz",y="abc"}')
"""
def checkPrometheusContentBasic(self, content):
elif not line.startswith('#'):
tokens = line.split(' ')
self.assertEqual(len(tokens), 2)
- if not line.startswith('dnsdist_') and not line.startswith('custom_prometheus_name'):
+ if not line.startswith('dnsdist_') and not line.startswith('custom_'):
raise AssertionError('Expecting prometheus metric to be prefixed by \'dnsdist_\', got: "%s"' % (line))
def checkMetric(self, content, name, expectedType, expectedValue):
addAction("values-action.proxy.tests.powerdns.com.", SetProxyProtocolValuesAction({ ["1"]="dnsdist", ["255"]="proxy-protocol"}))
"""
_config_params = ['_proxyResponderPort']
- _verboseMode = True
def testProxyUDP(self):
"""
_config_template = """
addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library='nghttp2', proxyProtocolOutsideTLS=true})
addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library='nghttp2', proxyProtocolOutsideTLS=false})
+ addTLSLocal("127.0.0.1:%d", "%s", "%s", {proxyProtocolOutsideTLS=true})
+ addTLSLocal("127.0.0.1:%d", "%s", "%s", {proxyProtocolOutsideTLS=false})
setProxyProtocolACL( { "127.0.0.1/32" } )
newServer{address="127.0.0.1:%d", useProxyProtocol=true, proxyProtocolAdvertiseTLS=true}
_caCert = 'ca.pem'
_dohServerPPOutsidePort = pickAvailablePort()
_dohServerPPInsidePort = pickAvailablePort()
- _config_params = ['_dohServerPPOutsidePort', '_serverCert', '_serverKey', '_dohServerPPInsidePort', '_serverCert', '_serverKey', '_proxyResponderPort']
+ _dotServerPPOutsidePort = pickAvailablePort()
+ _dotServerPPInsidePort = pickAvailablePort()
+ _config_params = ['_dohServerPPOutsidePort', '_serverCert', '_serverKey', '_dohServerPPInsidePort', '_serverCert', '_serverKey', '_dotServerPPOutsidePort', '_serverCert', '_serverKey', '_dotServerPPInsidePort', '_serverCert', '_serverKey', '_proxyResponderPort']
def testNoHeader(self):
"""
conn = self.openDOHConnection(reverseProxyPort, self._caCert, timeout=2.0)
reverseProxyBaseURL = ("https://%s:%d/" % (self._serverName, reverseProxyPort))
- (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, useQueue=True, conn=conn)
+ (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
(receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
self.assertTrue(receivedProxyPayload)
self.assertTrue(receivedDNSData)
for idx in range(5):
receivedResponse = None
toProxyQueue.put(response, True, 2.0)
- (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, useQueue=True, conn=conn)
+ (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
(receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
self.assertTrue(receivedProxyPayload)
self.assertTrue(receivedDNSData)
conn = self.openDOHConnection(reverseProxyPort, self._caCert, timeout=2.0)
reverseProxyBaseURL = ("https://%s:%d/" % (self._serverName, reverseProxyPort))
- (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, useQueue=True, conn=conn)
+ (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
(receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
self.assertTrue(receivedProxyPayload)
self.assertTrue(receivedDNSData)
for idx in range(5):
receivedResponse = None
toProxyQueue.put(response, True, 2.0)
- (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, useQueue=True, conn=conn)
+ (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
(receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
self.assertTrue(receivedProxyPayload)
self.assertTrue(receivedDNSData)
self.assertEqual(receivedResponse, response)
self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+ def testProxyDoTSeveralQueriesOverConnectionPPOutside(self):
+ """
+ Incoming Proxy Protocol: Several queries over the same connection (DoT, PP outside TLS)
+ """
+ name = 'several-queries.dot-outside.proxy-protocol-incoming.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN')
+ response = dns.message.make_response(query)
+
+ toProxyQueue.put(response, True, 2.0)
+
+ wire = query.to_wire()
+
+ reverseProxyPort = pickAvailablePort()
+ reverseProxy = threading.Thread(name='Mock Proxy Protocol Reverse Proxy', target=MockTCPReverseProxyAddingProxyProtocol, args=[reverseProxyPort, self._dotServerPPOutsidePort])
+ reverseProxy.start()
+ time.sleep(1)
+
+ receivedResponse = None
+ conn = self.openTLSConnection(reverseProxyPort, self._serverName, self._caCert, timeout=2.0)
+ self.sendTCPQueryOverConnection(conn, query, response=response)
+ receivedResponse = self.recvTCPResponseOverConnection(conn)
+ (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+ self.assertTrue(receivedProxyPayload)
+ self.assertTrue(receivedDNSData)
+ self.assertTrue(receivedResponse)
+
+ receivedQuery = dns.message.from_wire(receivedDNSData)
+ receivedQuery.id = query.id
+ receivedResponse.id = response.id
+ self.assertEqual(receivedQuery, query)
+ self.assertEqual(receivedResponse, response)
+ self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+
+ for idx in range(5):
+ receivedResponse = None
+ toProxyQueue.put(response, True, 2.0)
+ self.sendTCPQueryOverConnection(conn, query, response=response)
+ receivedResponse = self.recvTCPResponseOverConnection(conn)
+ (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+ self.assertTrue(receivedProxyPayload)
+ self.assertTrue(receivedDNSData)
+ self.assertTrue(receivedResponse)
+
+ receivedQuery = dns.message.from_wire(receivedDNSData)
+ receivedQuery.id = query.id
+ receivedResponse.id = response.id
+ self.assertEqual(receivedQuery, query)
+ self.assertEqual(receivedResponse, response)
+ self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+
+ def testProxyDoTSeveralQueriesOverConnectionPPInside(self):
+ """
+ Incoming Proxy Protocol: Several queries over the same connection (DoT, PP inside TLS)
+ """
+ name = 'several-queries.dot-inside.proxy-protocol-incoming.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN')
+ response = dns.message.make_response(query)
+
+ toProxyQueue.put(response, True, 2.0)
+
+ wire = query.to_wire()
+
+ reverseProxyPort = pickAvailablePort()
+ tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+ tlsContext.load_cert_chain(self._serverCert, self._serverKey)
+ tlsContext.set_alpn_protocols(['dot'])
+ reverseProxy = threading.Thread(name='Mock Proxy Protocol Reverse Proxy', target=MockTCPReverseProxyAddingProxyProtocol, args=[reverseProxyPort, self._dotServerPPInsidePort, tlsContext, self._caCert, self._serverName])
+ reverseProxy.start()
+
+ receivedResponse = None
+ time.sleep(1)
+ conn = self.openTLSConnection(reverseProxyPort, self._serverName, self._caCert, timeout=2.0)
+
+ self.sendTCPQueryOverConnection(conn, query, response=response)
+ receivedResponse = self.recvTCPResponseOverConnection(conn)
+ (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+ self.assertTrue(receivedProxyPayload)
+ self.assertTrue(receivedDNSData)
+ self.assertTrue(receivedResponse)
+
+ receivedQuery = dns.message.from_wire(receivedDNSData)
+ receivedQuery.id = query.id
+ receivedResponse.id = response.id
+ self.assertEqual(receivedQuery, query)
+ self.assertEqual(receivedResponse, response)
+
+ for idx in range(5):
+ receivedResponse = None
+ toProxyQueue.put(response, True, 2.0)
+ self.sendTCPQueryOverConnection(conn, query, response=response)
+ receivedResponse = self.recvTCPResponseOverConnection(conn)
+ (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+ self.assertTrue(receivedProxyPayload)
+ self.assertTrue(receivedDNSData)
+ self.assertTrue(receivedResponse)
+
+ receivedQuery = dns.message.from_wire(receivedDNSData)
+ receivedQuery.id = query.id
+ receivedResponse.id = response.id
+ self.assertEqual(receivedQuery, query)
+ self.assertEqual(receivedResponse, response)
+
@classmethod
def tearDownClass(cls):
cls._sock.close()
"""
# NORMAL responder, does not expect a proxy protocol payload!
_config_params = ['_testServerPort']
- _verboseMode = True
def testNoHeader(self):
"""
setACL( { "::1/128", "127.0.0.0/8" } )
"""
_config_params = ['_proxyResponderPort', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_dohWithH2OServerPort', '_serverCert', '_serverKey']
- _verboseMode = True
def testTruncation(self):
"""
self.assertEqual(len(receivedResponse.additional), 2)
self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
+
+class TestSVCBViaFFI(DNSDistTest):
+
+ _config_template = """
+ local ffi = require("ffi")
+
+ function setSVC(record, port, mandatoryParam, alpn, v4Hint, v6Hint)
+ ffi.C.dnsdist_ffi_svc_record_parameters_set_port(record, port)
+ ffi.C.dnsdist_ffi_svc_record_parameters_add_mandatory_param(record, mandatoryParam)
+ ffi.C.dnsdist_ffi_svc_record_parameters_add_alpn(record, alpn, #alpn)
+ if v4Hint then
+ ffi.C.dnsdist_ffi_svc_record_parameters_add_ipv4_hint(record, v4Hint, #v4Hint)
+ end
+ if v6Hint then
+ ffi.C.dnsdist_ffi_svc_record_parameters_add_ipv6_hint(record, v6Hint, #v6Hint)
+ end
+ end
+
+ function generateSVC(target, priority, port, alpn, noDefaultALPN, v4Hint, v6Hint)
+ local recordPtr = ffi.new("dnsdist_ffi_svc_record_parameters* [1]")
+ local recordPtrOut = ffi.cast("dnsdist_ffi_svc_record_parameters**", recordPtr)
+ ffi.C.dnsdist_ffi_svc_record_parameters_new(target, priority, noDefaultALPN, recordPtrOut)
+ ffi.gc(recordPtrOut[0], ffi.C.dnsdist_ffi_svc_record_parameters_free)
+ -- 3 is the port parameter
+ setSVC(recordPtrOut[0], port, 3, alpn, v4Hint, v6Hint)
+ return recordPtrOut[0]
+ end
+
+ function basicSVC(dq)
+ local SVCrecords = ffi.new("dnsdist_ffi_svc_record_parameters* [2]")
+ SVCrecords[0] = generateSVC("dot.powerdns.com.", 1, 853, "dot", true, "192.0.2.1", "2001:db8::1")
+ SVCrecords[1] = generateSVC("doh.powerdns.com.", 2, 443, "h2", false, "192.0.2.2", "2001:db8::2")
+ local path = "/dns-query{?dns}"
+ ffi.C.dnsdist_ffi_svc_record_parameters_set_additional_param(SVCrecords[1], 7, path, #path)
+ local SVCrecordsPtr = ffi.cast("const dnsdist_ffi_svc_record_parameters**", SVCrecords)
+ if not ffi.C.dnsdist_ffi_dnsquestion_generate_svc_response(dq, SVCrecordsPtr, 2, 60) then
+ return DNSAction.ServFail
+ end
+ return DNSAction.HeaderModify
+ end
+
+ addAction(AndRule{QTypeRule(64), SuffixMatchNodeRule("basic.svcb.tests.powerdns.com.")}, LuaFFIAction(basicSVC))
+
+ function noHintsSVC(dq)
+ local SVCrecords = ffi.new("dnsdist_ffi_svc_record_parameters* [2]")
+ SVCrecords[0] = generateSVC("dot.powerdns.com.", 1, 853, "dot", true, nil, nil)
+ SVCrecords[1] = generateSVC("doh.powerdns.com.", 2, 443, "h2", false, nil, nil)
+ local path = "/dns-query{?dns}"
+ ffi.C.dnsdist_ffi_svc_record_parameters_set_additional_param(SVCrecords[1], 7, path, #path)
+ local SVCrecordsPtr = ffi.cast("const dnsdist_ffi_svc_record_parameters**", SVCrecords)
+ if not ffi.C.dnsdist_ffi_dnsquestion_generate_svc_response(dq, SVCrecordsPtr, 2, 60) then
+ return DNSAction.ServFail
+ end
+ return DNSAction.HeaderModify
+ end
+
+ addAction(AndRule{QTypeRule(64), SuffixMatchNodeRule("no-hints.svcb.tests.powerdns.com.")}, LuaFFIAction(noHintsSVC))
+
+ function effectiveTargetSVC(dq)
+ local SVCrecords = ffi.new("dnsdist_ffi_svc_record_parameters* [2]")
+ SVCrecords[0] = generateSVC(".", 1, 853, "dot", true, "192.0.2.1", "2001:db8::1")
+ SVCrecords[1] = generateSVC(".", 2, 443, "h2", false, "192.0.2.1", "2001:db8::1")
+ local path = "/dns-query{?dns}"
+ ffi.C.dnsdist_ffi_svc_record_parameters_set_additional_param(SVCrecords[1], 7, path, #path)
+ local SVCrecordsPtr = ffi.cast("const dnsdist_ffi_svc_record_parameters**", SVCrecords)
+ if not ffi.C.dnsdist_ffi_dnsquestion_generate_svc_response(dq, SVCrecordsPtr, 2, 60) then
+ return DNSAction.ServFail
+ end
+ return DNSAction.HeaderModify
+ end
+
+ addAction(AndRule{QTypeRule(64), SuffixMatchNodeRule("effective-target.svcb.tests.powerdns.com.")}, LuaFFIAction(effectiveTargetSVC))
+
+ function httpsSVC(dq)
+ local SVCrecords = ffi.new("dnsdist_ffi_svc_record_parameters* [1]")
+ SVCrecords[0] = generateSVC(".", 1, 8002, "h2", false, "192.0.2.2", "2001:db8::2")
+ local SVCrecordsPtr = ffi.cast("const dnsdist_ffi_svc_record_parameters**", SVCrecords)
+ if not ffi.C.dnsdist_ffi_dnsquestion_generate_svc_response(dq, SVCrecordsPtr, 1, 60) then
+ return DNSAction.ServFail
+ end
+ return DNSAction.HeaderModify
+ end
+
+ addAction(AndRule{QTypeRule(65), SuffixMatchNodeRule("https.svcb.tests.powerdns.com.")}, LuaFFIAction(httpsSVC))
+
+ newServer{address="127.0.0.1:%s"}
+ """
+
+ def testBasic(self):
+ """
+ SVCB: Basic service binding
+ """
+ name = 'basic.svcb.tests.powerdns.com.'
+ query = dns.message.make_query(name, 64, 'IN')
+ # dnsdist set RA = RD for spoofed responses
+ query.flags &= ~dns.flags.RD
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(len(receivedResponse.answer), 1)
+ self.assertEqual(receivedResponse.answer[0].rdtype, 64)
+ self.assertEqual(len(receivedResponse.additional), 4)
+ self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
+ self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
+ self.assertEqual(receivedResponse.additional[2], dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
+ self.assertEqual(receivedResponse.additional[3], dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::1'))
+
+ def testNoHints(self):
+ """
+ SVCB: No hints
+ """
+ name = 'no-hints.svcb.tests.powerdns.com.'
+ query = dns.message.make_query(name, 64, 'IN')
+ # dnsdist set RA = RD for spoofed responses
+ query.flags &= ~dns.flags.RD
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(len(receivedResponse.answer), 1)
+ self.assertEqual(receivedResponse.answer[0].rdtype, 64)
+ self.assertEqual(len(receivedResponse.additional), 0)
+
+ def testEffectiveTarget(self):
+ """
+ SVCB: Effective target
+ """
+ name = 'effective-target.svcb.tests.powerdns.com.'
+ query = dns.message.make_query(name, 64, 'IN')
+ # dnsdist set RA = RD for spoofed responses
+ query.flags &= ~dns.flags.RD
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(len(receivedResponse.answer), 1)
+ self.assertEqual(receivedResponse.answer[0].rdtype, 64)
+ self.assertEqual(len(receivedResponse.additional), 2)
+ self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
+ self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::1'))
+
+ def testHTTPS(self):
+ """
+ SVCB: HTTPS
+ """
+ name = 'https.svcb.tests.powerdns.com.'
+ query = dns.message.make_query(name, 65, 'IN')
+ # dnsdist set RA = RD for spoofed responses
+ query.flags &= ~dns.flags.RD
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(len(receivedResponse.answer), 1)
+ self.assertEqual(receivedResponse.answer[0].rdtype, 65)
+ self.assertEqual(len(receivedResponse.additional), 2)
+ self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
+ self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
cls.startResponders()
cls.startDNSDist()
cls.setUpSockets()
+
+class TestTLSTicketsKeyAddedCallback(DNSDistTest):
+ _consoleKey = DNSDistTest.generateConsoleKey()
+ _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+
+ _serverKey = 'server.key'
+ _serverCert = 'server.chain'
+ _serverName = 'tls.tests.dnsdist.org'
+ _caCert = 'ca.pem'
+ _tlsServerPort = pickAvailablePort()
+ _numberOfKeys = 5
+
+ _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
+ _config_template = """
+ setKey("%s")
+ controlSocket("127.0.0.1:%s")
+
+ newServer{address="127.0.0.1:%s"}
+ addTLSLocal("127.0.0.1:%s", "%s", "%s", { provider="openssl" })
+
+ callbackCalled = 0
+ function keyAddedCallback(key, keyLen)
+ callbackCalled = keyLen
+ end
+
+ """
+
+ def testLuaThreadCounter(self):
+ """
+ LuaThread: Test the lua newThread interface
+ """
+ self.sendConsoleCommand('setTicketsKeyAddedHook(keyAddedCallback)');
+ called = self.sendConsoleCommand('callbackCalled')
+ self.assertEqual(int(called), 0)
+ self.sendConsoleCommand("getTLSFrontend(0):rotateTicketsKey()")
+ called = self.sendConsoleCommand('callbackCalled')
+ self.assertGreater(int(called), 0)
import glob
e = xml.etree.ElementTree.parse('pytest.xml')
-root = e.getroot()
+testsuites = e.getroot()
-for child in root:
- if len(child):
+for testsuite in testsuites:
+ if len(testsuite):
getstdout = False
- for elem in child:
- if elem.tag in ["failure", "error"]:
- cls = child.get("classname")
- name = child.get("name")
- if '_' not in cls or '.' not in cls:
- print('Unexpected classname %s; name %s' % (cls, name))
- getstdout = True
- continue
+ for testcase in testsuite:
+ cls = testcase.get("classname")
+ name = testcase.get("name")
+ if '_' not in cls or '.' not in cls:
+ print('Unexpected classname %s; name %s' % (cls, name))
+ getstdout = True
+ continue
- confdirnames = [cls.split('_')[1].split('.')[0], cls.split('.')[1].split('Test')[0]]
- for confdirname in confdirnames:
- confdir = os.path.join("configs", confdirname)
- recursorlog = os.path.join(confdir, "recursor.log")
- if os.path.exists(recursorlog):
- print("==============> %s <==============" % recursorlog)
- with open(recursorlog) as f:
- print(''.join(f.readlines()))
- authdirs = glob.glob(os.path.join(confdir, "auth-*"))
- for authdir in authdirs:
- authlog = os.path.join(authdir, "pdns.log")
- if os.path.exists(recursorlog):
- print("==============> %s <==============" % authlog)
- with open(authlog) as f:
- print(''.join(f.readlines()))
- if getstdout and elem.tag == 'system-out':
- print("==============> STDOUT LOG FROM XML <==============")
- print(elem.text)
- print("==============> END STDOUT LOG FROM XML <==============")
+ confdirnames = [cls.split('_')[1].split('.')[0], cls.split('.')[1].split('Test')[0]]
+ found = False
+ for confdirname in confdirnames:
+ confdir = os.path.join("configs", confdirname)
+ recursorlog = os.path.join(confdir, "recursor.log")
+ if os.path.exists(recursorlog):
+ found = True
+ for elem in testcase:
+ if elem.tag in ["failure", "error"]:
+ print("==============> %s <==============" % recursorlog)
+ with open(recursorlog) as f:
+ print(''.join(f.readlines()))
+ authdirs = glob.glob(os.path.join(confdir, "auth-*"))
+ for authdir in authdirs:
+ authlog = os.path.join(authdir, "pdns.log")
+ if os.path.exists(recursorlog):
+ print("==============> %s <==============" % authlog)
+ with open(authlog) as f:
+ print(''.join(f.readlines()))
+ if not found and confdirnames[0] != 'Flags':
+ print("%s not found, configdir does not mach expected pattern" % confdirnames)
+ if getstdout and elem.tag == 'system-out':
+ print("==============> STDOUT LOG FROM XML <==============")
+ print(elem.text)
+ print("==============> END STDOUT LOG FROM XML <==============")
import unittest
import dns
import dns.message
+import requests
from proxyprotocol import ProxyProtocol
print(f"*** End startAuth log for {logFile} ***")
raise AssertionError('%s failed (%d)' % (authcmd, cls._auths[ipaddress].returncode))
+ @classmethod
+ def checkConfdir(cls, confdir):
+ if cls.__name__ != 'FlagsTest' and os.path.basename(confdir) + 'Test' != cls.__name__:
+ raise AssertionError('conf dir ' + confdir + ' and ' + cls.__name__ + ' inconsistent with convention')
+
@classmethod
def generateRecursorConfig(cls, confdir):
+ cls.checkConfdir(confdir)
params = tuple([getattr(cls, param) for param in cls._config_params])
if len(params):
print(params)
@classmethod
def generateRecursorYamlConfig(cls, confdir, luaConfig=True):
+ cls.checkConfdir(confdir)
params = tuple([getattr(cls, param) for param in cls._config_params])
if len(params):
print(params)
return message
@classmethod
- def sendTCPQuery(cls, query, timeout=2.0):
+ def sendTCPQuery(cls, query, timeout=2.0, decode=True, fwparams=dict()):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if timeout:
sock.settimeout(timeout)
message = None
if data:
- message = dns.message.from_wire(data)
+ if not decode:
+ return data
+ message = dns.message.from_wire(data, **fwparams)
return message
@classmethod
if data:
message = dns.message.from_wire(data)
return message
+
+ def checkMetrics(self, map):
+ self.waitForTCPSocket("127.0.0.1", self._wsPort)
+ headers = {'x-api-key': self._apiKey}
+ url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+ r = requests.get(url, headers=headers, timeout=self._wsTimeout)
+ self.assertEqual(r.status_code, 200)
+ self.assertTrue(r.json())
+ content = r.json()
+ count = 0
+ for entry in content:
+ for key, expected in map.items():
+ if entry['name'] == key:
+ value = int(entry['value'])
+ if callable(expected):
+ self.assertTrue(expected(value))
+ else:
+ self.assertEqual(value, expected)
+ count += 1
+ self.assertEqual(count, len(map))
protobuf>=2.5; sys_platform != 'darwin'
protobuf>=3.0; sys_platform == 'darwin'
pyasn1==0.4.8
-pysnmp>=4.3.4
+pysnmp>=5,<6
requests>=2.1.0
Twisted>0.15.0
export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
-LIBFAKETIME_DEFAULT=/usr/lib/x86_64-linux-gnu/faketime/libfaketimeMT.so.1 # ubuntu default
+LIBFAKETIME_DEFAULT=/usr/lib/$(arch)-linux-gnu/faketime/libfaketimeMT.so.1 # ubuntu default
LIBAUTHBIND_DEFAULT=/usr/lib/authbind/libauthbind.so.1
if [ $(uname -s) = "Darwin" ]; then
# macOS is not /really/ supported here; it works for some tests, and then you might need sudo.
cls.tearDownRecursor()
class APIAllowedRecursorTest(APIRecursorTest):
- _confdir = 'API'
+ _confdir = 'APIAllowedRecursor'
_wsPort = 8042
_wsTimeout = 2
_wsPassword = 'secretpassword'
self.assertTrue(r.json())
class APIDeniedRecursorTest(APIRecursorTest):
- _confdir = 'API'
+ _confdir = 'APIDeniedRecursor'
_wsPort = 8042
_wsTimeout = 2
_wsPassword = 'secretpassword'
import os
from recursortests import RecursorTest
-class testAdditionalsDefault(RecursorTest):
+class AdditionalsDefaultTest(RecursorTest):
_confdir = 'AdditionalsDefault'
_config_template = """
self.assertRRsetInAdditional(res, adds1)
self.assertRRsetInAdditional(res, adds2)
-class testAdditionalsResolveImmediately(RecursorTest):
+class AdditionalsResolveImmediatelyTest(RecursorTest):
_confdir = 'AdditionalsResolveImmediately'
_config_template = """
dnssec=validate
self.assertRRsetInAdditional(res, adds7)
self.assertMatchingRRSIGInAdditional(res, adds7)
-class testAdditionalsResolveCacheOnly(RecursorTest):
+class AdditionalsResolveCacheOnlyTest(RecursorTest):
_confdir = 'AdditionalsResolveCacheOnly'
_config_template = """
dnssec=validate
self.assertEqual(res.options[0].otype, 15)
self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
-class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
+class AggressiveNSECCacheNSECTest(AggressiveNSECCacheBase):
_confdir = 'AggressiveNSECCacheNSEC'
__test__ = True
self.assertEqual(res.options[0].otype, 15)
self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(9, b''))
-class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
+class AggressiveNSECCacheNSEC3Test(AggressiveNSECCacheBase):
_confdir = 'AggressiveNSECCacheNSEC3'
__test__ = True
import socket
from recursortests import RecursorTest
-class testAnyBind(RecursorTest):
+class AnyBindTest(RecursorTest):
_confdir = 'AnyBind'
_config_template = """dnssec=validate
@ 3600 IN SOA {soa}
@ 3600 IN A 192.0.2.88
""".format(soa=cls._SOA))
- super(testAnyBind, cls).generateRecursorConfig(confdir)
+ super(AnyBindTest, cls).generateRecursorConfig(confdir)
@classmethod
def setUpSockets(cls):
from recursortests import RecursorTest
-class TestCarbon(RecursorTest):
+class CarbonTest(RecursorTest):
_confdir = 'Carbon'
_carbonNamespace = 'NS'
_carbonInstance = 'Instance'
--- /dev/null
+import dns
+import os
+import time
+from recursortests import RecursorTest
+
+class ChainTest(RecursorTest):
+ """
+ These regression tests test the chaining of outgoing requests.
+ """
+ _confdir = 'Chain'
+ _wsPort = 8042
+ _wsTimeout = 2
+ _wsPassword = 'secretpassword'
+ _apiKey = 'secretapikey'
+
+ _config_template = """dnssec=validate
+ trace=no
+ devonly-regression-test-mode
+ webserver=yes
+ webserver-port=%d
+ webserver-address=127.0.0.1
+ webserver-password=%s
+ api-key=%s
+""" % (_wsPort, _wsPassword, _apiKey)
+
+ def testBasic(self):
+ """
+ Tests the case of #14624. Sending many equal requests could lead to ServFail because of clashing
+ waiter ids.
+ """
+ # We actually do not check all responses, as experience show that packets may be dropped by the OS
+ # Instead, we check if a few counters in rec have the expected values.
+ count = 200
+ name = '9.delay1.example.'
+ exp = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', 'a')
+ for i in range(count):
+ query = dns.message.make_query(name, 'TXT', want_dnssec=True)
+ query.flags |= dns.flags.AD
+ self._sock.send(query.to_wire())
+
+ # Just check one, as OS emptying of socket buffers can work against us
+ data = self._sock.recv(4096)
+ res = dns.message.from_wire(data)
+ self.assertRcodeEqual(res, dns.rcode.NOERROR)
+ self.assertMessageIsAuthenticated(res)
+ self.assertRRsetInAnswer(res, exp)
+ self.assertMatchingRRSIGInAnswer(res, exp)
+ time.sleep(1)
+
+ self.checkMetrics({
+ 'max-chain-length': (lambda x: x <= count-1), # first request has count - 1 requests chained to it
+ 'servfail-answers': 0,
+ 'noerror-answers': (lambda x: x <= count),
+ })
from recursortests import RecursorTest
-class DNS64RecursorTest(RecursorTest):
+class DNS64Test(RecursorTest):
_confdir = 'DNS64'
_config_template = """
@ 3600 IN SOA {soa}
www 3600 IN A 192.0.2.42
www 3600 IN TXT "does exist"
+txt 3600 IN TXT "a and aaaa do not exist"
aaaa 3600 IN AAAA 2001:db8::1
cname 3600 IN CNAME cname2.example.dns64.
cname2 3600 IN CNAME www.example.dns64.
+cname3 3600 IN CNAME txt.example.dns64.
formerr 3600 IN A 192.0.2.43
""".format(soa=cls._SOA))
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2 IN PTR aaaa.example.dns64.
""".format(soa=cls._SOA))
- super(DNS64RecursorTest, cls).generateRecursorConfig(confdir)
+ super(DNS64Test, cls).generateRecursorConfig(confdir)
# this type (A) exists for this name
def testExistingA(self):
for expected in expectedResults:
self.assertRRsetInAnswer(res, expected)
+ # there is a CNAME from the name to a name that is NODATA for both A and AAAA
+ # so we should get a NODATA with a single SOA record (#14362)
+ def testCNAMEToNoData(self):
+ qname = 'cname3.example.dns64.'
+
+ expectedAnswer = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'CNAME', 'txt.example.dns64.')
+ query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ res = sender(query, 2.0, True, {"one_rr_per_rrset": True}) # we want to detect dups
+ self.assertRcodeEqual(res, dns.rcode.NOERROR)
+ self.assertEqual(len(res.answer), 1)
+ self.assertEqual(len(res.authority), 1)
+ self.assertRRsetInAnswer(res, expectedAnswer)
+ self.assertAuthorityHasSOA(res)
+
# this type (AAAA) does not exist for this name and there is no A record either, we should get a NXDomain
def testNXD(self):
qname = 'nxd.example.dns64.'
res = sender(query)
self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
+ # this type (AAAA) does not exist for this name and there is no A record either, we should get a NODATA as TXT does exist
+ def testNoData(self):
+ qname = 'txt.example.dns64.'
+
+ query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ res = sender(query, 2.0, True, {"one_rr_per_rrset": True}) # we want to detect dups
+ self.assertRcodeEqual(res, dns.rcode.NOERROR)
+ self.assertEqual(len(res.answer), 0)
+ self.assertEqual(len(res.authority), 1)
+
# there is an AAAA record, we should get it
def testExistingAAAA(self):
qname = 'aaaa.example.dns64.'
def tearDownClass(cls):
cls.tearDownRecursor()
-class testNoECS(ECSTest):
+class NoECSTest(ECSTest):
_confdir = 'NoECS'
_config_template = """edns-subnet-allow-list=
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected)
-class testIncomingNoECS(ECSTest):
+class IncomingNoECSTest(ECSTest):
_confdir = 'IncomingNoECS'
_config_template = """edns-subnet-allow-list=
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected, scopeZeroResponse=True)
-class testECSByName(ECSTest):
+class ECSByNameTest(ECSTest):
_confdir = 'ECSByName'
_config_template = """edns-subnet-allow-list=ecs-echo.example.
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected)
-class testECSByNameLarger(ECSTest):
+class ECSByNameLargerTest(ECSTest):
_confdir = 'ECSByNameLarger'
_config_template = """edns-subnet-allow-list=ecs-echo.example.
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected)
-class testECSByNameSmaller(ECSTest):
- _confdir = 'ECSByNameLarger'
+class ECSByNameSmallerTest(ECSTest):
+ _confdir = 'ECSByNameSmaller'
_config_template = """edns-subnet-allow-list=ecs-echo.example.
ecs-ipv4-bits=16
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected)
-class testIncomingECSByName(ECSTest):
- _confdir = 'ECSIncomingByName'
+class IncomingECSByNameTest(ECSTest):
+ _confdir = 'IncomingECSByName'
_config_template = """edns-subnet-allow-list=ecs-echo.example.
use-incoming-edns-subnet=yes
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected, ttlECS)
-class testIncomingECSByNameLarger(ECSTest):
- _confdir = 'ECSIncomingByNameLarger'
+class IncomingECSByNameLargerTest(ECSTest):
+ _confdir = 'IncomingECSByNameLarger'
_config_template = """edns-subnet-allow-list=ecs-echo.example.
use-incoming-edns-subnet=yes
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected, ttlECS)
-class testIncomingECSByNameSmaller(ECSTest):
- _confdir = 'ECSIncomingByNameSmaller'
+class IncomingECSByNameSmallerTest(ECSTest):
+ _confdir = 'IncomingECSByNameSmaller'
_config_template = """edns-subnet-allow-list=ecs-echo.example.
use-incoming-edns-subnet=yes
self.sendECSQuery(query, expected, ttlECS)
@unittest.skipIf(not have_ipv6(), "No IPv6")
-class testIncomingECSByNameV6(ECSTest):
- _confdir = 'ECSIncomingByNameV6'
+class IncomingECSByNameV6Test(ECSTest):
+ _confdir = 'IncomingECSByNameV6'
_config_template = """edns-subnet-allow-list=ecs-echo.example.
use-incoming-edns-subnet=yes
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected, ttlECS)
-class testECSNameMismatch(ECSTest):
+class ECSNameMismatchTest(ECSTest):
_confdir = 'ECSNameMismatch'
_config_template = """edns-subnet-allow-list=not-the-right-name.example.
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected)
-class testECSByIP(ECSTest):
+class ECSByIPTest(ECSTest):
_confdir = 'ECSByIP'
_config_template = """edns-subnet-allow-list=%s.21
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected)
-class testIncomingECSByIP(ECSTest):
- _confdir = 'ECSIncomingByIP'
+class IncomingECSByIPTest(ECSTest):
+ _confdir = 'IncomingECSByIP'
_config_template = """edns-subnet-allow-list=%s.21
use-incoming-edns-subnet=yes
self.sendECSQuery(query, expected)
-class testECSIPMismatch(ECSTest):
+class ECSIPMismatchTest(ECSTest):
_confdir = 'ECSIPMismatch'
_config_template = """edns-subnet-allow-list=192.0.2.1
query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
self.sendECSQuery(query, expected)
-class testECSWithProxyProtocoldRecursorTest(ECSTest):
- _confdir = 'ECSWithProxyProtocol'
+class ECSWithProxyProtocolRecursorTest(ECSTest):
+ _confdir = 'ECSWithProxyProtocolRecursor'
_config_template = """
ecs-add-for=2001:db8::1/128
edns-subnet-allow-list=ecs-echo.example.
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertRRsetInAnswer(res, expected)
-class testTooLargeToAddZeroScope(RecursorTest):
+class TooLargeToAddZeroScopeTest(RecursorTest):
_confdir = 'TooLargeToAddZeroScope'
_config_template = """
@classmethod
def generateRecursorConfig(cls, confdir):
- super(testTooLargeToAddZeroScope, cls).generateRecursorConfig(confdir)
+ super(TooLargeToAddZeroScopeTest, cls).generateRecursorConfig(confdir)
def testTooLarge(self):
qname = 'toolarge.ecs.'
self.assertEqual(message.edns, -1)
-class EDNSBufferTest16801680(EDNSBufferTest):
+class EDNSBuffer16801680Test(EDNSBufferTest):
"""
Runs test cases 1, 2, 5, 6, 7, 8
"""
+ _confdir = 'EDNSBuffer16801680'
def testEdnsBufferTestCase01(self):
query = self.getMessage('01', 4096)
message = dns.message.from_wire(raw)
self.checkEDNS(message, 512)
-class EDNSBufferTest16801681(EDNSBufferTest):
+class EDNSBuffer16801681Test(EDNSBufferTest):
"""
Runs test case 3
"""
self.checkEDNS(message, 512)
-class EDNSBufferTest16801679(EDNSBufferTest):
+class EDNSBuffer16801679Test(EDNSBufferTest):
"""
Runs test case 4
"""
class RecursorEDNSPaddingTest(RecursorTest):
+ _confdir = 'RecursorEDNSPadding'
+
@classmethod
def setUpClass(cls):
cls.setUpSockets()
class PaddingNotAllowedAlwaysTest(RecursorEDNSPaddingTest):
- _confdir = 'PaddingAlwaysNotAllowed'
+ _confdir = 'PaddingNotAllowedAlways'
_config_template = """edns-padding-from=127.0.0.2
edns-padding-mode=always
edns-padding-tag=7830
# we use the default tag (0) for padded responses, which will cause
# the same packet cache entry (with padding ) to be returned to a client
# not allowed by the edns-padding-from list
- _confdir = 'PaddingAlwaysSameTag'
+ _confdir = 'PaddingAllowedAlwaysSameTag'
_config_template = """edns-padding-from=127.0.0.1
edns-padding-mode=always
edns-padding-tag=0
from recursortests import RecursorTest
-class testExpired(RecursorTest):
+class ExpiredTest(RecursorTest):
"""This regression test starts the authoritative servers with a clock that is
set 15 days into the past. Hence, the recursor must reject the signatures
because they are expired.
self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
-class testExpiredWithEDE(RecursorTest):
+class ExpiredWithEDETest(RecursorTest):
"""This regression test starts the authoritative servers with a clock that is
set 15 days into the past. Hence, the recursor must reject the signatures
because they are expired.
from recursortests import RecursorTest
-class ExtendedErrorsRecursorTest(RecursorTest):
+class ExtendedErrorsTest(RecursorTest):
_confdir = 'ExtendedErrors'
_config_template = """
*.rpz.extended.zone.rpz. 60 IN CNAME .
""".format(soa=cls._SOA))
- super(ExtendedErrorsRecursorTest, cls).generateRecursorConfig(confdir)
+ super(ExtendedErrorsTest, cls).generateRecursorConfig(confdir)
- @pytest.mark.skip(reason="sidnlabs no longer serves thiss until further notice")
def testNotIncepted(self):
qname = 'signotincepted.bad-dnssec.wb.sidnlabs.nl.'
query = dns.message.make_query(qname, 'A', want_dnssec=True)
self.assertEqual(res.options[0].otype, 15)
self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(8, b''))
- @pytest.mark.skip(reason="sidnlabs no longer serves thiss until further notice")
def testExpired(self):
qname = 'sigexpired.bad-dnssec.wb.sidnlabs.nl.'
query = dns.message.make_query(qname, 'A', want_dnssec=True)
self.assertEqual(res.options[0].otype, 15)
self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(6, b''))
- @pytest.mark.skip(reason="sidnlabs no longer serves thiss until further notice")
def testBogus(self):
qname = 'bogussig.ok.bad-dnssec.wb.sidnlabs.nl.'
query = dns.message.make_query(qname, 'A', want_dnssec=True)
self.assertEqual(res.options[0].otype, 15)
self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b'Extra text from Lua!'))
-class NoExtendedErrorsRecursorTest(RecursorTest):
+class NoExtendedErrorsTest(RecursorTest):
- _confdir = 'ExtendedErrorsDisabled'
+ _confdir = 'NoExtendedErrors'
_config_template = """
dnssec=validate
extended-resolution-errors=no
@classmethod
def generateRecursorConfig(cls, confdir):
- super(NoExtendedErrorsRecursorTest, cls).generateRecursorConfig(confdir)
+ super(NoExtendedErrorsTest, cls).generateRecursorConfig(confdir)
- @pytest.mark.skip(reason="sidnlabs no longer serves thiss until further notice")
def testNotIncepted(self):
qname = 'signotincepted.bad-dnssec.wb.sidnlabs.nl.'
query = dns.message.make_query(qname, 'A', want_dnssec=True)
from recursortests import RecursorTest
-class TestFlags(RecursorTest):
+class FlagsTest(RecursorTest):
_confdir = 'Flags'
_config_template = """dnssec=%s"""
_config_params = ['_dnssec_setting']
from twisted.internet import reactor
import threading
-class testInterop(RecursorTest):
+class InteropTest(RecursorTest):
_confdir = 'Interop'
_config_template = """dnssec=validate
cls._UDPResponder.setDaemon(True)
cls._UDPResponder.start()
-class testInteropProcess(RecursorTest):
+class InteropProcessTest(RecursorTest):
_confdir = 'InteropProcess'
_config_template = """dnssec=process
from recursortests import RecursorTest
-class testKeepOpenTCP(RecursorTest):
+class KeepOpenTCPTest(RecursorTest):
_confdir = 'KeepOpenTCP'
_config_template = """dnssec=validate
@ 3600 IN SOA {soa}
@ 3600 IN A 192.0.2.88
""".format(soa=cls._SOA))
- super(testKeepOpenTCP, cls).generateRecursorConfig(confdir)
+ super(KeepOpenTCPTest, cls).generateRecursorConfig(confdir)
def sendTCPQueryKeepOpen(cls, sock, query, timeout=2.0):
try:
from recursortests import RecursorTest
-class testLockedCache(RecursorTest):
+class LockedCacheTest(RecursorTest):
"""
Test that a locked cached entry is *not* updated by the same additional encountered in a second query
"""
ttl2 = self.getCacheTTL()
self.assertGreater(ttl1, ttl2)
-class testNotLockedCache(RecursorTest):
+class NotLockedCacheTest(RecursorTest):
"""
Test that a not locked cached entry *is* updated by the same additional encountered in a second query
"""
from recursortests import RecursorTest
class GettagRecursorTest(RecursorTest):
- _confdir = 'LuaGettag'
+ _confdir = 'GettagRecursor'
_config_template = """
log-common-errors=yes
gettag-needs-edns-options=yes
self.assertResponseMatches(query, expected, res)
class GettagRecursorDistributesQueriesTest(GettagRecursorTest):
- _confdir = 'LuaGettagDistributes'
+ _confdir = 'GettagRecursorDistributesQueries'
_config_template = """
log-common-errors=yes
gettag-needs-edns-options=yes
self.transport.write(response.to_wire(), address)
class LuaHooksRecursorTest(RecursorTest):
- _confdir = 'LuaHooks'
+ _confdir = 'LuaHooksRecursor'
_config_template = """
forward-zones=luahooks.example=%s.23
log-common-errors=yes
self.assertRcodeEqual(res, dns.rcode.NOERROR)
class LuaHooksRecursorDistributesTest(LuaHooksRecursorTest):
- _confdir = 'LuaHooksDistributes'
+ _confdir = 'LuaHooksRecursorDistributes'
_config_template = """
forward-zones=luahooks.example=%s.23
log-common-errors=yes
class LuaDNS64Test(RecursorTest):
"""Tests the dq.followupAction("getFakeAAAARecords")"""
- _confdir = 'lua-dns64'
+ _confdir = 'LuaDNS64'
_config_template = """
"""
_lua_dns_script_file = """
- DNS64 should kick in, generating an AAAA
"""
- _confdir = 'gettagffi-rpz-dns64'
+ _confdir = 'GettagFFIDNS64'
_config_template = """
dns64-prefix=64:ff9b::/96
"""
class PDNSRandomTest(RecursorTest):
"""Tests if pdnsrandom works"""
- _confdir = 'pdnsrandom'
+ _confdir = 'PDNSRandom'
_config_template = """
"""
_lua_dns_script_file = """
class PDNSFeaturesTest(RecursorTest):
"""Tests if pdns_features works"""
- _confdir = 'pdnsfeatures'
+ _confdir = 'PDNSFeatures'
_config_template = """
"""
_lua_dns_script_file = """
class PDNSGeneratingAnswerFromGettagTest(RecursorTest):
"""Tests that we can generate answers from gettag"""
- _confdir = 'gettaganswers'
+ _confdir = 'PDNSGeneratingAnswerFromGettag'
_config_template = """
"""
_lua_dns_script_file = """
class PDNSValidationStatesTest(RecursorTest):
"""Tests that we have access to the validation states from Lua"""
- _confdir = 'validation-states-from-lua'
+ _confdir = 'PDNSValidationStates'
_config_template = """
dnssec=validate
"""
"""Tests the interaction between RPZ and followup queries (dns64, followCNAME)
"""
- _confdir = 'policyeventfilter-followup'
+ _confdir = 'PolicyEventFilterOnFollowUp'
_config_template = """
"""
_lua_config_file = """
"""Tests the interaction between followup queries and native dns64
"""
- _confdir = 'policyeventfilter-followup-dns64'
+ _confdir = 'PolicyEventFilterOnFollowUpWithNativeDNS64'
_config_template = """
dns64-prefix=1234::/96
"""
class LuaPostResolveFFITest(RecursorTest):
"""Tests postresolve_ffi interface"""
- _confdir = 'LuaPostResolveFFITest'
+ _confdir = 'LuaPostResolveFFI'
_config_template = """
"""
_lua_dns_script_file = """
import dns
from recursortests import RecursorTest
-class testNTA(RecursorTest):
+class NTATest(RecursorTest):
_confdir = 'NTA'
_config_template = """dnssec=validate"""
import time
from recursortests import RecursorTest
-class testNamedForward(RecursorTest):
+class NamedForwardTest(RecursorTest):
"""
This is forwarding test using a name as target
"""
_confdir = 'NamedForward'
_config_template = """
dnssec=validate
-forward-zones-recurse=.=dns.quad9.net
+forward-zones-recurse=.=dns.quad9.net;dns.google;one.one.one.one
system-resolver-ttl=10
"""
self.assertMatchingRRSIGInAnswer(res, expected)
@unittest.skipUnless('ENABLE_SUDO_TESTS' in os.environ, "sudo is not available")
-class testNamedForwardWithChange(RecursorTest):
+class NamedForwardWithChangeTest(RecursorTest):
"""
This is forwarding test using a name as target and a changing resolve
"""
from recursortests import RecursorTest
-class testNoDS(RecursorTest):
+class NoDSTest(RecursorTest):
_confdir = 'NoDS'
_config_template = """dnssec=validate"""
import dns
from recursortests import RecursorTest
-class testNoDSYAML(RecursorTest):
+class NoDSYAMLTest(RecursorTest):
_confdir = 'NoDSYAML'
_config_template = """
"""
@classmethod
def generateRecursorConfig(cls, confdir):
- super(testNoDSYAML, cls).generateRecursorYamlConfig(confdir, False)
+ super(NoDSYAMLTest, cls).generateRecursorYamlConfig(confdir, False)
def testNoDSInsecure(self):
"""#4430 When the root DS is removed, the result must be Insecure"""
from recursortests import RecursorTest
-class testNotYetValid(RecursorTest):
+class NotYetValidTest(RecursorTest):
"""This regression test starts the authoritative servers with a clock that is
set 15 days into the future. Hence, the recursor must reject the signatures
because they are not yet valid.
from recursortests import RecursorTest
-class NotifyRecursorTest(RecursorTest):
+class NotifyTest(RecursorTest):
_auth_zones = {
'8': {'threads': 1,
e 3600 IN A 192.0.2.42
f 3600 IN CNAME f ; CNAME loop: dirty trick to get a ServFail in an authzone
""".format(soa=cls._SOA))
- super(NotifyRecursorTest, cls).generateRecursorConfig(confdir)
+ super(NotifyTest, cls).generateRecursorConfig(confdir)
def checkRecordCacheMetrics(self, expectedHits, expectedMisses):
headers = {'x-api-key': self._apiKey}
import time
from recursortests import RecursorTest
-class testOOOTCP(RecursorTest):
+class OOOTCPTest(RecursorTest):
_confdir = 'OOOTCP'
_config_template = """dnssec=validate
@classmethod
def generateRecursorConfig(cls, confdir):
- super(testOOOTCP, cls).generateRecursorConfig(confdir)
+ super(OOOTCPTest, cls).generateRecursorConfig(confdir)
def testOOOVeryBasic(self):
expected = {}
from recursortests import RecursorTest
-class PacketCacheRecursorTest(RecursorTest):
+class PacketCacheTest(RecursorTest):
_auth_zones = {
'8': {'threads': 1,
e 3600 IN A 192.0.2.42
f 3600 IN CNAME f ; CNAME loop: dirty trick to get a ServFail in an authzone
""".format(soa=cls._SOA))
- super(PacketCacheRecursorTest, cls).generateRecursorConfig(confdir)
+ super(PacketCacheTest, cls).generateRecursorConfig(confdir)
def checkPacketCacheMetrics(self, expectedHits, expectedMisses):
self.waitForTCPSocket("127.0.0.1", self._wsPort)
raise AssertionError('%s returned an unexpected output. Faulty line is "%s", complete content is "%s"' % (testcmd, line, output))
class BasicPrometheusTest(RecPrometheusTest):
- _confdir = 'Prometheus'
+ _confdir = 'BasicPrometheus'
_wsPort = 8042
_wsTimeout = 2
_wsPassword = 'secretpassword'
# because it doesn't keep the information around.
self.assertTrue(msg.HasField('to'))
self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.to), to)
+ self.assertTrue(msg.HasField('workerId'))
self.assertTrue(msg.HasField('question'))
self.assertTrue(msg.question.HasField('qClass'))
self.assertEqual(msg.question.qClass, qclass)
def checkProtobufResponse(self, msg, protocol, response, initiator='127.0.0.1', receivedSize=None, vstate=dnsmessage_pb2.PBDNSMessage.VState.Indeterminate):
self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
self.checkProtobufBase(msg, protocol, response, initiator, receivedSize=receivedSize)
+ self.assertTrue(msg.HasField('workerId'))
+ self.assertTrue(msg.HasField('packetCacheHit'))
self.assertTrue(msg.HasField('response'))
self.assertTrue(msg.response.HasField('queryTimeSec'))
self.assertTrue(msg.response.HasField('validationState'))
@ 3600 IN SOA {soa}
a 3600 IN A 192.0.2.42
tagged 3600 IN A 192.0.2.84
+taggedtcp 3600 IN A 192.0.2.87
meta 3600 IN A 192.0.2.85
query-selected 3600 IN A 192.0.2.84
answer-selected 3600 IN A 192.0.2.84
This test makes sure that we correctly export queries and response over protobuf with a proxyMapping
"""
- _confdir = 'ProtobufProxyMappingTest'
+ _confdir = 'ProtobufProxyMapping'
_config_template = """
auth-zones=example=configs/%s/example.zone
allow-from=3.4.5.0/24
This test makes sure that we correctly export queries and response over protobuf.
"""
- _confdir = 'ProtobufProxyMappingLogMappedTest'
+ _confdir = 'ProtobufProxyMappingLogMapped'
_config_template = """
auth-zones=example=configs/%s/example.zone
allow-from=3.4.5.0/0"
that the recursor at least connects to the protobuf server.
"""
- _confdir = 'OutgoingProtobuffWithECSMapping'
+ _confdir = 'OutgoingProtobufWithECSMapping'
_config_template = """
# Switch off QName Minimization, it generates much more protobuf messages
# (or make the test much more smart!)
self.checkProtobufTags(msg, tags)
self.checkNoRemainingMessage()
-class ProtobufTagCacheTest(TestRecursorProtobuf):
- """
- This test makes sure that we correctly cache tags (actually not cache them)
- """
-
- _confdir = 'ProtobufTagCache'
- _config_template = """
-auth-zones=example=configs/%s/example.zone""" % _confdir
- _lua_config_file = """
- protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
- """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
- _lua_dns_script_file = """
- function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
- if qname:equal('tagged.example.') then
- return 0, { '' .. math.random() }
- end
- return 0
- end
- """
+class ProtobufTagCacheBase(TestRecursorProtobuf):
+ __test__ = False
def testTagged(self):
name = 'tagged.example.'
ts2 = msg.response.tags[0]
self.assertNotEqual(ts1, ts2)
+ def testTaggedTCP(self):
+ name = 'taggedtcp.example.'
+ expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.87')
+ query = dns.message.make_query(name, 'A', want_dnssec=True)
+ query.flags |= dns.flags.CD
+ res = self.sendTCPQuery(query)
+ self.assertRRsetInAnswer(res, expected)
+
+ msg = self.getFirstProtobufMessage()
+ self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, res)
+ self.assertEqual(len(msg.response.rrs), 1)
+ rr = msg.response.rrs[0]
+ # we have max-cache-ttl set to 15
+ self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
+ self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.87')
+ self.checkNoRemainingMessage()
+ print(msg.response)
+ self.assertEqual(len(msg.response.tags), 1)
+ ts1 = msg.response.tags[0]
+
+ # Again to check PC case
+ res = self.sendTCPQuery(query)
+ self.assertRRsetInAnswer(res, expected)
+
+ msg = self.getFirstProtobufMessage()
+ self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, res)
+ print(msg.response)
+ self.assertEqual(len(msg.response.rrs), 1)
+ rr = msg.response.rrs[0]
+ # time may have passed, so do not check TTL
+ self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=False)
+ self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.87')
+ self.checkNoRemainingMessage()
+ self.assertEqual(len(msg.response.tags), 1)
+ ts2 = msg.response.tags[0]
+ self.assertNotEqual(ts1, ts2)
+
+class ProtobufTagCacheTest(ProtobufTagCacheBase):
+ """
+ This test makes sure that we correctly cache tags (actually not cache them)
+ """
+
+ __test__ = True
+ _confdir = 'ProtobufTagCache'
+ _config_template = """
+auth-zones=example=configs/%s/example.zone""" % _confdir
+ _lua_config_file = """
+ protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
+ """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
+ _lua_dns_script_file = """
+ function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
+ if qname:equal('tagged.example.') or qname:equal('taggedtcp.example.') then
+ return 0, { '' .. math.random() }
+ end
+ return 0
+ end
+ """
+
+class ProtobufTagCacheFFITest(ProtobufTagCacheBase):
+ """
+ This test makes sure that we correctly cache tags (actually not cache them) for the FFI case
+ """
+
+ __test__ = True
+ _confdir = 'ProtobufTagCacheFFI'
+ _config_template = """
+auth-zones=example=configs/%s/example.zone""" % _confdir
+ _lua_config_file = """
+ protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
+ """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
+ _lua_dns_script_file = """
+ local ffi = require("ffi")
+
+ ffi.cdef[[
+ typedef struct pdns_ffi_param pdns_ffi_param_t;
+
+ const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref);
+ void pdns_ffi_param_add_policytag(pdns_ffi_param_t* ref, const char* name);
+ ]]
+
+ function gettag_ffi(obj)
+ qname = ffi.string(ffi.C.pdns_ffi_param_get_qname(obj))
+ if qname == 'tagged.example' or qname == 'taggedtcp.example' then
+ ffi.C.pdns_ffi_param_add_policytag(obj, '' .. math.random())
+ end
+ return 0
+ end
+ """
+
class ProtobufSelectedFromLuaTest(TestRecursorProtobuf):
"""
This test makes sure that we correctly export queries and responses but only if they have been selected from Lua.
function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
if qname:equal('tagged.example.') then
-- tag number, policy tags, data, requestorId, deviceId, deviceName
- return 0, {}, {}, '%s', '%s', '%s'
+ return 0, {}, {}, '%s:'..remote:getPort(), '%s:'..remote:getPort(), '%s:'..remote:getPort()
end
return 0
end
# check the protobuf messages corresponding to the UDP query and answer
msg = self.getFirstProtobufMessage()
self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
- self.checkProtobufIdentity(msg, self._requestorId, self._deviceId.encode('ascii'), self._deviceName)
+ port = ':' + str(msg.fromPort)
+ self.checkProtobufIdentity(msg, self._requestorId + port, (self._deviceId + port).encode('ascii'), self._deviceName + port)
+
+ # then the response
+ msg = self.getFirstProtobufMessage()
+ self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
+ self.assertEqual(len(msg.response.rrs), 1)
+ rr = msg.response.rrs[0]
+ # we have max-cache-ttl set to 15
+ self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
+ self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
+ self.checkProtobufIdentity(msg, self._requestorId + port, (self._deviceId + port).encode('ascii'), self._deviceName + port)
+ self.checkNoRemainingMessage()
+
+ # Again, but now the PC is involved
+ # check the protobuf messages corresponding to the UDP query and answer
+ # Re-init socket so we get a different port
+ self.setUpSockets();
+ res = self.sendUDPQuery(query)
+ msg = self.getFirstProtobufMessage()
+ self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
+ port2 = ':' + str(msg.fromPort)
+ self.assertNotEqual(port, port2)
+ self.checkProtobufIdentity(msg, self._requestorId + port2, (self._deviceId + port2).encode('ascii'), self._deviceName + port2)
# then the response
msg = self.getFirstProtobufMessage()
# we have max-cache-ttl set to 15
self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
- self.checkProtobufIdentity(msg, self._requestorId, self._deviceId.encode('ascii'), self._deviceName)
+ self.checkProtobufIdentity(msg, self._requestorId + port2, (self._deviceId + port2).encode('ascii'), self._deviceName + port2)
self.checkNoRemainingMessage()
class ProtobufTaggedExtraFieldsFFITest(ProtobufTaggedExtraFieldsTest):
typedef struct pdns_ffi_param pdns_ffi_param_t;
const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref);
+ uint16_t pdns_ffi_param_get_remote_port(pdns_ffi_param_t* ref);
void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag);
void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name);
void pdns_ffi_param_set_devicename(pdns_ffi_param_t* ref, const char* name);
function gettag_ffi(obj)
qname = ffi.string(ffi.C.pdns_ffi_param_get_qname(obj))
if qname == 'tagged.example' then
- ffi.C.pdns_ffi_param_set_requestorid(obj, "%s")
- deviceid = "%s"
+ port = ':'..tostring(ffi.C.pdns_ffi_param_get_remote_port(obj))
+ ffi.C.pdns_ffi_param_set_requestorid(obj, "%s"..port)
+ deviceid = "%s"..port
ffi.C.pdns_ffi_param_set_deviceid(obj, string.len(deviceid), deviceid)
- ffi.C.pdns_ffi_param_set_devicename(obj, "%s")
+ ffi.C.pdns_ffi_param_set_devicename(obj, "%s"..port)
end
return 0
end
"""
This test makes sure that we can correctly add extra meta fields (FFI version).
"""
- _confdir = 'ProtobufMetaFFITest'
+ _confdir = 'ProtobufMetaFFI'
_config_template = """
auth-zones=example=configs/%s/example.zone""" % _confdir
_lua_config_file = """
import os
from recursortests import RecursorTest
-class testProxyByTable(RecursorTest):
+class ProxyByTableTest(RecursorTest):
"""
This test makes sure that we correctly use the proxy-mapped address during the ACL check
"""
@ 3600 IN SOA {soa}
@ 3600 IN A 192.0.2.88
""".format(soa=cls._SOA))
- super(testProxyByTable, cls).generateRecursorConfig(confdir)
+ super(ProxyByTableTest, cls).generateRecursorConfig(confdir)
def testA(self):
import struct
import sys
import time
+import requests
try:
range = xrange
from recursortests import RecursorTest
from proxyprotocol import ProxyProtocol
-class ProxyProtocolRecursorTest(RecursorTest):
+class ProxyProtocolTest(RecursorTest):
@classmethod
def setUpClass(cls):
def tearDownClass(cls):
cls.tearDownRecursor()
-class ProxyProtocolAllowedRecursorTest(ProxyProtocolRecursorTest):
- _confdir = 'ProxyProtocol'
+class ProxyProtocolAllowedTest(ProxyProtocolTest):
+ _confdir = 'ProxyProtocolAllowed'
+ _wsPort = 8042
+ _wsTimeout = 2
+ _wsPassword = 'secretpassword'
+ _apiKey = 'secretapikey'
_lua_dns_script_file = """
function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp, proxyProtocolValues)
dq:addAnswer(pdns.A, '192.0.2.1', 60)
return true
end
- """ % (ProxyProtocolRecursorTest._recursorPort, ProxyProtocolRecursorTest._recursorPort)
+ """ % (ProxyProtocolTest._recursorPort, ProxyProtocolTest._recursorPort)
_config_template = """
proxy-protocol-from=127.0.0.1
proxy-protocol-maximum-size=512
allow-from=127.0.0.0/24, ::1/128, ::42/128
-""" % ()
+ webserver=yes
+ webserver-port=%d
+ webserver-address=127.0.0.1
+ webserver-password=%s
+api-key=%s
+
+""" % (_wsPort, _wsPassword, _apiKey)
+
+ def checkStats(self, expected127001):
+ headers = {'x-api-key': self._apiKey}
+ url = 'http://127.0.0.1:' + str(self._wsPort) + '/jsonstat?command=get-remote-ring&name=remotes'
+ r = requests.get(url, headers=headers, timeout=self._wsTimeout)
+ self.assertTrue(r)
+ self.assertEqual(r.status_code, 200)
+ self.assertTrue(r.json())
+ content = r.json()
+ # We allow all kind of entries, but 127.0.0.1 must have the given value, due to the
+ # testLocalProxyProtocol test, which actually does not set a source address. If we see a
+ # higher value than expected, some ProxyProtocol clients were accounted as 127.0.0.1, which
+ # is not right as all other tests set a source addres other than 127.0.0.1
+ for entry in content['entries']:
+ if entry[1] == '127.0.0.1':
+ self.assertEqual(entry[0], expected127001)
def testLocalProxyProtocol(self):
qname = 'local.proxy-protocol.recursor-tests.powerdns.com.'
res = dns.message.from_wire(data)
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertRRsetInAnswer(res, expected)
+ self.checkStats(1)
# TCP
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
res = dns.message.from_wire(data)
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertRRsetInAnswer(res, expected)
+ self.checkStats(2)
def testInvalidMagicProxyProtocol(self):
qname = 'invalid-magic.proxy-protocol.recursor-tests.powerdns.com.'
self.assertEqual(count, 5)
sock.close()
-class ProxyProtocolAllowedFFIRecursorTest(ProxyProtocolAllowedRecursorTest):
- # same tests than ProxyProtocolAllowedRecursorTest but with the Lua FFI interface instead of the regular one
- _confdir = 'ProxyProtocolFFI'
+class ProxyProtocolAllowedFFITest(ProxyProtocolAllowedTest):
+ # same tests than ProxyProtocolAllowedTest but with the Lua FFI interface instead of the regular one
+ _confdir = 'ProxyProtocolAllowedFFI'
_lua_dns_script_file = """
local ffi = require("ffi")
dq:addAnswer(pdns.A, '192.0.2.1', 60)
return true
end
- """ % (ProxyProtocolAllowedRecursorTest._recursorPort)
+ """ % (ProxyProtocolAllowedTest._recursorPort)
-class ProxyProtocolNotAllowedRecursorTest(ProxyProtocolRecursorTest):
+class ProxyProtocolNotAllowedTest(ProxyProtocolTest):
_confdir = 'ProxyProtocolNotAllowed'
_lua_dns_script_file = """
res = sender(query, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
self.assertEqual(res, None)
-class ProxyProtocolExceptionRecursorTest(ProxyProtocolRecursorTest):
+class ProxyProtocolExceptionTest(ProxyProtocolTest):
_confdir = 'ProxyProtocolException'
_lua_dns_script_file = """
proxy-protocol-from=127.0.0.1/32
proxy-protocol-exceptions=127.0.0.1:%d
allow-from=127.0.0.0/24, ::1/128
-""" % (ProxyProtocolRecursorTest._recursorPort)
+""" % (ProxyProtocolTest._recursorPort)
def testNoHeaderProxyProtocol(self):
qname = 'no-header.proxy-protocol-not-allowed.recursor-tests.powerdns.com.'
import os
from recursortests import RecursorTest
-class testRDNotAllowed(RecursorTest):
- _confdir = 'RDFlagNotAllowed'
+class RDNotAllowedTest(RecursorTest):
+ _confdir = 'RDNotAllowed'
_config_template = """
"""
self.assertRcodeEqual(res, dns.rcode.REFUSED)
self.assertAnswerEmpty(res)
-class testRDAllowed(RecursorTest):
- _confdir = 'RDFlagAllowed'
+class RDAllowedTest(RecursorTest):
+ _confdir = 'RDAllowed'
_config_template = """
disable-packetcache=yes
self.assertEqual(res.opcode(), 4)
self.assertEqual(res.question[0].to_text(), 'zone.rpz. IN SOA')
- def assertAdditionalHasSOA(self, msg):
+ def assertAdditionalHasSOA(self, msg, name):
if not isinstance(msg, dns.message.Message):
raise TypeError("msg is not a dns.message.Message but a %s" % type(msg))
found = False
for rrset in msg.additional:
- if rrset.rdtype == dns.rdatatype.SOA:
+ if rrset.rdtype == dns.rdatatype.SOA and str(rrset.name) == name:
found = True
break
if not found:
- raise AssertionError("No SOA record found in the authority section:\n%s" % msg.to_text())
+ raise AssertionError("No %s SOA record found in the additional section:\n%s" % (name, msg.to_text()))
- def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=False):
+ def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=None):
query = dns.message.make_query(name, 'A', want_dnssec=True)
query.flags |= dns.flags.CD
if adQuery:
self.assertRRsetInAnswer(res, expected)
if soa:
- self.assertAdditionalHasSOA(res)
+ self.assertAdditionalHasSOA(res, soa)
if singleCheck:
break
def checkNotBlocked(self, name, adQuery=False, singleCheck=False):
self.checkBlocked(name, False, adQuery, singleCheck)
- def checkCustom(self, qname, qtype, expected, soa=False):
+ def checkCustom(self, qname, qtype, expected, soa=None):
query = dns.message.make_query(qname, qtype, want_dnssec=True)
query.flags |= dns.flags.CD
for method in ("sendUDPQuery", "sendTCPQuery"):
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertRRsetInAnswer(res, expected)
if soa:
- self.assertAdditionalHasSOA(res)
+ self.assertAdditionalHasSOA(res, soa)
- def checkNoData(self, qname, qtype, soa=False):
+ def checkNoData(self, qname, qtype, soa=None):
query = dns.message.make_query(qname, qtype, want_dnssec=True)
query.flags |= dns.flags.CD
for method in ("sendUDPQuery", "sendTCPQuery"):
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertEqual(len(res.answer), 0)
if soa:
- self.assertAdditionalHasSOA(res)
+ self.assertAdditionalHasSOA(res, soa)
def checkNXD(self, qname, qtype='A'):
query = dns.message.make_query(qname, qtype, want_dnssec=True)
self.assertEqual(len(res.answer), 0)
self.assertEqual(len(res.authority), 1)
- def checkTruncated(self, qname, qtype='A', soa=False):
+ def checkTruncated(self, qname, qtype='A', soa=None):
query = dns.message.make_query(qname, qtype, want_dnssec=True)
query.flags |= dns.flags.CD
res = self.sendUDPQuery(query)
self.assertEqual(len(res.answer), 0)
self.assertEqual(len(res.authority), 0)
if soa:
- self.assertAdditionalHasSOA(res)
+ self.assertAdditionalHasSOA(res, soa)
res = self.sendTCPQuery(query)
self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
-- The first server is a bogus one, to test that we correctly fail over to the second one
rpzMaster({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=1, includeSOA=true})
""" % (rpzServerPort)
- _confdir = 'RPZXFR'
+ _confdir = 'RPZXFRRecursor'
_wsPort = 8042
_wsTimeout = 2
_wsPassword = 'secretpassword'
# first zone, only a should be blocked
self.waitUntilCorrectSerialIsLoaded(1)
self.checkRPZStats(1, 1, 1, self._xfrDone)
- self.checkBlocked('a.example.', soa=True)
+ self.checkBlocked('a.example.', soa='zone.rpz.')
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.sendNotify()
self.waitUntilCorrectSerialIsLoaded(2)
self.checkRPZStats(2, 2, 1, self._xfrDone)
- self.checkBlocked('a.example.', soa=True)
- self.checkBlocked('b.example.', soa=True)
+ self.checkBlocked('a.example.', soa='zone.rpz.')
+ self.checkBlocked('b.example.', soa='zone.rpz.')
self.checkNotBlocked('c.example.')
# third zone, only b should be blocked
self.waitUntilCorrectSerialIsLoaded(3)
self.checkRPZStats(3, 1, 1, self._xfrDone)
self.checkNotBlocked('a.example.')
- self.checkBlocked('b.example.', soa=True)
+ self.checkBlocked('b.example.', soa='zone.rpz.')
self.checkNotBlocked('c.example.')
# fourth zone, only c should be blocked
self.checkRPZStats(4, 1, 1, self._xfrDone)
self.checkNotBlocked('a.example.')
self.checkNotBlocked('b.example.')
- self.checkBlocked('c.example.', soa=True)
+ self.checkBlocked('c.example.', soa='zone.rpz.')
# fifth zone, we should get a full AXFR this time, and only d should be blocked
self.sendNotify()
self.checkNotBlocked('a.example.')
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
- self.checkBlocked('d.example.', soa=True)
+ self.checkBlocked('d.example.', soa='zone.rpz.')
# sixth zone, only e should be blocked, f is a local data record
self.sendNotify()
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
- self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa=True)
+ self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa='zone.rpz.')
self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'))
- self.checkNoData('e.example.', 'AAAA', soa=True)
- self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
+ self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
+ self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
# seventh zone, e should only have one A
self.sendNotify()
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
- self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa=True)
- self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa=True)
- self.checkNoData('e.example.', 'AAAA', soa=True)
- self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
+ self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa='zone.rpz.')
+ self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa='zone.rpz.')
+ self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
+ self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
# check that the policy is disabled for AD=1 queries
self.checkNotBlocked('e.example.', True)
# check non-custom policies
- self.checkTruncated('tc.example.', soa=True)
+ self.checkTruncated('tc.example.', soa='zone.rpz.')
self.checkDropped('drop.example.')
# eighth zone, all entries should be gone
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
self.checkNotBlocked('e.example.')
- self.checkBlocked('f.example.', soa=True)
+ self.checkBlocked('f.example.', soa='zone.rpz.')
self.checkNXD('tc.example.')
self.checkNXD('drop.example.')
self.checkNotBlocked('d.example.')
self.checkNotBlocked('e.example.')
self.checkNXD('f.example.')
- self.checkBlocked('g.example.', soa=True)
+ self.checkBlocked('g.example.', soa='zone.rpz.')
self.checkNXD('tc.example.')
self.checkNXD('drop.example.')
This test makes sure that we correctly load RPZ zones from a file
"""
- _confdir = 'RPZFile'
+ _confdir = 'RPZFileRecursor'
_lua_config_file = """
rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", includeSOA=true })
""" % (_confdir)
def testRPZ(self):
self.checkCustom('a.example.', 'A', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42', '192.0.2.43'))
self.checkCustom('a.example.', 'TXT', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'TXT', '"some text"'))
- self.checkBlocked('z.example.', soa=True)
+ self.checkBlocked('z.example.', soa='zone.rpz.')
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
# check that the policy is disabled for AD=1 queries
self.checkNotBlocked('z.example.', True)
# check non-custom policies
- self.checkTruncated('tc.example.', soa=True)
+ self.checkTruncated('tc.example.', soa='zone.rpz.')
self.checkDropped('drop.example.')
class RPZFileDefaultPolRecursorTest(RPZRecursorTest):
This test makes sure that we correctly load RPZ zones from a file with a default policy
"""
- _confdir = 'RPZFileDefaultPolicy'
+ _confdir = 'RPZFileDefaultPolRecursor'
_lua_config_file = """
rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", defpol=Policy.NoAction })
""" % (_confdir)
This test makes sure that we correctly load RPZ zones from a file with a default policy, not overriding local data entries
"""
- _confdir = 'RPZFileDefaultPolicyNotOverrideLocal'
+ _confdir = 'RPZFileDefaultPolNotOverrideLocalRecursor'
_lua_config_file = """
rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", defpol=Policy.NoAction, defpolOverrideLocalData=false })
""" % (_confdir)
This test makes sure that the recursor respects the RPZ ordering precedence rules
"""
- _confdir = 'RPZOrderingPrecedence'
+ _confdir = 'RPZOrderingPrecedenceRecursor'
_lua_config_file = """
rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz."})
rpzFile('configs/%s/zone2.rpz', { policyName="zone2.rpz."})
This test makes sure that we correctly load RPZ zones from a file while being modified by Lua callbacks
"""
- _confdir = 'RPZFileModByLua'
+ _confdir = 'RPZFileModByLuaRecursor'
_lua_dns_script_file = """
function preresolve(dq)
if dq.qname:equal('zmod.example.') then
_wsTimeout = 2
_wsPassword = 'secretpassword'
_apiKey = 'secretapikey'
- _confdir = 'RPZIncomplete'
+ _confdir = 'RPZIncompleteRecursor'
_auth_zones = {
'8': {'threads': 1,
'zones': ['ROOT']},
-- The first server is a bogus one, to test that we correctly fail over to the second one
rpzMaster({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=1 })
""" % (badrpzServerPort)
- _confdir = 'RPZXFRIncomplete'
+ _confdir = 'RPZXFRIncompleteRecursor'
_wsPort = 8042
_wsTimeout = 2
_wsPassword = 'secretpassword'
from recursortests import RecursorTest
-class testReadTrustAnchorsFromFile(RecursorTest):
- _confdir = 'ReadTAsFromFile'
+class ReadTrustAnchorsFromFileTest(RecursorTest):
+ _confdir = 'ReadTrustAnchorsFromFile'
_config_template = """dnssec=validate"""
_lua_config_file = """clearTA()
import struct
import sys
import threading
+import time
import dns
import dnstap_pb2
from unittest import SkipTest
self.assertNotEqual(res, None)
# We don't expect anything
+ time.sleep(1)
self.assertTrue(DNSTapServerParameters.queue.empty())
class DNSTapLogNODTest(TestRecursorDNSTap):
that the recursor at least connects to the DNSTap server.
"""
- _confdir = 'DNSTapLogNODQueries'
+ _confdir = 'DNSTapLogNOD'
_config_template = """
new-domain-tracking=yes
new-domain-history-dir=configs/%s/nod
return dnstap
def testA(self):
- name = 'www.example.org.'
+ name = 'types.example.'
query = dns.message.make_query(name, 'A', want_dnssec=True)
query.flags |= dns.flags.RD
res = self.sendUDPQuery(query)
class DNSTapLogUDRTest(TestRecursorDNSTap):
- _confdir = 'DNSTapLogUDRResponses'
+ _confdir = 'DNSTapLogUDR'
_config_template = """
new-domain-tracking=yes
new-domain-history-dir=configs/%s/nod
class DNSTapLogNODUDRTest(TestRecursorDNSTap):
- _confdir = 'DNSTapLogNODUDRs'
+ _confdir = 'DNSTapLogNODUDR'
_config_template = """
new-domain-tracking=yes
new-domain-history-dir=configs/%s/nod
if outgoing1 == outgoing2:
break
-class testRootNXTrustDisabled(RootNXTrustRecursorTest):
+class RootNXTrustDisabledTest(RootNXTrustRecursorTest):
_confdir = 'RootNXTrustDisabled'
_wsPort = 8042
_wsTimeout = 2
self.assertEqual(res.edns, 0)
self.assertEqual(len(res.options), 0)
-class testRootNXTrustEnabled(RootNXTrustRecursorTest):
+class RootNXTrustEnabledTest(RootNXTrustRecursorTest):
_confdir = 'RootNXTrustEnabled'
_wsPort = 8042
_wsTimeout = 2
cls.tearDownRecursor()
os.unlink('tagfile')
-class testRoutingTag(RoutingTagTest):
+class RoutingTagTest(RoutingTagTest):
_confdir = 'RoutingTag'
_config_template = """
print(e.output)
raise
-class testRoutingTagFFI(RoutingTagTest):
+class RoutingTagFFITest(RoutingTagTest):
_confdir = 'RoutingTagFFI'
_config_template = """
from recursortests import RecursorTest
-class TestSNMP(RecursorTest):
+class SNMPTest(RecursorTest):
_snmpTimeout = 2.0
_snmpServer = '127.0.0.1'
"""
def _checkStatsValues(self, results):
- count = 148
+ count = 152
for i in list(range(1, count)):
oid = self._snmpOID + '.1.' + str(i) + '.0'
self.assertTrue(oid in results)
import os
from recursortests import RecursorTest
-class testServerNames(RecursorTest):
+class ServerNamesTest(RecursorTest):
"""
This tests all kinds naming things
"""
import os
from recursortests import RecursorTest
-class testSimple(RecursorTest):
+class SimpleTest(RecursorTest):
_confdir = 'Simple'
_config_template = """dnssec=validate
@ 3600 IN SOA {soa}
@ 3600 IN A 192.0.2.88
""".format(soa=cls._SOA))
- super(testSimple, cls).generateRecursorConfig(confdir)
+ super(SimpleTest, cls).generateRecursorConfig(confdir)
def testSOAs(self):
for zone in ['.', 'example.', 'secure.example.']:
import subprocess
from recursortests import RecursorTest
-class testSimpleDoT(RecursorTest):
+class SimpleDoTTest(RecursorTest):
"""
This tests DoT to auth server in a very basic way and is dependent on powerdns.com nameservers having DoT enabled.
"""
import subprocess
from recursortests import RecursorTest
-class testSimpleForwardOverDoT(RecursorTest):
+class SimpleForwardOverDoTTest(RecursorTest):
"""
- This is forwarding to a DoT server in a very basic way and is dependent on Quad9 working
+ This is forwarding to DoT servers in a very basic way and is dependent on the forwards working for DoT
"""
_confdir = 'SimpleForwardOverDoT'
_config_template = """
dnssec=validate
-forward-zones-recurse=.=9.9.9.9:853
+forward-zones-recurse=.=1.1.1.1:853;8.8.8.8:853;9.9.9.9:853
devonly-regression-test-mode
"""
import os
from recursortests import RecursorTest
-class testSimpleTCP(RecursorTest):
+class SimpleTCPTest(RecursorTest):
_confdir = 'SimpleTCP'
_config_template = """dnssec=validate
@ 3600 IN SOA {soa}
@ 3600 IN A 192.0.2.88
""".format(soa=cls._SOA))
- super(testSimpleTCP, cls).generateRecursorConfig(confdir)
+ super(SimpleTCPTest, cls).generateRecursorConfig(confdir)
def testSOAs(self):
for zone in ['.', 'example.', 'secure.example.']:
import os
from recursortests import RecursorTest
-class testSimpleYAML(RecursorTest):
+class SimpleYAMLTest(RecursorTest):
_confdir = 'SimpleYAML'
_config_template = """
@ 3600 IN SOA {soa}
@ 3600 IN A 192.0.2.88
""".format(soa=cls._SOA))
- super(testSimpleYAML, cls).generateRecursorYamlConfig(confdir)
+ super(SimpleYAMLTest, cls).generateRecursorYamlConfig(confdir)
def testSOAs(self):
for zone in ['.', 'example.', 'secure.example.']:
from recursortests import RecursorTest
-class testSortlist(RecursorTest):
+class SortlistTest(RecursorTest):
_confdir = 'Sortlist'
_config_template = """dnssec=off"""
self.assertEqual(indexCNAME, 0)
self.assertGreater(indexMX, 0)
- self.assertEqual(recordsA, ['17.238.240.5', '17.38.42.80', '192.168.0.1'])
\ No newline at end of file
+ self.assertEqual(recordsA, ['17.238.240.5', '17.38.42.80', '192.168.0.1'])
import os
from recursortests import RecursorTest
-class testBogusMaxTTL(RecursorTest):
+class BogusMaxTTLTest(RecursorTest):
_confdir = 'BogusMaxTTL'
_config_template = """dnssec=validate
import subprocess
from recursortests import RecursorTest
-class testTraceFail(RecursorTest):
+class TraceFailTest(RecursorTest):
_confdir = 'TraceFail'
_config_template = """
from recursortests import RecursorTest
-class testTrustAnchorsEnabled(RecursorTest):
+class TrustAnchorsEnabledTest(RecursorTest):
"""This test will do a query for "trustanchor.server CH TXT" and hopes to get
a proper answer"""
self.assertRRsetInAnswer(result, expected)
-class testTrustAnchorsDisabled(RecursorTest):
+class TrustAnchorsDisabledTest(RecursorTest):
"""This test will do a query for "trustanchor.server CH TXT" and hopes to get
a proper answer"""
from recursortests import RecursorTest
-class testZTC(RecursorTest):
+class ZTCTest(RecursorTest):
_confdir = 'ZTC'
_config_template = """
from basicDNSSEC import BasicDNSSEC
import unittest
-class basicNSEC(BasicDNSSEC):
+class basicNSECTest(BasicDNSSEC):
__test__ = True
_confdir = 'basicNSEC'
import os
import subprocess
-class basicNSEC3(BasicDNSSEC):
+class basicNSEC3Test(BasicDNSSEC):
__test__ = True
_confdir = 'basicNSEC3'
case $context in
bind)
cat > pdns-bind.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=bind
bind-config=./named.conf
bind-ignore-broken-records=yes
__EOF__
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
--config-name=bind --socket-dir=./ --no-shuffle \
--cache-ttl=$cachettl --dname-processing \
--disable-axfr-rectify=yes &
bind-dnssec | bind-dnssec-nsec3 | bind-hybrid-nsec3 | bind-dnssec-nsec3-optout | bind-dnssec-nsec3-narrow)
rm -f dnssec.sqlite3
cat > pdns-bind.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=bind
bind-config=./named.conf
bind-ignore-broken-records=yes
skipreasons="nodyndns noalias nsec"
fi
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
--config-name=bind --socket-dir=./ --no-shuffle \
--cache-ttl=$cachettl --dname-processing \
--disable-axfr-rectify=yes $lua_prequery &
start_master ()
{
- case $context in
- bind*)
- source ./backends/bind-master
- ;;
- geoip*)
- source ./backends/geoip-master
- ;;
- gmysql*)
- source ./backends/gmysql-master
- ;;
-
- godbc_mssql*)
- [ -z $GODBC_MSSQL_DSN ] && echo '$GODBC_MSSQL_DSN must be set' >&2 && exit 1
- [ -z $GODBC_MSSQL_USERNAME ] && echo '$GODBC_MSSQL_USERNAME must be set' >&2 && exit 1
- [ -z $GODBC_MSSQL_PASSWORD ] && echo '$GODBC_MSSQL_PASSWORD must be set' >&2 && exit 1
- source ./backends/godbc_mssql-master
- ;;
-
- godbc_sqlite3*)
- [ -z $GODBC_SQLITE3_DSN ] && echo '$GODBC_SQLITE3_DSN must be set' >&2 && exit 1
- source ./backends/godbc_sqlite3-master
- ;;
-
- gpgsql*)
- source ./backends/gpgsql-master
- ;;
-
- gsqlite3*)
- source ./backends/gsqlite3-master
- ;;
-
- lmdb*)
- source ./backends/lmdb-master
- ;;
-
- remote*)
- source ./backends/remote-master
- ;;
-
- tinydns*)
- source ./backends/tinydns-master
- ;;
-
- ldap*)
- source ./backends/ldap-master
- ;;
-
- lua2*)
- source ./backends/lua2-master
- ;;
-
- ext-nsd*)
- source ./ext/nsd-master
- ;;
-
- ext-bind*)
- source ./ext/bind-master
- ;;
-
- *)
- nocontext=yes
- esac
-
- if [ "$nocontext" == "yes" ]
- then
- echo unknown context $context
- : > passed_tests
- echo 'unknown-context-'"$context" > failed_tests
- ./toxml $context
- exit
- fi
+ case $context in
+ bind*)
+ source ./backends/bind-master
+ ;;
+ geoip*)
+ source ./backends/geoip-master
+ ;;
+ gmysql*)
+ source ./backends/gmysql-master
+ ;;
+
+ godbc_mssql*)
+ [ -z $GODBC_MSSQL_DSN ] && echo '$GODBC_MSSQL_DSN must be set' >&2 && exit 1
+ [ -z $GODBC_MSSQL_USERNAME ] && echo '$GODBC_MSSQL_USERNAME must be set' >&2 && exit 1
+ [ -z $GODBC_MSSQL_PASSWORD ] && echo '$GODBC_MSSQL_PASSWORD must be set' >&2 && exit 1
+ source ./backends/godbc_mssql-master
+ ;;
+
+ godbc_sqlite3*)
+ [ -z $GODBC_SQLITE3_DSN ] && echo '$GODBC_SQLITE3_DSN must be set' >&2 && exit 1
+ source ./backends/godbc_sqlite3-master
+ ;;
+
+ gpgsql*)
+ source ./backends/gpgsql-master
+ ;;
+
+ gsqlite3*)
+ source ./backends/gsqlite3-master
+ ;;
+
+ lmdb*)
+ source ./backends/lmdb-master
+ ;;
+
+ remote*)
+ source ./backends/remote-master
+ ;;
+
+ tinydns*)
+ source ./backends/tinydns-master
+ ;;
+
+ ldap*)
+ source ./backends/ldap-master
+ ;;
+
+ lua2*)
+ source ./backends/lua2-master
+ ;;
+
+ ext-nsd*)
+ source ./ext/nsd-master
+ ;;
+
+ ext-bind*)
+ source ./ext/bind-master
+ ;;
+
+ *)
+ nocontext=yes
+ esac
+
+ if [ "$nocontext" == "yes" ]
+ then
+ echo unknown context $context
+ : > passed_tests
+ echo 'unknown-context-'"$context" > failed_tests
+ ./toxml $context
+ exit
+ fi
}
start_slave ()
{
- skipreasons="$skipreasons presigned nodyndns"
-
- case $presignedcontext in
- bind*)
- source ./backends/bind-slave
- ;;
-
- gmysql*)
- source ./backends/gmysql-slave
- ;;
-
- godbc_mssql*)
- [ -z $GODBC_MSSQL2_DSN ] && echo '$GODBC_MSSQL2_DSN must be set' >&2 && exit 1
- [ -z $GODBC_MSSQL2_USERNAME ] && echo '$GODBC_MSSQL2_USERNAME must be set' >&2 && exit 1
- [ -z $GODBC_MSSQL2_PASSWORD ] && echo '$GODBC_MSSQL2_PASSWORD must be set' >&2 && exit 1
- source ./backends/godbc_mssql-slave
- ;;
-
- gpgsql*)
- source ./backends/gpgsql-slave
- ;;
-
- gsqlite3*)
- source ./backends/gsqlite3-slave
- ;;
-
- lmdb*)
- source ./backends/lmdb-slave
- ;;
-
- ext-bind*)
- source ./ext/bind-slave
- ;;
-
- ext-nsd*)
- source ./ext/nsd-slave
- ;;
-
- *)
- nocontext=yes
- esac
-
- if [ "$nocontext" == "yes" ]
- then
- echo unknown presigned context $presignedcontext
- : > passed_tests
- echo 'unknown-presigned-context-'"$presignedcontext" > failed_tests
- ./toxml $context
- exit
- fi
+ skipreasons="$skipreasons presigned nodyndns"
+
+ case $presignedcontext in
+ bind*)
+ source ./backends/bind-slave
+ ;;
+
+ gmysql*)
+ source ./backends/gmysql-slave
+ ;;
+
+ godbc_mssql*)
+ [ -z $GODBC_MSSQL2_DSN ] && echo '$GODBC_MSSQL2_DSN must be set' >&2 && exit 1
+ [ -z $GODBC_MSSQL2_USERNAME ] && echo '$GODBC_MSSQL2_USERNAME must be set' >&2 && exit 1
+ [ -z $GODBC_MSSQL2_PASSWORD ] && echo '$GODBC_MSSQL2_PASSWORD must be set' >&2 && exit 1
+ source ./backends/godbc_mssql-slave
+ ;;
+
+ gpgsql*)
+ source ./backends/gpgsql-slave
+ ;;
+
+ gsqlite3*)
+ source ./backends/gsqlite3-slave
+ ;;
+
+ lmdb*)
+ source ./backends/lmdb-slave
+ ;;
+
+ ext-bind*)
+ source ./ext/bind-slave
+ ;;
+
+ ext-nsd*)
+ source ./ext/nsd-slave
+ ;;
+
+ *)
+ nocontext=yes
+ esac
+
+ if [ "$nocontext" == "yes" ]
+ then
+ echo unknown presigned context $presignedcontext
+ : > passed_tests
+ echo 'unknown-presigned-context-'"$presignedcontext" > failed_tests
+ ./toxml $context
+ exit
+ fi
}
geoipdatabase=${geoipdatabase:-$testsdir/GeoLiteCity.dat}
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
--no-shuffle --launch=geoip \
--cache-ttl=$cachettl --dname-processing --no-config \
--distributor-threads=1 \
--geoip-zones-file=$testsdir/geo.yaml --geoip-database-files="$geoipdatabase" \
- --module-dir=./modules --edns-subnet-processing=yes \
+ --module-dir="$PDNS_BUILD_PATH/modules" --edns-subnet-processing=yes \
$geoipkeydir &
;;
"$GMYSQLDB"
cat > pdns-gmysql.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=gmysql
gmysql-dbname=$GMYSQLDB
gmysql-user=$GMYSQLUSER
# actually terminates
tosql gsqlite | grep -v -E '(COMMIT|TRANSACTION)' | awk '1;!(NR%98){print "go"}' | cat - <(echo go) /dev/null | $BSQLODBC
cat > pdns-godbc_mssql.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=godbc
godbc-datasource=$GODBC_MSSQL_DSN
godbc-username=$GODBC_MSSQL_USERNAME
echo 'ANALYZE; PRAGMA journal_mode=WAL;' | sqlite3 pdns.sqlite3
cat > pdns-godbc_sqlite3.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=godbc
godbc-datasource=$GODBC_SQLITE3_DSN
godbc-get-tsig-keys-query=select name,algorithm, secret from tsigkeys
godbc-publish-domain-key-query=update cryptokeys set published=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?
godbc-id-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=? and domain_id=?
-godbc-info-all-primary-query=select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')
+godbc-info-all-primary-query=select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER') order by domains.id
godbc-info-all-secondaries-query=select domains.id, domains.name, domains.type, domains.master, domains.last_check, records.content from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name where domains.type in ('SLAVE', 'CONSUMER')
godbc-info-zone-query=select id,name,master,last_check,notified_serial,type,options,catalog,account from domains where name=?
godbc-info-producer-members-query=select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0
psql --user="$GPGSQLUSER" -c "ANALYZE" "$GPGSQLDB"
cat > pdns-gpgsql.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=gpgsql
gpgsql-dbname=$GPGSQLDB
gpgsql-user=$GPGSQLUSER
done
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
--config-name=$backend --socket-dir=./ --no-shuffle \
--dnsupdate=yes --resolver=$RESOLVERIP --outgoing-axfr-expand-alias=yes \
--expand-alias=yes \
+ --primary=yes --only-notify="" \
--cache-ttl=$cachettl --dname-processing \
--disable-axfr-rectify=yes $lua_prequery &
echo ANALYZE\; | sqlite3 pdns.sqlite3
cat > pdns-gsqlite3.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=gsqlite3
gsqlite3-database=pdns.sqlite3
consistent-backends
$ZONE2LDAP --dnsttl=yes --basedn=$LDAPBASEDN --layout=$layout --named-conf=named.conf | ldapmodify -D $LDAPUSER -w $LDAPPASSWD -H $LDAPHOST -c > /dev/null || true
cat > pdns-ldap.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=ldap
ldap-basedn=$LDAPBASEDN
ldap-binddn=$LDAPUSER
ldap-host=$LDAPHOST
__EOF__
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
--config-name=ldap --socket-dir=./ --no-shuffle \
--query-logging --dnsupdate=yes \
--expand-alias=yes --outgoing-axfr-expand-alias=yes \
case $context in
lmdb | lmdb-nodnssec | lmdb-nsec3 | lmdb-nsec3-optout | lmdb-nsec3-narrow)
cat > pdns-lmdb.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=lmdb
lmdb-filename=./pdns.lmdb
lmdb-random-ids=yes
for zone in $(grep 'zone ' named.conf | cut -f2 -d\" | grep -v '^nztest.com$')
do
if [ "$zone" = "." ]; then
- $PDNSUTIL --config-dir=. --config-name=lmdb load-zone $zone zones/ROOT
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb load-zone $zone zones/ROOT
else
- $PDNSUTIL --config-dir=. --config-name=lmdb load-zone $zone zones/$zone
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb load-zone $zone zones/$zone
fi
if [ $context != lmdb-nodnssec ]
then
then
if [ $context = lmdb-nsec3 ]
then
- $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone "1 0 1 abcd" 2>&1
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone "1 0 1 abcd" 2>&1
elif [ $context = lmdb-nsec3-optout ]
then
- $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone "1 1 1 abcd" 2>&1
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone "1 1 1 abcd" 2>&1
elif [ $context = lmdb-nsec3-narrow ]
then
- $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone '1 1 1 abcd' narrow 2>&1
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone '1 1 1 abcd' narrow 2>&1
fi
securezone $zone lmdb
if [ $zone = hiddencryptokeys.org ]
then
- keyid=$($PDNSUTIL --config-dir=. --config-name=lmdb list-keys $zone | grep hiddencryptokeys.org | awk '{ print $7 }')
- $PDNSUTIL --config-dir=. --config-name=lmdb unpublish-zone-key $zone $keyid
+ keyid=$($RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb list-keys $zone | grep hiddencryptokeys.org | awk '{ print $7 }')
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb unpublish-zone-key $zone $keyid
fi
if [ $zone = cryptokeys.org ]
then
- $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 384 active unpublished ecdsa384
- $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive published rsasha512
- $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive unpublished rsasha256
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 384 active unpublished ecdsa384
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive published rsasha512
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive unpublished rsasha256
fi
fi
else
- $PDNSUTIL --config-dir=. --config-name=lmdb rectify-zone $zone 2>&1
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb rectify-zone $zone 2>&1
fi
if [ "$zone" = "tsig.com" ]; then
- $PDNSUTIL --config-dir=. --config-name=lmdb import-tsig-key test $ALGORITHM $KEY
- $PDNSUTIL --config-dir=. --config-name=lmdb activate-tsig-key tsig.com test primary
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb import-tsig-key test $ALGORITHM $KEY
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb activate-tsig-key tsig.com test primary
fi
done
# setup catalog zone
- if ! $PDNSUTIL --config-dir=. --config-name=lmdb list-all-zones | grep '^.$' # detect root tests
+ if ! $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb list-all-zones | grep '^.$' # detect root tests
then
for zone in $(grep 'zone ' named.conf | cut -f2 -d\" | grep -v '^nztest.com$')
do
- $PDNSUTIL --config-dir=. --config-name=lmdb set-kind $zone master
- $PDNSUTIL --config-dir=. --config-name=lmdb set-catalog $zone catalog.invalid
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-kind $zone master
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-catalog $zone catalog.invalid
done
- $PDNSUTIL --config-dir=. --config-name=lmdb load-zone catalog.invalid zones/catalog.invalid
- $PDNSUTIL --config-dir=. --config-name=lmdb set-kind catalog.invalid producer
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb load-zone catalog.invalid zones/catalog.invalid
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-kind catalog.invalid producer
- $PDNSUTIL --config-dir=. --config-name=lmdb set-options-json test.com '{"producer":{"coo":"other-catalog.invalid","unique":"123"}}'
- $PDNSUTIL --config-dir=. --config-name=lmdb set-options-json tsig.com '{"producer":{"group":["pdns-group-x","pdns-group-y"]}}'
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-options-json test.com '{"producer":{"coo":"other-catalog.invalid","unique":"123"}}'
+ $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-options-json tsig.com '{"producer":{"group":["pdns-group-x","pdns-group-y"]}}'
fi
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
--config-name=lmdb --socket-dir=./ --no-shuffle \
--dnsupdate=no \
--expand-alias=yes --resolver=$RESOLVERIP \
# generate pdns.conf for pdnsutil
cat > pdns-lua2.conf <<EOF
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=lua2
lua2-filename=$testsdir/$luascript
lua2-api=2
allow-axfr-ips=0.0.0.0/0,::/0
EOF
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
--no-shuffle --launch=lua2 \
--cache-ttl=$cachettl --dname-processing --no-config \
--distributor-threads=1 --zone-cache-refresh-interval=$interval \
extracontexts="dnssec nsec3"
skipreasons="nsec3 nodyndns"
fi
-
+
remote_add_param="--remote-dnssec=yes"
elif [ "$remotesec" = "dnssec" ]
then
# generate pdns.conf for pdnsutil
cat > pdns-remote.conf <<EOF
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
launch=remote
remote-connection-string=$connstr,timeout=10000
EOF
# add DS records into list-all-records
$PDNSUTIL --config-dir=. --config-name=remote show-zone -v up.example.com | gawk '{ if ($1=="DS") { printf "up.example.com. 120 IN DS " $6 " " $7 " " $8 " " substr(toupper($9),0,56); if (length($9)>56) { print " " substr(toupper($9),57) } else { print "" } } }' > $testsdir/list-all-records/expected_dnssec_part2
- cat $testsdir/list-all-records/expected_dnssec_part1 $testsdir/list-all-records/expected_dnssec_part2 $testsdir/list-all-records/expected_dnssec_part3 > $testsdir/list-all-records/expected_result.dnssec
+ cat $testsdir/list-all-records/expected_dnssec_part1 $testsdir/list-all-records/expected_dnssec_part2 $testsdir/list-all-records/expected_dnssec_part3 > $testsdir/list-all-records/expected_result.dnssec
cp -f $testsdir/list-all-records/expected_result.dnssec $testsdir/list-all-records/expected_result.nsec3
fi
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
--no-shuffle --launch=remote \
--cache-ttl=$cachettl --dname-processing --no-config \
--distributor-threads=1 \
--dnsupdate=yes --zone-cache-refresh-interval=0 \
- --remote-connection-string="$connstr" $remote_add_param --module-dir=./modules &
+ --remote-connection-string="$connstr" $remote_add_param --module-dir="$PDNS_BUILD_PATH/modules" &
;;
*)
case $context in
tinydns)
- $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
+ $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
--no-shuffle --launch=tinydns \
--cache-ttl=$cachettl --dname-processing --no-config \
--dnsupdate=yes \
- --tinydns-dbfile=../modules/tinydnsbackend/data.cdb --module-dir=./modules &
+ --tinydns-dbfile=../modules/tinydnsbackend/data.cdb --module-dir="$PDNS_BUILD_PATH/modules" &
skipreasons="nodnssec noent nodyndns nometa noaxfr noalias"
;;
PATH=.:$PATH:/usr/sbin
MAKE=${MAKE:-make}
-export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
-export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
-export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
-export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
-export SDIG=${SDIG:-${PWD}/../pdns/sdig}
-export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
-export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
-export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
-export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
-export ZONE2JSON=${ZONE2JSON:-${PWD}/../pdns/zone2json}
-export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
-export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
-export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+if [ -z "$PDNS_BUILD_PATH" ]; then
+ # PDNS_BUILD_PATH is unset or empty. Assume an autotools build.
+ PDNS_BUILD_PATH=.
+
+ export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
+ export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
+ export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
+ export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
+ export SDIG=${SDIG:-${PWD}/../pdns/sdig}
+ export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
+ export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
+ export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
+ export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
+ export ZONE2JSON=${ZONE2JSON:-${PWD}/../pdns/zone2json}
+ export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
+ export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
+ export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+else
+ export PDNS=${PDNS:-$PDNS_BUILD_PATH/pdns-auth}
+ export PDNS2=${PDNS2:-$PDNS_BUILD_PATH/pdns-auth}
+ export PDNSRECURSOR=${PDNSRECURSOR:-$PDNS_BUILD_PATH/pdns/recursordist/pdns_recursor}
+ export RECCONTROL=${RECCONTROL:-$PDNS_BUILD_PATH/pdns/recursordist/rec_control}
+ export SDIG=${SDIG:-$PDNS_BUILD_PATH/sdig}
+ export NOTIFY=${NOTIFY:-$PDNS_BUILD_PATH/pdns-auth-notify}
+ export NSEC3DIG=${NSEC3DIG:-$PDNS_BUILD_PATH/nsec3dig}
+ export SAXFR=${SAXFR:-$PDNS_BUILD_PATH/saxfr}
+ export ZONE2SQL=${ZONE2SQL:-$PDNS_BUILD_PATH/pdns-zone2sql}
+ export ZONE2JSON=${ZONE2JSON:-$PDNS_BUILD_PATH/pdns-zone2json}
+ export ZONE2LDAP=${ZONE2LDAP:-$PDNS_BUILD_PATH/pdns-zone2ldap}
+ export PDNSUTIL=${PDNSUTIL:-$PDNS_BUILD_PATH/pdns-auth-util}
+ export PDNSCONTROL=${PDNSCONTROL:-$PDNS_BUILD_PATH/pdns-auth-control}
+fi
unset _JAVA_OPTIONS
touch passed_tests failed_tests skipped_tests
-for a in $(find $testsdir -type d | grep -v ^.$ | grep -v .svn | grep -v ^confdir | LC_ALL=C sort)
+for a in $(find $testsdir -type d | grep -v ^.$ | grep -v .svn | grep -v ^confdir | LC_ALL=C sort)
do
if [ ! -x $a/command ]
then
echo "$testname: " >> test-results
cat $a/description >> test-results
-
+
SKIPIT=0
- if [ -e $a/skip ]
+ if [ -e $a/skip ]
then
SKIPIT=1
result=" Skipped test $a"
result=" Skipped test $a because it's not the specified single test"
fi
-
+
if [ $SKIPIT = 1 ]
then
echo $testname >> skipped_tests
done
[ -n "$context" ] && [ -e "$a/expected_result.$context" ] && expected=$a/expected_result.$context
diff ${diffopts} $expected $a/real_result > $a/diff 2>&1
- if [ -s $a/diff ]
+ if [ -s $a/diff ]
then
if [ $FAIL = 0 ]
then
failed=$[$failed+1]
fi
fi
- fi
+ fi
echo "$result"
echo
echo "$result" >> test-results
set -x
fi
-export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
-export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
-export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
-export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
-export SDIG=${SDIG:-${PWD}/../pdns/sdig}
-export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
-export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
-export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
-export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
-export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
-export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
-export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+if [ -z "$PDNS_BUILD_PATH" ]; then
+ # PDNS_BUILD_PATH is unset or empty. Assume an autotools build.
+ PDNS_BUILD_PATH=.
+
+ export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
+ export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
+ export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
+ export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
+ export SDIG=${SDIG:-${PWD}/../pdns/sdig}
+ export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
+ export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
+ export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
+ export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
+ export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
+ export ZONE2JSON=${ZONE2JSON:-${PWD}/../pdns/zone2json}
+ export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
+ export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+else
+ export PDNS=${PDNS:-$PDNS_BUILD_PATH/pdns-auth}
+ export PDNS2=${PDNS2:-$PDNS_BUILD_PATH/pdns-auth}
+ export PDNSRECURSOR=${PDNSRECURSOR:-$PDNS_BUILD_PATH/pdns/recursordist/pdns_recursor}
+ export RECCONTROL=${RECCONTROL:-$PDNS_BUILD_PATH/pdns/recursordist/rec_control}
+ export SDIG=${SDIG:-$PDNS_BUILD_PATH/sdig}
+ export NOTIFY=${NOTIFY:-$PDNS_BUILD_PATH/pdns-auth-notify}
+ export NSEC3DIG=${NSEC3DIG:-$PDNS_BUILD_PATH/nsec3dig}
+ export SAXFR=${SAXFR:-$PDNS_BUILD_PATH/saxfr}
+ export ZONE2SQL=${ZONE2SQL:-$PDNS_BUILD_PATH/pdns-zone2sql}
+ export ZONE2JSON=${ZONE2JSON:-$PDNS_BUILD_PATH/pdns-zone2json}
+ export ZONE2LDAP=${ZONE2LDAP:-$PDNS_BUILD_PATH/pdns-zone2ldap}
+ export PDNSUTIL=${PDNSUTIL:-$PDNS_BUILD_PATH/pdns-auth-util}
+ export PDNSCONTROL=${PDNSCONTROL:-$PDNS_BUILD_PATH/pdns-auth-control}
+fi
+
export RESOLVERIP=${RESOLVERIP:-8.8.8.8}
export FIX_TESTS=${FIX_TESTS:-NO}
-
ALGORITHM=${ALGORITHM:="hmac-md5"}
KEY=${KEY:="kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="}
esac
done; unset -v arg
if [ "$_show_help" -eq 1 ]; then
- grep -v '^#' << '__EOF__'
+ grep -v '^#' << '__EOF__'
Usage: ./start-test-stop <port> [<context>] [wait|nowait] [<cachettl>] [<specifictest>]
* Specifictest can be used to run only one single test.
__EOF__
- exit
+ exit
fi
unset -v _show_help
bindwait ()
{
- check_process
- configname=$1
- domcount=$(grep -c ^zone named.conf)
- if [ ! -x $PDNSCONTROL ]
- then
- echo "No pdns_control found"
- exit
- fi
- loopcount=0
-
- while [ $loopcount -lt 20 ]
- do
- sleep 5
- done=$( ($PDNSCONTROL --config-name=$configname --socket-dir=. --no-config bind-domain-status || true) | grep -c 'parsed into memory' || true )
- if [ $done = $domcount ]
- then
- return
- fi
- let loopcount=loopcount+1
- done
-
- if [ $done != $domcount ]
- then
- echo "Domain parsing failed" >> failed_tests
- fi
+ check_process
+ configname=$1
+ domcount=$(grep -c ^zone named.conf)
+ if [ ! -x $PDNSCONTROL ]
+ then
+ echo "No pdns_control found"
+ exit
+ fi
+ loopcount=0
+
+ while [ $loopcount -lt 20 ]
+ do
+ sleep 5
+ done=$( ($PDNSCONTROL --config-name=$configname --socket-dir=. --no-config bind-domain-status || true) | grep -c 'parsed into memory' || true )
+ if [ $done = $domcount ]
+ then
+ return
+ fi
+ let loopcount=loopcount+1
+ done
+
+ if [ $done != $domcount ]
+ then
+ echo "Domain parsing failed" >> failed_tests
+ fi
}
securezone ()
{
- local zone=$1
- local configname=$2
-
- if [ -n "$configname" ]
- then
- configname="--config-name=$configname"
- fi
- if [ "${zone: 0:16}" = "secure-delegated" ]
- then
- $PDNSUTIL --config-dir=. $configname import-zone-key $zone $zone.private ksk 2>&1
- $PDNSUTIL --config-dir=. $configname add-zone-key $zone rsasha256 1024 zsk active 2>&1
- $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
- $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
- $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
- else
- # check if PKCS#11 should be used
- if [ "$pkcs11" -eq 1 ]; then
- if [ "$slot" == "" ]; then
- slot=0
- else
- slot=$((slot+1))
- fi
- label=pdnstest-${EPOCHSECONDS}-${slot}
- softhsm2-util --delete-token --label $label 2> /dev/null || true
- softhsm2-util --init-token --label $label --free --pin 1234 --so-pin 1234
- kid=`$PDNSUTIL --config-dir=. $configname hsm assign $zone ecdsa256 ksk softhsm2 $label 1234 $label 2>&1 | grep softhsm | awk '{ print $NF }'`
- $PDNSUTIL --config-dir=. $configname hsm create-key $zone $kid
- $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
- else
- $PDNSUTIL --config-dir=. $configname secure-zone $zone 2>&1
- fi
- if [ "${zone: 0:20}" = "cdnskey-cds-test.com" ]; then
- $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
- $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
- fi
- if [ "$zone" = "dnssec-parent.com" ]; then
- $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 0 2>&1
- $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone delete 2>&1
- fi
- fi
+ local zone=$1
+ local configname=$2
+
+ if [ -n "$configname" ]
+ then
+ configname="--config-name=$configname"
+ fi
+ if [ "${zone: 0:16}" = "secure-delegated" ]
+ then
+ $PDNSUTIL --config-dir=. $configname import-zone-key $zone $zone.private ksk 2>&1
+ $PDNSUTIL --config-dir=. $configname add-zone-key $zone rsasha256 1024 zsk active 2>&1
+ $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
+ $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
+ $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
+ else
+ # check if PKCS#11 should be used
+ if [ "$pkcs11" -eq 1 ]; then
+ if [ "$slot" == "" ]; then
+ slot=0
+ else
+ slot=$((slot+1))
+ fi
+ label=pdnstest-${EPOCHSECONDS}-${slot}
+ softhsm2-util --delete-token --label $label 2> /dev/null || true
+ softhsm2-util --init-token --label $label --free --pin 1234 --so-pin 1234
+ kid=`$PDNSUTIL --config-dir=. $configname hsm assign $zone ecdsa256 ksk softhsm2 $label 1234 $label 2>&1 | grep softhsm | awk '{ print $NF }'`
+ $PDNSUTIL --config-dir=. $configname hsm create-key $zone $kid
+ $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
+ else
+ $PDNSUTIL --config-dir=. $configname secure-zone $zone 2>&1
+ fi
+ if [ "${zone: 0:20}" = "cdnskey-cds-test.com" ]; then
+ $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
+ $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
+ fi
+ if [ "$zone" = "dnssec-parent.com" ]; then
+ $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 0 2>&1
+ $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone delete 2>&1
+ fi
+ fi
}
kill_process ()
{
- set +e
- trap - EXIT INT TERM
-
- if [ $1 -gt 1 ]
- then
- echo "exitvalue$1" >> failed_tests
- ./toxml
- ./totar
- fi
-
- pids=$(cat pdns*.pid)
-
- if [ -n "$pids" ]
- then
- kill $pids
- # make sure they die.
- loopcount=0
- done=0
- while [ $loopcount -lt 10 ] && [ $done -eq 0 ]
- do
- done=1
- for pid in $pids
- do
- kill -0 $pid > /dev/null 2>&1
- if [ $? -eq 0 ];
- then
- done=0
- fi
- done
- let loopcount=loopcount+1
- sleep 1
- done
-
- kill -9 $pids
- fi
-
- rm pdns*.pid
- exit $1
+ set +e
+ trap - EXIT INT TERM
+
+ if [ $1 -gt 1 ]
+ then
+ echo "exitvalue$1" >> failed_tests
+ ./toxml
+ ./totar
+ fi
+
+ pids=$(cat pdns*.pid)
+
+ if [ -n "$pids" ]
+ then
+ kill $pids
+ # make sure they die.
+ loopcount=0
+ done=0
+ while [ $loopcount -lt 10 ] && [ $done -eq 0 ]
+ do
+ done=1
+ for pid in $pids
+ do
+ kill -0 $pid > /dev/null 2>&1
+ if [ $? -eq 0 ];
+ then
+ done=0
+ fi
+ done
+ let loopcount=loopcount+1
+ sleep 1
+ done
+
+ kill -9 $pids
+ fi
+
+ rm pdns*.pid
+ exit $1
}
if [ ! -x $PDNS ]
then
- echo "$PDNS is not executable binary"
- exit
+ echo "$PDNS is not executable binary"
+ exit
fi
if [ ! -x $PDNS2 ]
then
- echo "$PDNS2 is not executable binary"
- exit
+ echo "$PDNS2 is not executable binary"
+ exit
fi
address="${PDNS_LISTEN_ADDR:-127.0.0.1}"
# Copy original zones because the test might modify them (well only the dyndns stuff, but let's make this work for others as well)
for zone in $(grep 'zone ' named.conf | cut -f2 -d\")
do
- if [ -f zones/$zone.orig ]
- then
- cp -f zones/$zone.orig zones/$zone
- fi
+ if [ -f zones/$zone.orig ]
+ then
+ cp -f zones/$zone.orig zones/$zone
+ fi
done
rm -f pdns*.pid
if [[ "$context" =~ .+-presigned.* ]]
then
- presigned=yes
- port=$((port-100))
- eval "$(echo "$context" | sed -r 's/(.+)(-presigned)(-(.*))?/context=\1 presignedcontext=\4/')"
- if [ -z "$presignedcontext" ]
- then
- presignedcontext=$context
- fi
+ presigned=yes
+ port=$((port-100))
+ eval "$(echo "$context" | sed -r 's/(.+)(-presigned)(-(.*))?/context=\1 presignedcontext=\4/')"
+ if [ -z "$presignedcontext" ]
+ then
+ presignedcontext=$context
+ fi
fi
if [ "${context: -5}" = "-both" ]
then
- both=yes
- port=$((port-100))
- context=${context%-both}
- presignedcontext=$context
+ both=yes
+ port=$((port-100))
+ context=${context%-both}
+ presignedcontext=$context
fi
optout=0
if [ "${context: -13}" = "-nsec3-optout" ]
then
- optout=1
+ optout=1
fi
if [ "${context: -7}" = "-pkcs11" ]
start_master
if [ "$skiplua" == "1" ]; then
- skipreasons="$skipreasons nolua"
+ skipreasons="$skipreasons nolua"
fi
check_process
dotests () {
- nameserver=127.0.0.1 ./runtests $spectest
- ./toxml
- ./totar
-
- cat ./trustedkeys
-
- if [ -s "./failed_tests" ]
- then
- for t in `cat failed_tests`
- do
- echo -e "\n\n$t"
- cat ${testsdir}/$t/diff
- done
- if [ "${!1}" -eq 0 ]
- then
- eval "$1=1"
- fi
- fi
+ nameserver=127.0.0.1 ./runtests $spectest
+ ./toxml
+ ./totar
+
+ cat ./trustedkeys
+
+ if [ -s "./failed_tests" ]
+ then
+ for t in `cat failed_tests`
+ do
+ echo -e "\n\n$t"
+ cat ${testsdir}/$t/diff
+ done
+ if [ "${!1}" -eq 0 ]
+ then
+ eval "$1=1"
+ fi
+ fi
}
## TODO: give sdig a timeout
if [ $presigned = no ] || [ $both = yes ]
then
- dotests RETVAL
+ dotests RETVAL
fi
if [ $presigned = yes ] || [ $both = yes ]
then
- start_slave
+ start_slave
- export port
- export context
- export skipreasons
- export backend
+ export port
+ export context
+ export skipreasons
+ export backend
- dotests RETVAL
+ dotests RETVAL
fi
if [ "$wait" = "wait" ]
then
- echo tests done! push enter to terminate instance
- read l
+ echo tests done! push enter to terminate instance
+ read l
fi
trap "kill_process $RETVAL" EXIT
)
@task(help={'backend': 'Backend to install test deps for, e.g. gsqlite3; can be repeated'}, iterable=['backend'], optional=['backend'])
-def install_auth_test_deps(c, backend): # FIXME: rename this, we do way more than apt-get
+def install_auth_test_deps_only(c, backend):
extra=[]
for b in backend:
extra.extend(auth_backend_test_deps[b])
c.sudo('DEBIAN_FRONTEND=noninteractive apt-get -y install ' + ' '.join(extra+auth_test_deps))
+@task(help={'backend': 'Backend to install test deps for, e.g. gsqlite3; can be repeated'}, iterable=['backend'], optional=['backend'])
+def install_auth_test_deps(c, backend): # FIXME: rename this, we do way more than apt-get
+ install_auth_test_deps_only(c, backend)
+
c.run('chmod +x /opt/pdns-auth/bin/* /opt/pdns-auth/sbin/*')
# c.run('''if [ ! -e $HOME/bin/jdnssec-verifyzone ]; then
# wget https://github.com/dblacka/jdnssec-tools/releases/download/0.14/jdnssec-tools-0.14.tar.gz
geoip_mmdb = ['geoip'],
)
+backend_rootzone_tests = dict(
+ geoip = False,
+ geoip_mmdb = False,
+ lua2 = False,
+ ldap = False,
+ tinydns = False,
+ remote = False,
+ bind = True,
+ lmdb = True,
+ gmysql = True,
+ gpgsql = True,
+ gsqlite3 = True,
+ godbc_sqlite3 = True,
+ godbc_mssql = True,
+)
+
godbc_mssql_credentials = {"username": "sa", "password": "SAsa12%%-not-a-secret-password"}
godbc_config = f'''
@task
def test_auth_backend(c, backend):
pdns_auth_env_vars = f'PDNS=/opt/pdns-auth/sbin/pdns_server PDNS2=/opt/pdns-auth/sbin/pdns_server SDIG=/opt/pdns-auth/bin/sdig NOTIFY=/opt/pdns-auth/bin/pdns_notify NSEC3DIG=/opt/pdns-auth/bin/nsec3dig SAXFR=/opt/pdns-auth/bin/saxfr ZONE2SQL=/opt/pdns-auth/bin/zone2sql ZONE2LDAP=/opt/pdns-auth/bin/zone2ldap ZONE2JSON=/opt/pdns-auth/bin/zone2json PDNSUTIL=/opt/pdns-auth/bin/pdnsutil PDNSCONTROL=/opt/pdns-auth/bin/pdns_control PDNSSERVER=/opt/pdns-auth/sbin/pdns_server SDIG=/opt/pdns-auth/bin/sdig GMYSQLHOST={auth_backend_ip_addr} GMYSQL2HOST={auth_backend_ip_addr} MYSQL_HOST={auth_backend_ip_addr} PGHOST={auth_backend_ip_addr} PGPORT=5432'
+ backend_env_vars = ''
if backend == 'remote':
ci_auth_install_remotebackend_test_deps(c)
if backend == 'bind':
setup_softhsm(c)
- with c.cd('regression-tests'):
- for variant in backend_regress_tests[backend]:
- c.run(f'{pdns_auth_env_vars} SOFTHSM2_CONF=/opt/pdns-auth/softhsm/softhsm2.conf ./start-test-stop 5300 {variant}')
- return
+ backend_env_vars = 'SOFTHSM2_CONF=/opt/pdns-auth/softhsm/softhsm2.conf'
if backend == 'godbc_sqlite3':
setup_godbc_sqlite3(c)
- with c.cd('regression-tests'):
- for variant in backend_regress_tests[backend]:
- c.run(f'{pdns_auth_env_vars} GODBC_SQLITE3_DSN=pdns-sqlite3-1 ./start-test-stop 5300 {variant}')
- return
+ backend_env_vars = 'GODBC_SQLITE3_DSN=pdns-sqlite3-1'
if backend == 'godbc_mssql':
setup_godbc_mssql(c)
- with c.cd('regression-tests'):
- for variant in backend_regress_tests[backend]:
- c.run(f'{pdns_auth_env_vars} GODBC_MSSQL_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL_DSN=pdns-mssql-docker GODBC_MSSQL2_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL2_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL2_DSN=pdns-mssql-docker ./start-test-stop 5300 {variant}')
- return
+ backend_env_vars = f'GODBC_MSSQL_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL_DSN=pdns-mssql-docker GODBC_MSSQL2_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL2_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL2_DSN=pdns-mssql-docker'
if backend == 'ldap':
setup_ldap_client(c)
if backend == 'geoip_mmdb':
- with c.cd('regression-tests'):
- for variant in backend_regress_tests[backend]:
- c.run(f'{pdns_auth_env_vars} geoipdatabase=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb ./start-test-stop 5300 {variant}')
- return
+ backend_env_vars = 'geoipdatabase=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb'
with c.cd('regression-tests'):
if backend == 'lua2':
c.run('touch trustedkeys') # avoid silly error during cleanup
for variant in backend_regress_tests[backend]:
- c.run(f'{pdns_auth_env_vars} ./start-test-stop 5300 {variant}')
+ c.run(f'{pdns_auth_env_vars} {backend_env_vars} ./start-test-stop 5300 {variant}')
+
+ if backend_rootzone_tests[backend]:
+ with c.cd('regression-tests.rootzone'):
+ for variant in backend_regress_tests[backend]:
+ c.run(f'{pdns_auth_env_vars} {backend_env_vars} ./start-test-stop 5300 {variant}')
if backend == 'gsqlite3':
if os.getenv('SKIP_IPV6_TESTS'):
@task
def ci_build_and_install_quiche(c, repo):
- with open(f'{repo}/builder-support/helpers/quiche.json') as quiche_json:
- quiche_data = json.load(quiche_json)
- quiche_version = quiche_data['version']
- quiche_hash = quiche_data['SHA256SUM']
-
- # we have to pass -L because GitHub will do a redirect, sadly
- c.run(f'curl -L -o quiche-{quiche_version}.tar.gz https://github.com/cloudflare/quiche/archive/{quiche_version}.tar.gz')
- # Line below should echo two spaces between digest and name
- c.run(f'echo {quiche_hash}" "quiche-{quiche_version}.tar.gz | sha256sum -c -')
- c.run(f'tar xf quiche-{quiche_version}.tar.gz')
- with c.cd(f'quiche-{quiche_version}'):
- c.run('cargo build --release --no-default-features --features ffi,boringssl-boring-crate --package quiche')
- # cannot use c.sudo() inside a cd() context, see https://github.com/pyinvoke/invoke/issues/687
- c.run('sudo install -Dm644 quiche/include/quiche.h /usr/include')
- c.run('sudo install -Dm644 target/release/libquiche.so /usr/lib')
- c.run('install -D target/release/libquiche.so /opt/dnsdist/lib/libquiche.so')
- c.run(f"""sudo install -Dm644 /dev/stdin /usr/lib/pkgconfig/quiche.pc <<PC
-# quiche
-Name: quiche
-Description: quiche library
-URL: https://github.com/cloudflare/quiche
-Version: {quiche_version}
-Libs: -lquiche
-PC""")
+ with c.cd(f'{repo}/builder-support/helpers/'):
+ # be careful that rust needs to have been installed system-wide,
+ # as the one installed in GitHub actions' Ubuntu images in /home/runner/.cargo/bin/cargo
+ # is not in the path for the root user (and shouldn't be)
+ c.run(f'sudo {repo}/builder-support/helpers/install_quiche.sh')
+
+ # cannot use c.sudo() inside a cd() context, see https://github.com/pyinvoke/invoke/issues/687
+ c.run('sudo mv /usr/lib/libdnsdist-quiche.so /usr/lib/libquiche.so')
+ c.run("sudo sed -i 's,^Libs:.*,Libs: -lquiche,g' /usr/lib/pkgconfig/quiche.pc")
+ c.run('mkdir -p /opt/dnsdist/lib')
+ c.run('cp /usr/lib/libquiche.so /opt/dnsdist/lib/libquiche.so')
# this is run always
def setup():