rec: Update new b-root-server.net addresses in built-in hints.
---
-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'
+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'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
ANSSI
Antoin
apikey
+apizones
AQAB
ARCHFLAGS
arecord
domainrelatedobject
Donatas
dontcare
+doq
downsides
downstreams
dport
ejones
Ekkelenkamp
elgoog
+endbr
Enden
ent
envoutput
Lutter
Luuk
LYg
+Machard
Maik
Maikel
MAILA
msrv
mtasker
mthread
+mtid
Mulholland
multimaster
munmap
print("No diagnostics or warnings produced by clang-tidy")
return 0
+ gh_step_summary = os.getenv('GITHUB_STEP_SUMMARY')
+ if gh_step_summary:
+ # Print Markdown summary
+ summaryFp = open(gh_step_summary, 'a', encoding='utf-8')
+ print('### clang-tidy summary', file=summaryFp)
+
fixes = fixes["Diagnostics"]
have_warnings = False
for fix in fixes:
# User-friendly printout
print(f"{level}: {relative_filename}:{line}: {message} ({name})")
+ if gh_step_summary:
+ print(f'- **{relative_filename}:{line}** {message} (`{name}`)', file=summaryFp)
+
have_warnings = True
return 1 if have_warnings else 0
"""
+import argparse
import os
import sys
+from pathlib import Path
import helpers
import unidiff
+def create_argument_parser():
+ """Create command-line argument parser."""
+ parser = argparse.ArgumentParser(
+ description="Filter git diff files that are not in the product"
+ )
+ parser.add_argument(
+ "--product",
+ type=str,
+ required=True,
+ help="Product (auth, dnsdist or rec)",
+ )
+ return parser.parse_args()
+
def main():
"""Start the script."""
- # It might be tempting to normalize the paths here instead of
- # rewriting the compilation database, but then clang-tidy
- # loses the depth of files in the repository, outputing for
- # example "credentials.cc" instead of "pdns/credentials.cc"
+ args = create_argument_parser()
+ product = args.product
+
compdb = helpers.load_compdb("compile_commands.json")
compdb = helpers.index_compdb(compdb)
- pdns_path = os.path.join("pdns", "")
- cwd = os.getcwd()
- root = helpers.get_repo_root()
+ cwd = Path(os.getcwd())
diff = sys.stdin.read()
patch_set = unidiff.PatchSet(diff)
for patch in patch_set:
- path = os.path.join(root, patch.path)
- if path in compdb:
- print(patch)
+ # We have to deal with several possible cases for input files, as shown by git:
+ # - in ext/: ext/lmdb-safe/lmdb-safe.cc
+ # - in modules/: modules/lmdbbackend/lmdbbackend.cc
+ # - files that live in the dnsdist or rec dir only: pdns/dnsdistdist/dnsdist-dnsparser.cc or pdns/recursordist/rec-tcp.cc
+ # - files that live in pdns/ and are used by several products (but possibly not with the same compilation flags, so
+ # it is actually important that they are processed for all products: pdns/misc.cc
+ path = Path(patch.path)
+ if product == 'auth':
+ path = Path(cwd).joinpath(path)
else:
- msg = f"Skipping {path}: it is not in the compilation db"
- print(msg, file=sys.stderr)
+ if str(path).startswith('modules'):
+ print(f'Skipping {path}: modules do not apply to {product}', file=sys.stderr)
+ continue
+
+ if str(path).startswith('ext'):
+ subpath = Path(cwd).joinpath(path)
+ else:
+ subpath = Path(cwd).joinpath(path.name)
+
+ if not subpath.exists():
+ print(f'Skipping {path}: does not exist for {product} ({subpath})', file=sys.stderr)
+ continue
+
+ path = subpath
+ if patch.source_file is not None:
+ patch.source_file = str(path)
+ patch.target_file = str(path)
+
+ if not str(path) in compdb:
+ print(f'Skipping {path}: it is not in the compilation db', file=sys.stderr)
+ continue
+
+ print(patch, file=sys.stderr)
+ print(patch)
return 0
"""Helpers for dealing with git, compilation databases, etc."""
-import pathlib
import json
import os
-import sys
import git
import yaml
filename = os.path.join(item["directory"], item["file"])
result.add(filename)
return result
-
-def normalize_dist_dir(version, distPath):
- """Map the path of a source file from inside the dist directory
- to its path in the git repository."""
- # get rid of the distdir path, to get file paths as they are in the repository
- repositoryPath = pathlib.Path(get_repo_root()).resolve()
- distPath = pathlib.Path(distPath).resolve()
- if f'pdns-{version}' in distPath.parts:
- # authoritative or tool
- authPath = repositoryPath.joinpath(f'pdns-{version}').resolve()
- relativeToAuth = distPath.relative_to(authPath)
- return str(repositoryPath.joinpath(relativeToAuth))
-
- if f'pdns-recursor-{version}' in distPath.parts:
- recPath = repositoryPath.joinpath('pdns', 'recursordist', f'pdns-recursor-{version}').resolve()
- relativeToRec = distPath.relative_to(recPath)
- return str(repositoryPath.joinpath('pdns', 'recursordist', relativeToRec).resolve())
-
- if f'dnsdist-{version}' in distPath.parts:
- dnsdistPath = repositoryPath.joinpath('pdns', 'dnsdistdist', f'dnsdist-{version}').resolve()
- relativeToDist = distPath.relative_to(dnsdistPath)
- return str(repositoryPath.joinpath('pdns', 'dnsdistdist', relativeToDist).resolve())
-
- print(f'Unable to map {distPath}', file=sys.stderr)
- return str(distPath)
+++ /dev/null
-#!/usr/bin/env python3
-
-import argparse
-import os
-
-import json
-
-import helpers
-
-def create_argument_parser():
- """Create command-line argument parser."""
- parser = argparse.ArgumentParser(
- description="Normalize paths in compilation database"
- )
- parser.add_argument(
- "--version",
- type=str,
- required=True,
- help="Version number of the current build",
- )
- parser.add_argument('database')
- return parser.parse_args()
-
-if __name__ == "__main__":
- """Start the script."""
- args = create_argument_parser()
-
- compDB = helpers.load_compdb(args.database)
- for entry in compDB:
- for key in ['file', 'directory']:
- if key in entry:
- entry[key] = helpers.normalize_dist_dir(args.version, entry[key])
-
- with open(args.database + '.temp', 'w', encoding='utf-8') as outputFile:
- json.dump(compDB, outputFile, ensure_ascii=False, indent=2)
-
- os.rename(args.database + '.temp', args.database)
contents: read
env:
+ COMPILER: clang
CLANG_VERSION: '13'
# github.workspace variable points to the Runner home folder. Container home folder defined below.
REPO_HOME: '/__w/pdns/pdns'
BUILDER_VERSION: '0.0.0-git1'
COVERAGE: yes
LLVM_PROFILE_FILE: "/tmp/code-%p.profraw"
+ OPTIMIZATIONS: yes
+ DECAF_SUPPORT: yes
jobs:
build-auth:
defaults:
run:
working-directory: ./pdns-${{ env.BUILDER_VERSION }}
- outputs:
- clang-tidy-failed: ${{ steps.clang-tidy-annotations.outputs.failed }}
steps:
- uses: actions/checkout@v3
with:
working-directory: .
- run: inv ci-auth-configure
- run: inv ci-auth-make-bear # This runs under pdns-$BUILDER_VERSION/pdns/
- - name: Normalize paths in compilation DB
- working-directory: .
- run: python3 .github/scripts/normalize_paths_in_compilation_database.py --version $BUILDER_VERSION pdns-$BUILDER_VERSION/pdns/compile_commands.json
- - name: Copy the compilation DB
- working-directory: .
- run: cp pdns-$BUILDER_VERSION/pdns/compile_commands.json .
- - run: ln -s .clang-tidy.full .clang-tidy
- working-directory: .
- - name: Run clang-tidy
- working-directory: .
- run: git diff -U0 HEAD^..HEAD | python3 .github/scripts/git-filter.py | python3 .github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p1 -export-fixes clang-tidy-auth.yml
- - name: Print clang-tidy fixes YAML
- working-directory: .
- shell: bash
- run: |
- if [ -f clang-tidy-auth.yml ]; then
- cat clang-tidy-auth.yml
- fi
- - name: Result annotations
- id: clang-tidy-annotations
- working-directory: .
- shell: bash
- run: |
- if [ -f clang-tidy-auth.yml ]; then
- set +e
- python3 .github/scripts/clang-tidy.py --fixes-file clang-tidy-auth.yml
- echo "failed=$?" >> $GITHUB_OUTPUT
- fi
- run: inv ci-auth-install-remotebackend-test-deps
- run: inv ci-auth-run-unit-tests
- run: inv generate-coverage-info ./testrunner $GITHUB_WORKSPACE
defaults:
run:
working-directory: ./pdns/recursordist/pdns-recursor-${{ env.BUILDER_VERSION }}
- outputs:
- clang-tidy-failed: ${{ steps.clang-tidy-annotations.outputs.failed }}
steps:
- uses: actions/checkout@v3
with:
working-directory: ./pdns/recursordist/
- run: inv ci-rec-configure
- run: inv ci-rec-make-bear
- - name: Normalize paths in compilation DB
- working-directory: .
- run: python3 .github/scripts/normalize_paths_in_compilation_database.py --version $BUILDER_VERSION ./pdns/recursordist/pdns-recursor-$BUILDER_VERSION/compile_commands.json
- - name: Copy compilation DB
- working-directory: .
- run: cp ./pdns/recursordist/pdns-recursor-$BUILDER_VERSION/compile_commands.json .
- - run: ln -s .clang-tidy.full .clang-tidy
- working-directory: .
- - name: Run clang-tidy
- working-directory: .
- run: git diff -U0 HEAD^..HEAD | python3 .github/scripts/git-filter.py | python3 .github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p1 -export-fixes clang-tidy-rec.yml
- - name: Print clang-tidy fixes YAML
- working-directory: .
- shell: bash
- run: |
- if [ -f clang-tidy-rec.yml ]; then
- cat clang-tidy-rec.yml
- fi
- - name: Result annotations
- id: clang-tidy-annotations
- working-directory: .
- shell: bash
- run: |
- if [ -f clang-tidy-rec.yml ]; then
- set +e
- python .github/scripts/clang-tidy.py --fixes-file clang-tidy-rec.yml
- echo "failed=$?" >> $GITHUB_OUTPUT
- fi
- run: inv ci-rec-run-unit-tests
- run: inv generate-coverage-info ./testrunner $GITHUB_WORKSPACE
if: ${{ matrix.sanitizers != 'tsan' }}
defaults:
run:
working-directory: ./pdns/dnsdistdist/dnsdist-${{ env.BUILDER_VERSION }}
- outputs:
- clang-tidy-failed: ${{ steps.clang-tidy-annotations.outputs.failed }}
steps:
- uses: actions/checkout@v3
with:
working-directory: ./pdns/dnsdistdist/
- run: inv ci-dnsdist-configure ${{ matrix.features }}
- run: inv ci-dnsdist-make-bear
- - name: Normalize paths in compilation DB
- working-directory: .
- run: python3 .github/scripts/normalize_paths_in_compilation_database.py --version $BUILDER_VERSION ./pdns/dnsdistdist/dnsdist-$BUILDER_VERSION/compile_commands.json
- - name: Copy compilation DB
- run: cp ./pdns/dnsdistdist/dnsdist-$BUILDER_VERSION/compile_commands.json compile_commands.json
- working-directory: .
- - run: ln -s .clang-tidy.full .clang-tidy
- working-directory: .
- - name: Run clang-tidy
- working-directory: .
- run: git diff -U0 HEAD^..HEAD | python3 .github/scripts/git-filter.py | python3 .github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p1 -export-fixes clang-tidy-dnsdist.yml
- - name: Print clang-tidy fixes YAML
- working-directory: .
- shell: bash
- run: |
- if [ -f clang-tidy-dnsdist.yml ]; then
- cat clang-tidy-dnsdist.yml
- fi
- - name: Result annotations
- id: clang-tidy-annotations
- working-directory: .
- shell: bash
- run: |
- if [ -f clang-tidy-dnsdist.yml ]; then
- set +e
- python .github/scripts/clang-tidy.py --fixes-file clang-tidy-dnsdist.yml
- echo "failed=$?" >> $GITHUB_OUTPUT
- fi
- run: inv ci-dnsdist-run-unit-tests
- run: inv generate-coverage-info ./testrunner $GITHUB_WORKSPACE
if: ${{ matrix.sanitizers != 'tsan' }}
sanitizers: [ubsan+asan, tsan]
dist_name: [debian]
dist_release_name: [bullseye]
- pdns_repo_version: ['45']
+ pdns_repo_version: ['48']
container:
image: ghcr.io/powerdns/base-pdns-ci-image/debian-11-pdns-base:master
env:
- run: inv install-swagger-tools
- run: inv swagger-syntax-check
- check-clang-tidy:
- needs: [build-auth, build-dnsdist, build-recursor]
- runs-on: ubuntu-20.04
- name: Check whether clang-tidy succeeded
- steps:
- - run: |
- if [ "x${{ needs.build-auth.outputs.clang-tidy-failed }}" != "x" -a "${{ needs.build-auth.outputs.clang-tidy-failed }}" != "0" ]; then
- echo "::error::Auth clang-tidy failed"
- exit 1
- fi
- if [ "x${{needs.build-recursor.outputs.clang-tidy-failed}}" != "x" -a "${{needs.build-recursor.outputs.clang-tidy-failed}}" != "0" ]; then
- echo "::error::Rec clang-tidy failed"
- exit 1
- fi
- if [ "x${{ needs.build-dnsdist.outputs.clang-tidy-failed }}" != "x" -a "${{ needs.build-dnsdist.outputs.clang-tidy-failed }}" != "0" ]; then
- echo "::error::dnsdist clang-tidy failed"
- exit 1
- fi
-
collect:
needs:
- build-auth
- test-recursor-api
- test-recursor-regression
- test-recursor-bulk
- - check-clang-tidy
if: success() || failure()
runs-on: ubuntu-20.04
steps:
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@v1.4.0
+ uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0
with:
base64-subjects: "${{ needs.build.outputs[format('pkghashes-{0}', matrix.os)] }}"
upload-assets: false
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@v1.4.0
+ uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0
with:
base64-subjects: "${{ needs.build.outputs.srchashes }}"
upload-assets: false
-name: "CodeQL"
+name: "CodeQL and clang-tidy"
on:
push:
permissions: # least privileges, see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
contents: read
+# clang-tidy fun:
+# We need to invoke clang-tidy from the correct directory, the one the product was compiled in, so that we get the correct include paths.
+# This means the root for the auth, pdns/recursordist for the rec and pdns/dnsdistdist for dnsdist
+# It is important that files that are used by more than one product are processed by all the products using them
+# because they might have difference compilation flags.
+# We have to use our own clang-tidy-diff.py because the line-filter flag only supports file names, not paths.
+# Finally the GH annotations that we generate from clang-tidy.py, have to be relative to the path in the git repository, so we need to
+# follow symlinks.
+# How does that work? We use git diff to get the list of diffs, and git-filter.py to get the right folder depending on the product.
+# Then we call clang-tidy-diff.py, which invokes clang-tidy on the correct file, deducing the line numbers from the diff, and
+# merging the results for all processed files to a YAML file. Finally clang-tidy.py converts the YAML output to GitHub annotations
+# (GitHub only supports 10 of these per job, the rest are not displayed) and to GitHub markdown step summary (which has no such limits).
+
jobs:
analyze:
name: Analyze
if: ${{ !github.event.schedule || vars.SCHEDULED_CODEQL_ANALYSIS }}
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
permissions:
actions: read # for github/codeql-action/init to get workflow details
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
+ env:
+ COMPILER: gcc
+ UNIT_TESTS: yes
+ FUZZING_TARGETS: yes
+ COVERAGE: no
+ OPTIMIZATIONS: no
+ # for clang-tidy only, not compilation
+ CLANG_VERSION: '14'
+ REPO_HOME: ${{ github.workspace }}
+ DECAF_SUPPORT: no
+
+ outputs:
+ clang-tidy-annotations-auth: ${{ steps.clang-tidy-annotations-auth.outputs.failed }}
+ clang-tidy-annotations-dnsdist: ${{ steps.clang-tidy-annotations-dnsdist.outputs.failed }}
+ clang-tidy-annotations-rec: ${{ steps.clang-tidy-annotations-rec.outputs.failed }}
+
steps:
- uses: PowerDNS/pdns/set-ubuntu-mirror@meta
- name: Checkout repository
# a pull request then we can checkout the head.
fetch-depth: 2
- # Python is required for building the Authoritative server
- - uses: actions/setup-python@v4
- with:
- python-version: '3.8'
-
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
# TODO: go through +security-and-quality (400 alerts) once, then see if we can upgrade to it
# If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
+ # By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Update repository metadata
run: |
sudo apt-get update
- - name: Install dependencies
- run: |
- sudo apt-get -qq -y --no-install-recommends --allow-downgrades install \
- bison \
- default-libmysqlclient-dev \
- flex \
- libboost-all-dev \
- libcap-dev \
- libcdb-dev \
- libcurl4-openssl-dev \
- libedit-dev \
- libfstrm-dev \
- libgeoip-dev \
- libgnutls28-dev \
- libh2o-evloop-dev \
- libkrb5-dev \
- libldap2-dev \
- liblmdb-dev \
- liblua5.3-dev \
- libmaxminddb-dev \
- libnghttp2-dev \
- libp11-kit-dev \
- libpq-dev \
- libre2-dev \
- libsnmp-dev \
- libsodium-dev \
- libsqlite3-dev \
- libssl-dev \
- libsystemd-dev \
- libwslay-dev \
- libyaml-cpp-dev \
- ragel \
- rustc \
- unixodbc-dev
+ - name: Install python invoke and needed libs
+ run: |
+ sudo apt-get -qq -y --no-install-recommends install python3 python3-pip python3-invoke python3-git python3-unidiff ccache
+
+ - name: Install clang-tidy tools
+ run: |
+ inv install-clang-tidy-tools
+
+ - name: Install dependencies for auth
+ if: matrix.product == 'auth'
+ run: |
+ inv install-auth-build-deps
+ - name: Autoreconf auth
+ if: matrix.product == 'auth'
+ run: |
+ inv ci-autoconf
+ - name: Configure auth
+ if: matrix.product == 'auth'
+ run: |
+ inv ci-auth-configure
- name: Build auth
if: matrix.product == 'auth'
run: |
- autoreconf -vfi
- ./configure --with-modules='bind geoip gmysql godbc gpgsql gsqlite3 ldap lmdb lua2 pipe remote tinydns' --enable-tools --enable-ixfrdist --enable-dns-over-tls --enable-experimental-pkcs11 --with-libsodium --enable-lua-records CFLAGS='-O0' CXXFLAGS='-O0'
- make -j8 -C ext
- make -j8 -C modules
- make -j8 -C pdns
+ inv ci-auth-make-bear
+ - run: ln -s .clang-tidy.full .clang-tidy
+ 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
+ - name: Print clang-tidy fixes YAML for auth
+ if: matrix.product == 'auth'
+ shell: bash
+ run: |
+ if [ -f clang-tidy-auth.yml ]; then
+ cat clang-tidy-auth.yml
+ fi
+ - name: Result annotations for auth
+ if: matrix.product == 'auth'
+ id: clang-tidy-annotations-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
+ echo "failed=$?" >> $GITHUB_OUTPUT
+ fi
+ - name: Install dependencies for dnsdist
+ if: matrix.product == 'dnsdist'
+ run: |
+ inv install-dnsdist-build-deps
+ - name: Autoreconf dnsdist
+ if: matrix.product == 'dnsdist'
+ working-directory: ./pdns/dnsdistdist/
+ run: |
+ inv ci-autoconf
+ - run: inv ci-install-rust ${{ env.REPO_HOME }}
+ if: matrix.product == 'dnsdist'
+ working-directory: ./pdns/dnsdistdist/
+ - run: inv ci-build-and-install-quiche
+ if: matrix.product == 'dnsdist'
+ working-directory: ./pdns/dnsdistdist/
+ - name: Configure dnsdist
+ if: matrix.product == 'dnsdist'
+ working-directory: ./pdns/dnsdistdist/
+ run: |
+ inv ci-dnsdist-configure full
- name: Build dnsdist
if: matrix.product == 'dnsdist'
+ working-directory: ./pdns/dnsdistdist/
run: |
- cd pdns/dnsdistdist
- autoreconf -vfi
- ./configure --enable-unit-tests --enable-dnstap --enable-dnscrypt --enable-dns-over-tls --enable-dns-over-https --with-h2o LIBS=-lwslay CFLAGS='-O0' CXXFLAGS='-O0'
- make -j8 -C ext/arc4random
- make -j8 -C ext/ipcrypt
- make -j8 -C ext/yahttp
- make -j4 dnsdist
+ inv ci-dnsdist-make-bear
+ - run: ln -s ../../.clang-tidy.full .clang-tidy
+ if: matrix.product == 'dnsdist'
+ working-directory: ./pdns/dnsdistdist/
+ - 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
+ - name: Print clang-tidy fixes YAML for dnsdist
+ if: matrix.product == 'dnsdist'
+ working-directory: ./pdns/dnsdistdist/
+ shell: bash
+ run: |
+ if [ -f clang-tidy-dnsdist.yml ]; then
+ cat clang-tidy-dnsdist.yml
+ fi
+ - name: Result annotations for dnsdist
+ if: matrix.product == 'dnsdist'
+ id: clang-tidy-annotations-dnsdist
+ working-directory: ./pdns/dnsdistdist/
+ shell: bash
+ run: |
+ if [ -f clang-tidy-dnsdist.yml ]; then
+ set +e
+ python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-dnsdist.yml
+ echo "failed=$?" >> $GITHUB_OUTPUT
+ fi
- - name: Build recursor
+ - name: Install dependencies for rec
+ if: matrix.product == 'rec'
+ run: |
+ inv install-rec-build-deps
+ - run: inv ci-install-rust ${{ env.REPO_HOME }}
+ if: matrix.product == 'rec'
+ working-directory: ./pdns/recursordist/
+ - name: Autoreconf rec
if: matrix.product == 'rec'
+ working-directory: ./pdns/recursordist/
run: |
- cd pdns/recursordist
- autoreconf -vfi
- ./configure --enable-unit-tests --enable-nod --enable-dnstap CFLAGS='-O0' CXXFLAGS='-O0'
- make -j8 -C ext
- make -j8 -C settings
- make -j8 -C settings/rust
- make htmlfiles.h
- make -j4 pdns_recursor rec_control
+ inv ci-autoconf
+ - name: Configure rec
+ if: matrix.product == 'rec'
+ working-directory: ./pdns/recursordist/
+ run: |
+ inv ci-rec-configure
+ - name: Build rec
+ if: matrix.product == 'rec'
+ working-directory: ./pdns/recursordist/
+ run: |
+ CONCURRENCY=4 inv ci-rec-make-bear
+ - run: ln -s ../../.clang-tidy.full .clang-tidy
+ if: matrix.product == 'rec'
+ working-directory: ./pdns/recursordist/
+ - 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
+ - name: Print clang-tidy fixes YAML for rec
+ if: matrix.product == 'rec'
+ working-directory: ./pdns/recursordist/
+ shell: bash
+ run: |
+ if [ -f clang-tidy-rec.yml ]; then
+ cat clang-tidy-rec.yml
+ fi
+ - name: Result annotations for rec
+ if: matrix.product == 'rec'
+ id: clang-tidy-annotations-rec
+ working-directory: ./pdns/recursordist/
+ shell: bash
+ run: |
+ if [ -f clang-tidy-rec.yml ]; then
+ set +e
+ python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-rec.yml
+ echo "failed=$?" >> $GITHUB_OUTPUT
+ fi
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+
+ check-clang-tidy:
+ needs: analyze
+ runs-on: ubuntu-20.04
+ name: Check whether clang-tidy succeeded
+ steps:
+ - run: |
+ if [ "x${{ needs.analyze.outputs.clang-tidy-annotations-auth }}" != "x" -a "${{ needs.analyze.outputs.clang-tidy-annotations-auth }}" != "0" ]; then
+ echo "::error::Auth clang-tidy failed"
+ exit 1
+ fi
+ if [ "x${{ needs.analyze.outputs.clang-tidy-annotations-dnsdist }}" != "x" -a "${{ needs.analyze.outputs.clang-tidy-annotations-dnsdist }}" != "0" ]; then
+ echo "::error::DNSdist clang-tidy failed"
+ exit 1
+ fi
+ if [ "x${{needs.analyze.outputs.clang-tidy-annotations-rec }}" != "x" -a "${{needs.analyze.outputs.clang-tidy-annotations-rec }}" != "0" ]; then
+ echo "::error::Rec clang-tidy failed"
+ exit 1
+ fi
- run: inv coverity-clang-configure
- run: inv ci-autoconf
working-directory: ./pdns/dnsdistdist/
+ - run: inv ci-build-and-install-quiche
+ working-directory: ./pdns/dnsdistdist/
- run: inv ci-dnsdist-configure full
working-directory: ./pdns/dnsdistdist/
- run: inv coverity-make
./pdns/lua-record.cc
./pdns/malloctrace.cc
./pdns/malloctrace.hh
-./pdns/mastercommunicator.cc
+./pdns/auth-primarycommunicator.cc
./pdns/minicurl.cc
./pdns/minicurl.hh
./pdns/misc.cc
./pdns/signingpipe.cc
./pdns/signingpipe.hh
./pdns/sillyrecords.cc
-./pdns/slavecommunicator.cc
./pdns/snmp-agent.cc
./pdns/snmp-agent.hh
./pdns/sodcrypto.cc
./pdns/tsigutils.hh
./pdns/tsigverifier.cc
./pdns/tsigverifier.hh
-./pdns/ueberbackend.cc
-./pdns/ueberbackend.hh
./pdns/unix_semaphore.cc
./pdns/unix_utility.cc
./pdns/utility.hh
sudo dpkg --purge --force-all firefox
sudo apt-get autoremove
sudo apt-get -qq -y --allow-downgrades dist-upgrade
-sudo apt-get -qq -y --no-install-recommends install python3-pip
-sudo pip3 install git+https://github.com/pyinvoke/invoke@faa5728a6f76199a3da1750ed952e7efee17c1da
-sudo pip3 install gitpython
-sudo pip3 install unidiff
+sudo apt-get -qq -y --no-install-recommends install python3-pip python3-invoke
sudo chmod 755 /usr/sbin/policy-rc.d
sudo apt-get update
sudo apt-get -qq -y --no-install-recommends install python3-pip python3-invoke
-sudo pip3 install gitpython
-sudo pip3 install unidiff
ADD builder-support/gen-version /pdns-recursor/pdns/recursordist/builder-support/gen-version
WORKDIR /pdns-recursor/pdns/recursordist
+ADD builder-support/helpers/ /pdns/builder-support/helpers/
+RUN /pdns/builder-support/helpers/install_rust.sh
+
RUN mkdir /sdist
ARG BUILDER_VERSION
--enable-systemd --with-systemd=%{_unitdir} \
--without-net-snmp
%endif
-%if 0%{?rhel} >= 7
- --enable-dnscrypt \
+%if 0%{?rhel} >= 7 || 0%{?amzn} == 2023
--enable-dnstap \
--enable-dns-over-https \
--enable-systemd --with-systemd=%{_unitdir} \
--with-gnutls \
--with-libcap \
- --with-libsodium \
--with-lua=%{lua_implementation} \
- --with-net-snmp \
--with-re2 \
-%if 0%{?rhel} >= 8
+%if 0%{?amzn} != 2023
+ --enable-dnscrypt \
+ --with-libsodium \
+ --with-net-snmp \
+%endif
+%if 0%{?rhel} >= 8 || 0%{?amzn} == 2023
--enable-dns-over-quic \
--with-quiche \
%endif
%install
%make_install
install -d %{buildroot}/%{_sysconfdir}/dnsdist
-%if 0%{?rhel} >= 8
+%if 0%{?rhel} >= 8 || 0%{?amzn} == 2023
install -Dm644 /usr/lib/libdnsdist-quiche.so %{buildroot}/%{_libdir}/libdnsdist-quiche.so
%endif
%{__mv} %{buildroot}%{_sysconfdir}/dnsdist/dnsdist.conf-dist %{buildroot}%{_sysconfdir}/dnsdist/dnsdist.conf
%{!?_licensedir:%global license %%doc}
%doc README.md
%{_bindir}/*
-%if 0%{?rhel} >= 8
+%if 0%{?rhel} >= 8 || 0%{?amzn} == 2023
+%define __requires_exclude libdnsdist-quiche\\.so
%{_libdir}/libdnsdist-quiche.so
%endif
%{_mandir}/man1/*
Setting this option to ``yes`` makes PowerDNS ignore out of zone records
when loading zone files.
-.. _setting-bind-supermasters:
+Autoprimary support (experimental)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-``bind-supermasters``
-~~~~~~~~~~~~~~~~~~~~~
+.. _setting-bind-autoprimaries:
+
+``bind-autoprimaries``
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionchanged:: 4.9.0
+
+ This was called ``bind-supermasters`` before 4.9.0.
Specifies file where to read list of autoprimaries.
BIND backend only checks IP address of primary server.
BIND backend can only read this file, not write it.
-.. _setting-bind-supermaster-config:
+.. _setting-bind-autoprimary-config:
-``bind-supermaster-config``
+``bind-autoprimary-config``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. versionchanged:: 4.9.0
+
+ This was called ``bind-supermaster-config`` before 4.9.0.
+
When a new zone is configured via the autosecondary mechanism, bindbackend *writes* a zone entry to this file.
Your ``bind-config`` file should have an ``include`` statement to make sure this file is read on startup.
-.. _setting-bind-supermaster-destdir:
+.. _setting-bind-autoprimary-destdir:
-``bind-supermaster-destdir``
+``bind-autoprimary-destdir``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. versionchanged:: 4.9.0
+
+ This was called ``bind-supermaster-destdir`` before 4.9.0.
+
Each new zone configured via the autosecondary mechanism gets a zone file in this directory.
This directory must be writable.
Records can now be added using ``pdnsutil add-record`` or ``pdnsutil edit-zone``.
-Slave operation
-^^^^^^^^^^^^^^^
+Secondary operation
+^^^^^^^^^^^^^^^^^^^
-These backends are fully slave capable. To become a slave of the
-'example.com' domain, using 198.51.100.6 as the master execute this::
+These backends are fully secondary capable. To become a secondary of the
+'example.com' domain, using 198.51.100.6 as the primary execute this::
- pdnsutil create-slave-zone example.com 198.51.100.6
+ pdnsutil create-secondary-zone example.com 198.51.100.6
And wait a while for PowerDNS to pick up the addition - which happens
within one minute (this is determined by the
-:ref:`setting-slave-cycle-interval`
+:ref:`setting-xfr-cycle-interval`
setting). There is no need to inform PowerDNS that a new domain was
added. Typical output is::
- Apr 09 13:34:29 All slave domains are fresh
- Apr 09 13:35:29 1 slave domain needs checking
- Apr 09 13:35:29 Domain example.com is stale, master serial 1, our serial 0
+ Apr 09 13:34:29 All secondary domains are fresh
+ Apr 09 13:35:29 1 secondary domain needs checking
+ Apr 09 13:35:29 Domain example.com is stale, primary serial 1, our serial 0
Apr 09 13:35:30 [gPgSQLBackend] Connected to database
Apr 09 13:35:30 AXFR started for 'example.com'
Apr 09 13:35:30 AXFR done for 'example.com'
Periodically, PowerDNS schedules checks to see if domains are still
fresh. The default
-:ref:`setting-slave-cycle-interval` is 60
+:ref:`setting-xfr-cycle-interval` is 60
seconds, large installations may need to raise this value. Once a domain
has been checked, it will not be checked before its SOA refresh timer
has expired. Domains whose status is unknown get checked every 60
seconds by default.
-PowerDNS has support for multiple masters per zone, and also port numbers for these masters::
+PowerDNS has support for multiple primaries per zone, and also port numbers for these primaries::
- pdnsutil create-slave-zone example.com 198.51.100.6 2001:0DB8:15:4AF::4
- pdnsutil create-slave-zone example.net 198.51.100.20:5301 '[2001:0DB8:11:6E::4]:54'
+ pdnsutil create-secondary-zone example.com 198.51.100.6 2001:0DB8:15:4AF::4
+ pdnsutil create-secondary-zone example.net 198.51.100.20:5301 '[2001:0DB8:11:6E::4]:54'
-Superslave operation
-^^^^^^^^^^^^^^^^^^^^
+Autoprimary operation
+^^^^^^^^^^^^^^^^^^^^^
-To configure a :ref:`supermaster <supermaster-operation>` with IP address 203.0.113.53 which lists this
-installation as 'autoslave.example.com', issue the following::
+To configure a :ref:`autoprimary <supermaster-operation>` with IP address 203.0.113.53 which lists this
+installation as 'autosecondary.example.com', issue the following::
- pdnsutil add-supermaster 203.0.113.53 autoslave.example.com internal
+ pdnsutil add-autoprimary 203.0.113.53 autosecondary.example.com internal
From now on, valid notifies from 203.0.113.53 for which the zone lists an NS record
-containing 'autoslave.example.com' will lead to the provisioning of a
-slave domain under the account 'internal'. See :ref:`supermaster-operation`
+containing 'autosecondary.example.com' will lead to the provisioning of a
+secondary domain under the account 'internal'. See :ref:`autoprimary-operation`
for details.
-Master operation
-^^^^^^^^^^^^^^^^
+Primary operation
+^^^^^^^^^^^^^^^^^
-The generic SQL backend is fully master capable with automatic discovery
+The generic SQL backend is fully primary capable with automatic discovery
of serial changes. Raising the serial number of a domain suffices to
trigger PowerDNS to send out notifications. To configure a domain for
-master operation instead of the default native replication, issue::
+primary operation instead of the default native replication, issue::
pdnsutil create-zone example.com
pdnsutil set-kind example.com MASTER
Effects: the record (or domain, respectively) will not be visible to DNS
clients. The REST API will still see the record (or domain). Even if a
-domain is disabled, slaving still works. Slaving considers a disabled
-domain to have a serial of 0; this implies that a slaved domain will not
+domain is disabled, xfr still works. A secondary considers a disabled
+domain to have a serial of 0; this implies that a secondary domain will not
stay disabled.
.. _generic-sql-handling-dnssec-signed-zones:
a zone.
- ``remove-domain-key-query``: Called to remove a crypto key.
-Master/slave queries
-^^^^^^^^^^^^^^^^^^^^
+Primary/secondary queries
+^^^^^^^^^^^^^^^^^^^^^^^^^
-These queries are used to manipulate the master/slave information in the
+These queries are used to manipulate the primary/secondary information in the
database. Most installations will have zero need to change the following
queries.
-On masters
-~~~~~~~~~~
+On primaries
+~~~~~~~~~~~~
-- ``info-all-master-query``: Called to get data on all domains for
- which the server is master.
-- ``update-serial-query`` Called to update the last notified serial of
- a master domain.
+- ``info-all-primary-query``: Called to get data on all domains for which the server is primary.
+- ``update-serial-query`` Called to update the last notified serial of a primary domain.
-On slaves
-~~~~~~~~~
+On secondaries
+~~~~~~~~~~~~~~
-- ``info-all-slaves-query``: Called to retrieve all slave domains.
-- ``update-lastcheck-query``: Called to update the last time a slave
- domain was successfully checked for freshness.
-- ``update-master-query``: Called to update the master address of a
- domain.
+- ``info-all-secondaries-query``: Called to retrieve all secondary domains.
+- ``update-lastcheck-query``: Called to update the last time a secondary domain was successfully checked for freshness.
+- ``update-primary-query``: Called to update the primary address of a domain.
-On superslaves
+On autoprimary
~~~~~~~~~~~~~~
-- ``supermaster-query``: Called to determine if a certain host is a
- supermaster for a certain domain name.
-- ``supermaster-name-to-ips``: Called to the IP and account for a
- supermaster.
+- ``autoprimary-query``: Called to determine if a certain host is a autoprimary for a certain domain name.
+- ``autoprimary-name-to-ips``: Called to the IP and account for a autoprimary.
TSIG
^^^^
Setting catalog values is supported in the :doc:`API <http-api/zone>`, by setting the ``catalog`` property in the zone properties.
-Each member zone may have one or more additional properties as defined in the draft.
+Each member zone may have one or more additional properties as defined in the RFC.
PowerDNS currently supports the following properties:
- coo - A single DNSName
We want to explicitly thank Kees Monshouwer for digging up all the
DNSSEC improvements and porting them back to this release.
-When upgrading, please run "pdnssec rectify-all-zones" and trigger an
+When upgrading, please run ``pdnssec rectify-all-zones`` and trigger an
AXFR for all DNSSEC zones to make sure you benefit from all the
compliance improvements present in this version.
- `commit a7aa9be <https://github.com/PowerDNS/pdns/commit/a7aa9be>`__:
Replace hardcoded make with variable
- `commit e4fe901 <https://github.com/PowerDNS/pdns/commit/e4fe901>`__:
- make sure to run PKG\_PROG\_PKG\_CONFIG before the first PKG\_\*
+ make sure to run ``PKG_PROG_PKG_CONFIG`` before the first ``PKG_*``
usage
- `commit 29bf169 <https://github.com/PowerDNS/pdns/commit/29bf169>`__:
fix hmac-md5 TSIG key lookup
**Warning**: Version 3.3 of the PowerDNS Authoritative Server is a major
upgrade if you are coming from 2.9.x. There are also some important
changes if you are coming from 3.0, 3.1 or 3.2. Please refer to the
-`Upgrade documentation <authoritative/upgrading.md>`__ for important
+`Upgrade documentation <../upgrading.rst>`__ for important
information on correct and stable operation, as well as notes on
performance and memory use.
- We imported the TinyDNS backend by Ruben d'Arco. Code mostly in
`commit
2559 <http://wiki.powerdns.com/projects/trac/changeset/2559>`__. See
- `TinyDNS Backend <authoritative/backend-tinydns.md>`__.
+ `TinyDNS Backend <../backends/tinydns.rst>`__.
- Overriding C(XX)FLAGS is easier now. Problem pointed out by Jose
Arthur Benetasso Villanova and others, fix suggested by Sten Spans.
Patch in `commit
all important algorithms are supported.
Complete detail can be found in `Serving authoritative DNSSEC
-data <authoritative/dnssec.md>`__. The goal of 'PowerDNSSEC' is to allow
-existing PowerDNS installations to start serving DNSSEC with as little
-hassle as possible, while maintaining performance and achieving high
-levels of security.
-
-Tutorials and examples of how to use DNSSEC in PowerDNS can be found
-linked from http://powerdnssec.org.
+data <../dnssec/intro.rst>`__. The goal of PowerDNS's DNSSEC support
+is to allow existing PowerDNS installations to start serving DNSSEC with
+as little hassle as possible, while maintaining performance and
+achieving high levels of security.
PowerDNS Authoritative Server 3.0 development has been made possible by
the financial and moral support of
DNS <http://www.ipcom.at/en/dns/rcodezero_anycast/>`__, a subsidiary
of NIC.AT, the Austrian registry
- `SIDN, the Dutch registry <http://www.sidn.nl/>`__
-- .. (awaiting details) ..
This release has received exceptional levels of community support, and
we'd like to thank the following people in addition to those mentioned
Additionally, the bind2backend is almost ready to replace the stock bind
backend. If you run with Bind zones, you are cordially invited to
-substitute 'launch=bind2' for 'launch=bind'. This will happen
+substitute ``launch=bind2`` for ``launch=bind``. This will happen
automatically in 2.9.19!
In other news, the entire Wikipedia constellation now runs on PowerDNS
Recursor improvements and fixes.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-See `Recursion <authoritative/recursion.md>`__ for details. The changes
+See `Recursion <../guides/recursion.rst>`__ for details. The changes
below mean that all of the caveats listed for the recursor have now been
addressed.
- PostgreSQL now only depends on the C API and not on the deprecated
C++ one
- PowerDNS can now fully overrule external zones when doing recursion.
- See `Recursion <authoritative/recursion.md>`__.
+ See `Recursion <../guides/recursion.rst>`__.
Version 2.9.13
--------------
be restarted without having to restart the rest of the nameserver, for
example. Cooperation between the both halves of PowerDNS is also almost
seamless. As a result, 'non-lazy recursion' has been dropped. See
-`Recursion <authoritative/recursion.md>`__ for more details.
+`Recursion <../guides/recursion.rst>`__ for more details.
Furthermore, the recursor only works on Linux, Windows and Solaris (not
entirely). FreeBSD does not support the required functions. If you know
PowerDNS than yet know about it. So spread the word!
In other news, we now have a security page at
-`Security <security/index.md>`__. Furthermore, Maurice Nonnekes
+`Security <../security.rst>`__. Furthermore, Maurice Nonnekes
contributed an OpenBSD port! See `his
page <http://www.codeninja.nl/openbsd/powerdns/>`__ for more details!
the operator is in charge.
For more about all this coolness, see
-`“pdns\_control” <authoritative/running.md#pdnscontrol>`__ and
+`“pdns\_control” <running.rst#pdnscontrol>`__ and
`“pdns\_control
-commands” <authoritative/backend-bind.md#bind-control-commands>`__.
+commands” <backends/bind.rst#bind-control-commands>`__.
**Warning**: Again some changes in compilation instructions. The hybrid
pgmysql backend has been split up into 'gmysql' and 'gpgsql', sharing a
Developers: this version needs the new pdns-2.5.1 development kit,
available on http://downloads.powerdns.com/releases/dev. See also
-`Backend writers' guide <appendix/backend-writers-guide.md>`__.
+`Backend writers' guide <../appendices/backend-writers-guide.rst>`__.
And some small changes
The webserver also displays the efficiency of the new Query Cache.
The old Packet Cache is still there (and useful) but see
- `Authoritative Server Performance <authoritative/performance.md>`__
+ `Authoritative Server Performance <../performance.rst>`__
for more details.
- There is now the ability to shut off some logging at a very early
Developers: this version is compatible with the pdns-2.1 development
kit, available on http://downloads.powerdns.com/releases/dev. See also
-`*Backend writers' guide* <appendix/backend-writers-guide.md>`__.
+`*Backend writers' guide* <../appendices/backend-writers-guide.rst>`__.
This version fixes some stability issues with malformed or malcrafted
packets. An upgrade is advised. Furthermore, there are interesting new
Developers: this version is compatible with the pdns-2.1 development
kit, available on http://downloads.powerdns.com/releases/dev. See also
-`Backend writers' guide <appendix/backend-writers-guide.md>`__
+`Backend writers' guide <../appendices/backend-writers-guide.rst>`__
This release adds the Generic MySQL backend which allows full
master/slave semantics with MySQL and InnoDB tables (or other tables
Developers: this version is compatible with the pdns-2.1 development
kit, available on http://downloads.powerdns.com/releases/dev. See also
-`Backend writers' guide <appendix/backend-writers-guide.md>`__
+`Backend writers' guide <../appendices/backend-writers-guide.rst>`__
Again a big release. PowerDNS is seeing some larger deployments in more
demanding environments and these are helping shake out remaining issues,
- **pdns\_control purge** can now also purge based on suffix, allowing
operators to purge an entire domain from the packet cache instead of
only specific records. See also
- `pdns\_control <authoritative/running.md#pdnscontrol>`__ Thanks to
+ `pdns\_control <running.rst#pdnscontrol>`__ Thanks to
Mike Benoit for this suggestion.
- **soa-serial-offset** for installations with small SOA serial numbers
wishing to register .DE domains with DENIC which demands six-figure
SOA serial numbers. See also `Chapter 21, *Index of all Authoritative
- Server settings* <authoritative/settings.md>`__.
+ Server settings* <../settings.rst>`__.
Version 2.1
-----------
with user expectations. If a recursive question can be answered
entirely from local data, it is. To restore old behaviour, disable
**lazy-recursion**. Also see
- `Recursion <authoritative/recursion.md>`__.
+ `Recursion <../guides/recursion.rst>`__.
Features
^^^^^^^^
- Zone2sql now accepts ^^transactions to wrap zones in a transaction
for PostgreSQL and Oracle output. This is a major speedup and also
makes for better isolation of inserts. See
- `Zone2sql <authoritative/migration.md#zone2sql>`__.
+ `Zone2sql <migration.rst#zone2sql>`__.
- **pdns\_control** now has the ability to purge the PowerDNS cache or
parts of it. This enables operators to raise the TTL of the Packet
Cache to huge values and only to invalidate the cache when changes
are made. See also `Authoritative Server
- Performance <authoritative/performance.md>`__ and
- `pdns\_control <authoritative/running.md#pdnscontrol>`__.
+ Performance <../performance.rst>`__ and
+ `pdns\_control <../running.rst#pdnscontrol>`__.
Version 2.0.1
-------------
^^^^^^^^
- pdns\_control (see
- `pdns\_control <authoritative/running.md#pdnscontrol>`__) now opens
+ `pdns\_control <running.rst#pdnscontrol>`__) now opens
the local end of its socket in ``/tmp`` instead of next to the remote
socket (by default ``/var/run``). This eases the way for allowing
non-root access to pdns\_control. When running chrooted (see
`Chapter 7, *Security settings &
- considerations* <common/security.md>`__), the local socket again
+ considerations* <../security.rst>`__), the local socket again
moves back to ``/var/run``.
- pdns\_control now has a 'version' command. See `Section 1.1,
- “pdns\_control” <authoritative/running.md#pdnscontrol>`__.
+ “pdns\_control” <../running.rst#pdnscontrol>`__.
Version 1.99.11 Prerelease
--------------------------
`Supermaster automatic provisioning of
slaves <authoritative/modes-of-operation.md#supermaster>`__.
- Recursing backend can now live on a non-standard (!=53) port. See
- `Recursion <authoritative/recursion.md>`__.
+ `Recursion <../guides/recursion.rst>`__.
- Slave zone retrieval is now queued instead of immediate, which scales
better and is more resilient to temporary failures.
- **max-queue-length** parameter. If this many packets are queued for
Feature enhancements
^^^^^^^^^^^^^^^^^^^^
-- Recursing backend. See `Recursion <authoritative/recursion.md>`__.
+- Recursing backend. See `Recursion <../guides/recursion.rst>`__.
Allows recursive and authoritative DNS on the same IP address.
-- `NAPTR support <types.md#naptr>`__, which is especially useful for
+- `NAPTR support <appendices/types.rst#naptr>`__, which is especially useful for
the ENUM/E.164 community.
- Zone transfers can now be allowed per `netmask instead of only per IP
- address <authoritative/settings.md#allow-axfr-ips>`__.
+ address <../settings.rst#allow-axfr-ips>`__.
- Preliminary support for slave operation included. Only for the
adventurous right now! See `Slave
- operation <authoritative/modes-of-operation.md>`__
+ operation <../modes-of-operation.rst>`__
- All record types now documented, see `Supported record types and
- their storage <types.md>`__.
+ their storage <../appendices/types.rst>`__.
Known bugs
^^^^^^^^^^
DNSSEC is a major change in the way DNS works. Furthermore, there is a
bewildering array of settings that can be configured.
-It is well possible to configure DNSSEC in such a way that your domain
+It is easy to (mis)configure DNSSEC in such a way that your domain
will not operate reliably, or even, at all. We advise operators to stick
to the keying defaults of ``pdnsutil secure-zone``.
- Morten Stevens
- Pieter Lexis
-This list is far from complete yet ..
+and everyone else who contributed to making this possible.
DNSSEC is a complicated subject, but it is not required to know all the
ins and outs of this protocol to be able to use PowerDNS. In this
section, we explain the core concepts that are needed to operate a
-PowerDNSSEC installation.
+PowerDNS installation with DNSSEC.
-Zone material is enhanced with signatures using 'keys'. Such a signature
+Zone material is enhanced with signatures using ``keys``. Such a signature
(called an RRSIG) is a cryptographic guarantee that the data served is
the original data. DNSSEC keys are asymmetric (RSA, DSA, ECSDA or GOST),
the public part is published in DNS and is called a DNSKEY record, and
key, we are done in theory.
However, for a variety of reasons, most DNSSEC operations run with
-another layer of keys. The so called 'Key Signing Key' is sent to the
+another layer of keys. The so called ``Key Signing Key`` is sent to the
parent zone, and this Key Signing Key is used to sign a new set of keys
called the Zone Signing Keys.
This setup allows us to change our keys without having to tell the zone
operator about it.
-A final challenge is how to DNSSEC sign the answer 'no such domain'. In
-the language of DNS, the way to say 'there is no such domain' (NXDOMAIN)
+A final challenge is how to DNSSEC sign the answer *no such domain*. In
+the language of DNS, the way to say *there is no such domain* (``NXDOMAIN``)
or there is no such record type is to send an empty answer. Such empty
answers are universal, and can't be signed.
-In DNSSEC parlance we therefore sign a record that says 'there are no
-domains between A.powerdnssec.org and C.powerdnssec.org'. This securely
-tells the world that B.powerdnssec.org does not exist. This solution is
-called NSEC, and is simple but has downsides - it also tells the world
+In DNSSEC parlance we therefore sign a record that says *there are no
+domains between* ``A.powerdnssec.org`` *and* ``C.powerdnssec.org``. This securely
+tells the world that ``B.powerdnssec.org`` does not exist. This solution is
+called ``NSEC``, and is simple but has downsides - it also tells the world
exactly which records DO exist.
So alternatively, we can say that if a certain mathematical operation
-(an 'iterated salted hash') is performed on a question, that no valid
+(an *iterated salted hash*) is performed on a question, that no valid
answers exist that have as outcome of this operation an answer between
-two very large numbers. This leads to the same 'proof of non-existence'.
-This solution is called NSEC3.
+two very large numbers. This leads to the same *proof of non-existence*.
+This solution is called ``NSEC3``.
-A PowerDNS zone can either be operated in NSEC or in one of two NSEC3
-modes ('inclusive' and 'narrow').
+A PowerDNS zone can either be operated in ``NSEC`` or in one of two ``NSEC3``
+modes (``inclusive`` and ``narrow``).
List all options
--on-error-resume-next
Ignore missing zone files during parsing. Dangerous.
---slave
+--secondary
Maintain slave status of zones listed in named.conf as being slaves.
The default behaviour is to convert all zones to native operation.
--verbose
slave zones as slaves, and not convert them to native operation.
``zone2sql`` can generate SQL for nearly all the Generic SQL backends.
-See `its manpage <manpages/zone2sql.1>` for more information.
+See :doc:`its manpage <manpages/zone2sql.1>` for more information.
An example call to ``zone2sql`` could be:
-@ 86400 IN SOA pdns-public-ns1.powerdns.com. peter\.van\.dijk.powerdns.com. 2023101701 10800 3600 604800 10800
+@ 86400 IN SOA pdns-public-ns1.powerdns.com. peter\.van\.dijk.powerdns.com. 2023111000 10800 3600 604800 10800
@ 3600 IN NS pdns-public-ns1.powerdns.com.
@ 3600 IN NS pdns-public-ns2.powerdns.com.
recursor-4.9.0-rc1.security-status 60 IN TXT "2 Unsupported pre-release"
recursor-4.9.0.security-status 60 IN TXT "1 OK"
recursor-4.9.1.security-status 60 IN TXT "1 OK"
+recursor-4.9.2.security-status 60 IN TXT "1 OK"
recursor-5.0.0-alpha1.security-status 60 IN TXT "2 Unsupported pre-release"
-recursor-5.0.0-alpha2.security-status 60 IN TXT "1 Unsupported pre-release"
+recursor-5.0.0-alpha2.security-status 60 IN TXT "2 Unsupported pre-release"
+recursor-5.0.0-beta1.security-status 60 IN TXT "1 Unsupported pre-release"
; 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.0.security-status 60 IN TXT "3 Upgrade now, see https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"
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.9.0-alpha1.security-status 60 IN TXT "1 Unsupported pre-release (known vulnerabilities)"
+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 "1 Unsupported pre-release (no known vulnerabilities)"
+dnsdist-1.9.0-alpha3.security-status 60 IN TXT "1 Unsupported pre-release (no known vulnerabilities)"
See the `3.X <https://doc.powerdns.com/3/authoritative/upgrading/>`__
upgrade notes if your version is older than 3.4.2.
+4.8.0 to 4.9.0
+--------------
+
+Removed options
+^^^^^^^^^^^^^^^
+
+Various settings, deprecated since 4.5.0, have been removed.
+
+* :ref:`setting-allow-unsigned-supermaster` is now :ref:`setting-allow-unsigned-autoprimary`
+* :ref:`setting-master` is now :ref:`setting-primary`
+* :ref:`setting-slave-cycle-interval` is now :ref:`setting-xfr-cycle-interval`
+* :ref:`setting-slave-renotify` is now :ref:`setting-secondary-do-renotify`
+* :ref:`setting-slave` is now :ref:`setting-secondary`
+* :ref:`setting-superslave` is now :ref:`setting-autosecondary`
+
+Renamed options
+^^^^^^^^^^^^^^^
+
+Bind backend
+~~~~~~~~~~~~
+
+Various experimental autoprimary settings have been renamed.
+
+* ``supermaster-config`` is now ``autoprimary-config``
+* ``supermasters`` is now ``autoprimaries``
+* ``supermaster-destdir`` is now ``autoprimary-destdir``
+
+Gsql backends
+~~~~~~~~~~~~~
+
+Various custom queries have been renamed.
+
+* ``info-all-slaves-query`` is now ``info-all-secondaries-query``
+* ``supermaster-query`` is now ``autoprimary-query``
+* ``supermaster-name-to-ips`` is now ``autoprimary-name-to-ips``
+* ``supermaster-add`` is now ``autoprimary-add``
+* ``update-master-query`` is now ``update-primary-query``
+* ``info-all-master-query`` is now ``info-all-primary-query``
+
any version to 4.8.x
--------------------
#endif /* #ifndef DNSDIST */
-MDBDbi::MDBDbi(MDB_env* env, MDB_txn* txn, const string_view dbname, int flags)
+MDBDbi::MDBDbi(MDB_env* /* env */, MDB_txn* txn, const string_view dbname, int flags) : d_dbi(-1)
{
// A transaction that uses this function must finish (either commit or abort) before any other transaction in the process may use this function.
--- /dev/null
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_compare_version.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+# This macro compares two version strings. Due to the various number of
+# minor-version numbers that can exist, and the fact that string
+# comparisons are not compatible with numeric comparisons, this is not
+# necessarily trivial to do in a autoconf script. This macro makes doing
+# these comparisons easy.
+#
+# The six basic comparisons are available, as well as checking equality
+# limited to a certain number of minor-version levels.
+#
+# The operator OP determines what type of comparison to do, and can be one
+# of:
+#
+# eq - equal (test A == B)
+# ne - not equal (test A != B)
+# le - less than or equal (test A <= B)
+# ge - greater than or equal (test A >= B)
+# lt - less than (test A < B)
+# gt - greater than (test A > B)
+#
+# Additionally, the eq and ne operator can have a number after it to limit
+# the test to that number of minor versions.
+#
+# eq0 - equal up to the length of the shorter version
+# ne0 - not equal up to the length of the shorter version
+# eqN - equal up to N sub-version levels
+# neN - not equal up to N sub-version levels
+#
+# When the condition is true, shell commands ACTION-IF-TRUE are run,
+# otherwise shell commands ACTION-IF-FALSE are run. The environment
+# variable 'ax_compare_version' is always set to either 'true' or 'false'
+# as well.
+#
+# Examples:
+#
+# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
+# AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
+#
+# would both be true.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
+# AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
+#
+# would both be false.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
+#
+# would be true because it is only comparing two minor versions.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
+#
+# would be true because it is only comparing the lesser number of minor
+# versions of the two values.
+#
+# Note: The characters that separate the version numbers do not matter. An
+# empty string is the same as version 0. OP is evaluated by autoconf, not
+# configure, so must be a string, not a variable.
+#
+# The author would like to acknowledge Guido Draheim whose advice about
+# the m4_case and m4_ifvaln functions make this macro only include the
+# portions necessary to perform the specific comparison specified by the
+# OP argument in the final configure script.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Tim Toolan <toolan@ele.uri.edu>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 13
+
+dnl #########################################################################
+AC_DEFUN([AX_COMPARE_VERSION], [
+ AC_REQUIRE([AC_PROG_AWK])
+
+ # Used to indicate true or false condition
+ ax_compare_version=false
+
+ # Convert the two version strings to be compared into a format that
+ # allows a simple string comparison. The end result is that a version
+ # string of the form 1.12.5-r617 will be converted to the form
+ # 0001001200050617. In other words, each number is zero padded to four
+ # digits, and non digits are removed.
+ AS_VAR_PUSHDEF([A],[ax_compare_version_A])
+ A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/[[^0-9]]//g'`
+
+ AS_VAR_PUSHDEF([B],[ax_compare_version_B])
+ B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/[[^0-9]]//g'`
+
+ dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
+ dnl # then the first line is used to determine if the condition is true.
+ dnl # The sed right after the echo is to remove any indented white space.
+ m4_case(m4_tolower($2),
+ [lt],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+ ],
+ [gt],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+ ],
+ [le],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+ ],
+ [ge],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+ ],[
+ dnl Split the operator from the subversion count if present.
+ m4_bmatch(m4_substr($2,2),
+ [0],[
+ # A count of zero means use the length of the shorter version.
+ # Determine the number of characters in A and B.
+ ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'`
+ ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'`
+
+ # Set A to no more than B's length and B to no more than A's length.
+ A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
+ B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
+ ],
+ [[0-9]+],[
+ # A count greater than zero means use only that many subversions
+ A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+ B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+ ],
+ [.+],[
+ AC_WARNING(
+ [invalid OP numeric parameter: $2])
+ ],[])
+
+ # Pad zeros at end of numbers to make same length.
+ ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
+ B="$B`echo $A | sed 's/./0/g'`"
+ A="$ax_compare_version_tmp_A"
+
+ # Check for equality or inequality as necessary.
+ m4_case(m4_tolower(m4_substr($2,0,2)),
+ [eq],[
+ test "x$A" = "x$B" && ax_compare_version=true
+ ],
+ [ne],[
+ test "x$A" != "x$B" && ax_compare_version=true
+ ],[
+ AC_WARNING([invalid OP parameter: $2])
+ ])
+ ])
+
+ AS_VAR_POPDEF([A])dnl
+ AS_VAR_POPDEF([B])dnl
+
+ dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
+ if test "$ax_compare_version" = "true" ; then
+ m4_ifvaln([$4],[$4],[:])dnl
+ m4_ifvaln([$5],[else $5])dnl
+ fi
+]) dnl AX_COMPARE_VERSION
int Bind2Backend::s_first = 1;
bool Bind2Backend::s_ignore_broken_records = false;
-std::mutex Bind2Backend::s_supermaster_config_lock; // protects writes to config file
+std::mutex Bind2Backend::s_autosecondary_config_lock; // protects writes to config file
std::mutex Bind2Backend::s_startup_lock;
string Bind2Backend::s_binddirectory;
fd = -1;
*d_of << "; Written by PowerDNS, don't edit!" << endl;
- *d_of << "; Zone '" << bbd.d_name << "' retrieved from master " << endl
- << "; at " << nowTime() << endl; // insert master info here again
+ *d_of << "; Zone '" << bbd.d_name << "' retrieved from primary " << endl
+ << "; at " << nowTime() << endl; // insert primary info here again
return true;
}
throw DBException("out-of-zone data '" + rr.qname.toLogString() + "' during AXFR of zone '" + d_transaction_qname.toLogString() + "'");
}
- shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), QClass::IN, rr.content));
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::make(rr.qtype.getCode(), QClass::IN, rr.content));
string content = drc->getZoneRepresentation();
// SOA needs stripping too! XXX FIXME - also, this should not be here I think
return true;
}
-void Bind2Backend::getUpdatedMasters(vector<DomainInfo>& changedDomains, std::unordered_set<DNSName>& /* catalogs */, CatalogHashMap& /* catalogHashes */)
+void Bind2Backend::getUpdatedPrimaries(vector<DomainInfo>& changedDomains, std::unordered_set<DNSName>& /* catalogs */, CatalogHashMap& /* catalogHashes */)
{
vector<DomainInfo> consider;
{
auto state = s_state.read_lock();
for (const auto& i : *state) {
- if (i.d_kind != DomainInfo::Master && this->alsoNotify.empty() && i.d_also_notify.empty())
+ if (i.d_kind != DomainInfo::Primary && this->alsoNotify.empty() && i.d_also_notify.empty())
continue;
DomainInfo di;
di.last_check = i.d_lastcheck;
di.notified_serial = i.d_lastnotified;
di.backend = this;
- di.kind = DomainInfo::Master;
+ di.kind = DomainInfo::Primary;
consider.push_back(std::move(di));
}
}
di.zone = i.d_name;
di.last_check = i.d_lastcheck;
di.kind = i.d_kind;
- di.masters = i.d_masters;
+ di.primaries = i.d_primaries;
di.backend = this;
domains->push_back(std::move(di));
};
}
}
-void Bind2Backend::getUnfreshSlaveInfos(vector<DomainInfo>* unfreshDomains)
+void Bind2Backend::getUnfreshSecondaryInfos(vector<DomainInfo>* unfreshDomains)
{
vector<DomainInfo> domains;
{
auto state = s_state.read_lock();
domains.reserve(state->size());
for (const auto& i : *state) {
- if (i.d_kind != DomainInfo::Slave)
+ if (i.d_kind != DomainInfo::Secondary)
continue;
DomainInfo sd;
sd.id = i.d_id;
sd.zone = i.d_name;
- sd.masters = i.d_masters;
+ sd.primaries = i.d_primaries;
sd.last_check = i.d_lastcheck;
sd.backend = this;
- sd.kind = DomainInfo::Slave;
+ sd.kind = DomainInfo::Secondary;
domains.push_back(std::move(sd));
}
}
di.id = bbd.d_id;
di.zone = domain;
- di.masters = bbd.d_masters;
+ di.primaries = bbd.d_primaries;
di.last_check = bbd.d_lastcheck;
di.backend = this;
di.kind = bbd.d_kind;
ret << "\t On-disk file: " << info.d_filename << " (" << info.d_ctime << ")" << std::endl;
ret << "\t Kind: ";
switch (info.d_kind) {
- case DomainInfo::Master:
- ret << "Master";
+ case DomainInfo::Primary:
+ ret << "Primary";
break;
- case DomainInfo::Slave:
- ret << "Slave";
+ case DomainInfo::Secondary:
+ ret << "Secondary";
break;
default:
ret << "Native";
}
ret << std::endl;
- ret << "\t Masters: " << std::endl;
- for (const auto& master : info.d_masters) {
- ret << "\t\t - " << master.toStringWithPort() << std::endl;
+ ret << "\t Primaries: " << std::endl;
+ for (const auto& primary : info.d_primaries) {
+ ret << "\t\t - " << primary.toStringWithPort() << std::endl;
}
ret << "\t Also Notify: " << std::endl;
for (const auto& also : info.d_also_notify) {
// overwrite what we knew about the domain
bbd.d_name = domain.name;
bool filenameChanged = (bbd.d_filename != domain.filename);
- bool addressesChanged = (bbd.d_masters != domain.masters || bbd.d_also_notify != domain.alsoNotify);
+ bool addressesChanged = (bbd.d_primaries != domain.primaries || bbd.d_also_notify != domain.alsoNotify);
bbd.d_filename = domain.filename;
- bbd.d_masters = domain.masters;
+ bbd.d_primaries = domain.primaries;
bbd.d_also_notify = domain.alsoNotify;
DomainInfo::DomainKind kind = DomainInfo::Native;
if (domain.type == "primary" || domain.type == "master") {
- kind = DomainInfo::Master;
+ kind = DomainInfo::Primary;
}
if (domain.type == "secondary" || domain.type == "slave") {
- kind = DomainInfo::Slave;
+ kind = DomainInfo::Secondary;
}
bool kindChanged = (bbd.d_kind != kind);
catch (std::system_error& ae) {
ostringstream msg;
if (ae.code().value() == ENOENT && isNew && domain.type == "slave")
- msg << " error at " + nowTime() << " no file found for new slave domain '" << domain.name << "'. Has not been AXFR'd yet";
+ msg << " error at " + nowTime() << " no file found for new secondary domain '" << domain.name << "'. Has not been AXFR'd yet";
else
msg << " error at " + nowTime() + " parsing '" << domain.name << "' from file '" << domain.filename << "': " << ae.what();
if (!bbd.d_loaded) {
d_handle.reset();
- throw DBException("Zone for '" + d_handle.domain.toLogString() + "' in '" + bbd.d_filename + "' not loaded (file missing, corrupt or master dead)"); // fsck
+ throw DBException("Zone for '" + d_handle.domain.toLogString() + "' in '" + bbd.d_filename + "' not loaded (file missing, corrupt or primary dead)"); // fsck
}
d_handle.d_records = bbd.d_records.get();
bool Bind2Backend::autoPrimariesList(std::vector<AutoPrimary>& primaries)
{
- if (getArg("supermaster-config").empty())
+ if (getArg("autoprimary-config").empty())
return false;
- ifstream c_if(getArg("supermasters"), std::ios::in);
+ ifstream c_if(getArg("autoprimaries"), std::ios::in);
if (!c_if) {
- g_log << Logger::Error << "Unable to open supermasters file for read: " << stringerror() << endl;
+ g_log << Logger::Error << "Unable to open autoprimaries file for read: " << stringerror() << endl;
return false;
}
return true;
}
-bool Bind2Backend::superMasterBackend(const string& ip, const DNSName& /* domain */, const vector<DNSResourceRecord>& /* nsset */, string* /* nameserver */, string* account, DNSBackend** db)
+bool Bind2Backend::autoPrimaryBackend(const string& ip, const DNSName& /* domain */, const vector<DNSResourceRecord>& /* nsset */, string* /* nameserver */, string* account, DNSBackend** db)
{
// Check whether we have a configfile available.
- if (getArg("supermaster-config").empty())
+ if (getArg("autoprimary-config").empty())
return false;
- ifstream c_if(getArg("supermasters").c_str(), std::ios::in); // this was nocreate?
+ ifstream c_if(getArg("autoprimaries").c_str(), std::ios::in); // this was nocreate?
if (!c_if) {
- g_log << Logger::Error << "Unable to open supermasters file for read: " << stringerror() << endl;
+ g_log << Logger::Error << "Unable to open autoprimaries file for read: " << stringerror() << endl;
return false;
}
if (sip != ip) // ip not found in authorization list - reject
return false;
- // ip authorized as supermaster - accept
+ // ip authorized as autoprimary - accept
*db = this;
if (saccount.length() > 0)
*account = saccount.c_str();
return bbd;
}
-bool Bind2Backend::createSlaveDomain(const string& ip, const DNSName& domain, const string& /* nameserver */, const string& account)
+bool Bind2Backend::createSecondaryDomain(const string& ip, const DNSName& domain, const string& /* nameserver */, const string& account)
{
- string filename = getArg("supermaster-destdir") + '/' + domain.toStringNoDot();
+ string filename = getArg("autoprimary-destdir") + '/' + domain.toStringNoDot();
g_log << Logger::Warning << d_logprefix
<< " Writing bind config zone statement for superslave zone '" << domain
- << "' from supermaster " << ip << endl;
+ << "' from autoprimary " << ip << endl;
{
- std::lock_guard<std::mutex> l2(s_supermaster_config_lock);
+ std::lock_guard<std::mutex> l2(s_autosecondary_config_lock);
- ofstream c_of(getArg("supermaster-config").c_str(), std::ios::app);
+ ofstream c_of(getArg("autoprimary-config").c_str(), std::ios::app);
if (!c_of) {
- g_log << Logger::Error << "Unable to open supermaster configfile for append: " << stringerror() << endl;
- throw DBException("Unable to open supermaster configfile for append: " + stringerror());
+ g_log << Logger::Error << "Unable to open autoprimary configfile for append: " << stringerror() << endl;
+ throw DBException("Unable to open autoprimary configfile for append: " + stringerror());
}
c_of << endl;
- c_of << "# Superslave zone '" << domain.toString() << "' (added: " << nowTime() << ") (account: " << account << ')' << endl;
+ c_of << "# AutoSecondary zone '" << domain.toString() << "' (added: " << nowTime() << ") (account: " << account << ')' << endl;
c_of << "zone \"" << domain.toStringNoDot() << "\" {" << endl;
c_of << "\ttype secondary;" << endl;
c_of << "\tfile \"" << filename << "\";" << endl;
}
BB2DomainInfo bbd = createDomainEntry(domain, filename);
- bbd.d_kind = DomainInfo::Slave;
- bbd.d_masters.push_back(ComboAddress(ip, 53));
+ bbd.d_kind = DomainInfo::Secondary;
+ bbd.d_primaries.push_back(ComboAddress(ip, 53));
bbd.setCtime();
safePutBBDomainInfo(bbd);
return true;
}
-bool Bind2Backend::searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result)
+bool Bind2Backend::searchRecords(const string& pattern, size_t maxResults, vector<DNSResourceRecord>& result)
{
SimpleMatch sm(pattern, true);
static bool mustlog = ::arg().mustDo("query-logging");
shared_ptr<const recordstorage_t> rhandle = h.d_records.get();
- for (recordstorage_t::const_iterator ri = rhandle->begin(); result.size() < static_cast<vector<DNSResourceRecord>::size_type>(maxResults) && ri != rhandle->end(); ri++) {
+ for (recordstorage_t::const_iterator ri = rhandle->begin(); result.size() < maxResults && ri != rhandle->end(); ri++) {
DNSName name = ri->qname.empty() ? i.d_name : (ri->qname + i.d_name);
if (sm.match(name) || sm.match(ri->content)) {
DNSResourceRecord r;
declare(suffix, "ignore-broken-records", "Ignore records that are out-of-bound for the zone.", "no");
declare(suffix, "config", "Location of named.conf", "");
declare(suffix, "check-interval", "Interval for zonefile changes", "0");
- declare(suffix, "supermaster-config", "Location of (part of) named.conf where pdns can write zone-statements to", "");
- declare(suffix, "supermasters", "List of IP-addresses of supermasters", "");
- declare(suffix, "supermaster-destdir", "Destination directory for newly added slave zones", ::arg()["config-dir"]);
+ declare(suffix, "autoprimary-config", "Location of (part of) named.conf where pdns can write zone-statements to", "");
+ declare(suffix, "autoprimaries", "List of IP-addresses of autoprimaries", "");
+ declare(suffix, "autoprimary-destdir", "Destination directory for newly added secondary zones", ::arg()["config-dir"]);
declare(suffix, "dnssec-db", "Filename to store & access our DNSSEC metadatabase, empty for none", "");
declare(suffix, "dnssec-db-journal-mode", "SQLite3 journal mode", "WAL");
declare(suffix, "hybrid", "Store DNSSEC metadata in other backend", "no");
DomainInfo::DomainKind d_kind{DomainInfo::Native}; //!< the kind of domain
string d_filename; //!< full absolute filename of the zone on disk
string d_status; //!< message describing status of a domain, for human consumption
- vector<ComboAddress> d_masters; //!< IP address of the master of this domain
+ vector<ComboAddress> d_primaries; //!< IP address of the primary of this domain
set<string> d_also_notify; //!< IP list of hosts to also notify
LookButDontTouch<recordstorage_t> d_records; //!< the actual records belonging to this domain
time_t d_ctime{0}; //!< last known ctime of the file on disk
time_t d_lastcheck{0}; //!< last time domain was checked for freshness
- uint32_t d_lastnotified{0}; //!< Last serial number we notified our slaves of
+ uint32_t d_lastnotified{0}; //!< Last serial number we notified our secondaries of
unsigned int d_id{0}; //!< internal id of the domain
mutable bool d_checknow; //!< if this domain has been flagged for a check
bool d_loaded{false}; //!< if a domain is loaded
public:
Bind2Backend(const string& suffix = "", bool loadZones = true);
~Bind2Backend();
- void getUnfreshSlaveInfos(vector<DomainInfo>* unfreshDomains) override;
- void getUpdatedMasters(vector<DomainInfo>& changedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
+ void getUnfreshSecondaryInfos(vector<DomainInfo>* unfreshDomains) override;
+ void getUpdatedPrimaries(vector<DomainInfo>& changedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getSerial = true) override;
time_t getCtime(const string& fname);
// DNSSEC
bool commitTransaction() override;
bool abortTransaction() override;
void alsoNotifies(const DNSName& domain, set<string>* ips) override;
- bool searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result) override;
+ bool searchRecords(const string& pattern, size_t maxResults, vector<DNSResourceRecord>& result) override;
// the DNSSEC related (getDomainMetadata has broader uses too)
bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta) override;
// for autoprimary support
bool autoPrimariesList(std::vector<AutoPrimary>& primaries) override;
- bool superMasterBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** db) override;
- static std::mutex s_supermaster_config_lock;
- bool createSlaveDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account) override;
+ bool autoPrimaryBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** db) override;
+ static std::mutex s_autosecondary_config_lock;
+ bool createSecondaryDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account) override;
private:
void setupDNSSEC();
static int maxNSEC3Iterations = ::arg().asNum("max-nsec3-iterations");
if (ns3p) {
- auto tmp = std::dynamic_pointer_cast<NSEC3PARAMRecordContent>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, value));
+ auto tmp = std::dynamic_pointer_cast<NSEC3PARAMRecordContent>(DNSRecordContent::make(QType::NSEC3PARAM, 1, value));
*ns3p = *tmp;
if (ns3p->d_iterations > maxNSEC3Iterations) {
#include <fstream>
#include <filesystem>
#include <utility>
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
#include <yaml-cpp/yaml.h>
+#pragma GCC diagnostic pop
ReadWriteLock GeoIPBackend::s_state_lock;
WriteLock writeLock(&s_state_lock);
setArgPrefix("geoip" + suffix);
if (!getArg("dnssec-keydir").empty()) {
- DIR* dir = opendir(getArg("dnssec-keydir").c_str());
- if (dir == nullptr) {
+ auto dirHandle = std::unique_ptr<DIR, decltype(&closedir)>(opendir(getArg("dnssec-keydir").c_str()), closedir);
+ if (!dirHandle) {
throw PDNSException("dnssec-keydir " + getArg("dnssec-keydir") + " does not exist");
}
d_dnssec = true;
- closedir(dir);
}
if (s_rc == 0) { // first instance gets to open everything
initialize();
declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,options,catalog,account from domains where name=?");
- declare(suffix, "info-all-slaves-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')");
- declare(suffix, "supermaster-query", "", "select account from supermasters where ip=? and nameserver=?");
- declare(suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=? and account=?");
- declare(suffix, "supermaster-add", "", "insert into supermasters (ip, nameserver, account) values (?,?,?)");
+ declare(suffix, "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')");
+ declare(suffix, "autoprimary-query", "", "select account from supermasters where ip=? and nameserver=?");
+ declare(suffix, "autoprimary-name-to-ips", "", "select ip,account from supermasters where nameserver=? and account=?");
+ declare(suffix, "autoprimary-add", "", "insert into supermasters (ip, nameserver, account) values (?,?,?)");
declare(suffix, "autoprimary-remove", "", "delete from supermasters where ip = ? and nameserver = ?");
declare(suffix, "list-autoprimaries", "", "select ip,nameserver,account from supermasters");
declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0");
declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and type=? and disabled=0");
- declare(suffix, "update-master-query", "", "update domains set master=? where name=?");
+ declare(suffix, "update-primary-query", "", "update domains set master=? where name=?");
declare(suffix, "update-kind-query", "", "update domains set type=? where name=?");
declare(suffix, "update-options-query", "", "update domains set options=? where name=?");
declare(suffix, "update-catalog-query", "", "update domains set catalog=? where name=?");
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-master-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')");
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, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,options,catalog,account from domains where name=?");
- declare(suffix, "info-all-slaves-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')");
- declare(suffix, "supermaster-query", "", "select account from supermasters where ip=? and nameserver=?");
- declare(suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=? and account=?");
- declare(suffix, "supermaster-add", "", "insert into supermasters (ip, nameserver, account) values (?,?,?)");
+ declare(suffix, "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')");
+ declare(suffix, "autoprimary-query", "", "select account from supermasters where ip=? and nameserver=?");
+ declare(suffix, "autoprimary-name-to-ips", "", "select ip,account from supermasters where nameserver=? and account=?");
+ declare(suffix, "autoprimary-add", "", "insert into supermasters (ip, nameserver, account) values (?,?,?)");
declare(suffix, "autoprimary-remove", "", "delete from supermasters where ip = ? and nameserver = ?");
declare(suffix, "list-autoprimaries", "", "select ip,nameserver,account from supermasters");
declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0");
declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and type=? and disabled=0");
- declare(suffix, "update-master-query", "", "update domains set master=? where name=?");
+ declare(suffix, "update-primary-query", "", "update domains set master=? where name=?");
declare(suffix, "update-kind-query", "", "update domains set type=? where name=?");
declare(suffix, "update-options-query", "", "update domains set options=? where name=?");
declare(suffix, "update-catalog-query", "", "update domains set catalog=? where name=?");
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-master-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')");
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, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,options,catalog,account from domains where name=$1");
- declare(suffix, "info-all-slaves-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')");
- declare(suffix, "supermaster-query", "", "select account from supermasters where ip=$1 and nameserver=$2");
- declare(suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=$1 and account=$2");
- declare(suffix, "supermaster-add", "", "insert into supermasters (ip, nameserver, account) values ($1,$2,$3)");
+ declare(suffix, "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')");
+ declare(suffix, "autoprimary-query", "", "select account from supermasters where ip=$1 and nameserver=$2");
+ declare(suffix, "autoprimary-name-to-ips", "", "select ip,account from supermasters where nameserver=$1 and account=$2");
+ declare(suffix, "autoprimary-add", "", "insert into supermasters (ip, nameserver, account) values ($1,$2,$3)");
declare(suffix, "autoprimary-remove", "", "delete from supermasters where ip = $1 and nameserver = $2");
declare(suffix, "list-autoprimaries", "", "select ip,nameserver,account from supermasters");
declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=$1 where domain_id=$2 and name=$3 and disabled=false");
declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=$1 where domain_id=$2 and name=$3 and type=$4 and disabled=false");
- declare(suffix, "update-master-query", "", "update domains set master=$1 where name=$2");
+ declare(suffix, "update-primary-query", "", "update domains set master=$1 where name=$2");
declare(suffix, "update-kind-query", "", "update domains set type=$1 where name=$2");
declare(suffix, "update-options-query", "", "update domains set options=$1 where name=$2");
declare(suffix, "update-catalog-query", "", "update domains set catalog=$1 where name=$2");
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-master-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')");
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, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,options,catalog,account from domains where name=:domain");
- declare(suffix, "info-all-slaves-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')");
- declare(suffix, "supermaster-query", "", "select account from supermasters where ip=:ip and nameserver=:nameserver");
- declare(suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=:nameserver and account=:account");
- declare(suffix, "supermaster-add", "", "insert into supermasters (ip, nameserver, account) values (:ip,:nameserver,:account)");
+ declare(suffix, "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')");
+ declare(suffix, "autoprimary-query", "", "select account from supermasters where ip=:ip and nameserver=:nameserver");
+ declare(suffix, "autoprimary-name-to-ips", "", "select ip,account from supermasters where nameserver=:nameserver and account=:account");
+ declare(suffix, "autoprimary-add", "", "insert into supermasters (ip, nameserver, account) values (:ip,:nameserver,:account)");
declare(suffix, "autoprimary-remove", "", "delete from supermasters where ip = :ip and nameserver = :nameserver");
declare(suffix, "list-autoprimaries", "", "select ip,nameserver,account from supermasters");
- declare(suffix, "insert-zone-query", "", "insert into domains (type,name,master,account,last_check,notified_serial) values(:type, :domain, :masters, :account, null, null)");
+ declare(suffix, "insert-zone-query", "", "insert into domains (type,name,master,account,last_check,notified_serial) values(:type, :domain, :primaries, :account, null, null)");
declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (:content,:ttl,:priority,:qtype,:domain_id,:disabled,:qname,:ordername,:auth)");
declare(suffix, "insert-empty-non-terminal-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth,ttl,prio,content) values (null,:domain_id,0,:qname,:ordername,:auth,null,null,null)");
declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=:auth where domain_id=:domain_id and name=:qname and disabled=0");
declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=:auth where domain_id=:domain_id and name=:qname and type=:qtype and disabled=0");
- declare(suffix, "update-master-query", "", "update domains set master=:master where name=:domain");
+ declare(suffix, "update-primary-query", "", "update domains set master=:master where name=:domain");
declare(suffix, "update-kind-query", "", "update domains set type=:kind where name=:domain");
declare(suffix, "update-options-query", "", "update domains set options=:options where name=:domain");
declare(suffix, "update-catalog-query", "", "update domains set catalog=:catalog where name=:domain");
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-master-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')");
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");
ldapauthenticator.hh ldapauthenticator_p.hh ldapauthenticator.cc \
ldapbackend.cc ldapbackend.hh \
ldaputils.hh ldaputils.cc \
- master.cc \
native.cc \
powerldap.cc powerldap.hh \
+ primary.cc \
utils.hh
libldapbackend_la_LDFLAGS = -module -avoid-version
-ldapbackend.lo master.lo native.lo powerldap.lo ldaputils.lo ldapauthenticator.lo
+ldapbackend.lo native.lo powerldap.lo primary.lo ldaputils.lo ldapauthenticator.lo
bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getSerial = true) override;
- // Master backend
- void getUpdatedMasters(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
+ // Primary backend
+ void getUpdatedPrimaries(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
void setNotified(uint32_t id, uint32_t serial) override;
};
if (result.count("PdnsDomainMaster") && !result["PdnsDomainMaster"].empty()) {
for (const auto& m : result["PdnsDomainMaster"])
- di.masters.emplace_back(m, 53);
+ di.primaries.emplace_back(m, 53);
}
if (result.count("PdnsDomainType") && !result["PdnsDomainType"].empty()) {
string kind = result["PdnsDomainType"][0];
if (kind == "master")
- di.kind = DomainInfo::Master;
+ di.kind = DomainInfo::Primary;
else if (kind == "slave")
- di.kind = DomainInfo::Slave;
+ di.kind = DomainInfo::Secondary;
else
di.kind = DomainInfo::Native;
}
#include "ldapbackend.hh"
#include <cstdlib>
-void LdapBackend::getUpdatedMasters(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
+void LdapBackend::getUpdatedPrimaries(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
{
string filter;
PowerLDAP::SearchResult::Ptr search;
NULL};
try {
- // First get all domains on which we are master.
+ // First get all domains on which we are primary.
filter = strbind(":target:", "&(SOARecord=*)(PdnsDomainId=*)", getArg("filter-axfr"));
search = d_pldap->search(getArg("basedn"), LDAP_SCOPE_SUBTREE, filter, attronly);
}
catch (LDAPNoConnection& lnc) {
g_log << Logger::Warning << d_myname << " Connection to LDAP lost, trying to reconnect" << endl;
if (reconnect())
- this->getUpdatedMasters(domains, catalogs, catalogHashes);
+ this->getUpdatedPrimaries(domains, catalogs, catalogHashes);
else
throw PDNSException("Failed to reconnect to LDAP server");
}
ar& g.zone;
ar& g.last_check;
ar& g.account;
- ar& g.masters;
+ ar& g.primaries;
ar& g.id;
ar& g.notified_serial;
ar& g.kind;
ar& g.zone;
ar& g.last_check;
ar& g.account;
- ar& g.masters;
+ ar& g.primaries;
ar& g.id;
ar& g.notified_serial;
ar& g.kind;
static std::string serializeContent(uint16_t qtype, const DNSName& domain, const std::string& content)
{
- auto drc = DNSRecordContent::mastermake(qtype, QClass::IN, content);
+ auto drc = DNSRecordContent::make(qtype, QClass::IN, content);
return drc->serialize(domain, false);
}
});
}
-bool LMDBBackend::setMasters(const DNSName& domain, const vector<ComboAddress>& masters)
+bool LMDBBackend::setPrimaries(const DNSName& domain, const vector<ComboAddress>& primaries)
{
- return genChangeDomain(domain, [&masters](DomainInfo& di) {
- di.masters = masters;
+ return genChangeDomain(domain, [&primaries](DomainInfo& di) {
+ di.primaries = primaries;
});
}
-bool LMDBBackend::createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& masters, const string& account)
+bool LMDBBackend::createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& primaries, const string& account)
{
DomainInfo di;
di.zone = domain;
di.kind = kind;
- di.masters = masters;
+ di.primaries = primaries;
di.account = account;
txn.put(di, 0, d_random_ids);
});
}
-void LMDBBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains)
+void LMDBBackend::getUnfreshSecondaryInfos(vector<DomainInfo>* domains)
{
uint32_t serial;
time_t now = time(0);
});
}
-void LMDBBackend::getUpdatedMasters(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
+void LMDBBackend::getUpdatedPrimaries(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
{
CatalogInfo ci;
try {
getAllDomainsFiltered(&scratch, [&catalog, &members, &type](DomainInfo& di) {
- if ((type == CatalogInfo::CatalogType::Producer && di.kind != DomainInfo::Master) || (type == CatalogInfo::CatalogType::Consumer && di.kind != DomainInfo::Slave) || di.catalog != catalog) {
+ if ((type == CatalogInfo::CatalogType::Producer && di.kind != DomainInfo::Primary) || (type == CatalogInfo::CatalogType::Consumer && di.kind != DomainInfo::Secondary) || di.catalog != catalog) {
return false;
}
CatalogInfo ci;
ci.d_id = di.id;
ci.d_zone = di.zone;
- ci.d_primaries = di.masters;
+ ci.d_primaries = di.primaries;
try {
ci.fromJson(di.options, type);
}
bool list(const DNSName& target, int id, bool include_disabled) override;
bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getserial = true) override;
- bool createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& masters, const string& account) override;
+ bool createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& primaries, const string& account) override;
bool startTransaction(const DNSName& domain, int domain_id = -1) override;
bool commitTransaction() override;
bool get(DNSZoneRecord& dzr) override;
// secondary support
- void getUnfreshSlaveInfos(vector<DomainInfo>* domains) override;
+ void getUnfreshSecondaryInfos(vector<DomainInfo>* domains) override;
void setStale(uint32_t domain_id) override;
void setFresh(uint32_t domain_id) override;
// primary support
- void getUpdatedMasters(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
+ void getUpdatedPrimaries(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
void setNotified(uint32_t id, uint32_t serial) override;
// catalog zones
bool setOptions(const DNSName& domain, const std::string& options) override;
bool setCatalog(const DNSName& domain, const DNSName& options) override;
- bool setMasters(const DNSName& domain, const vector<ComboAddress>& masters) override;
+ bool setPrimaries(const DNSName& domain, const vector<ComboAddress>& primaries) override;
bool setKind(const DNSName& domain, const DomainInfo::DomainKind kind) override;
bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta) override;
bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override
else if (item.first == "last_check")
di.last_check = static_cast<time_t>(boost::get<long>(item.second));
else if (item.first == "masters")
- for (const auto& master : boost::get<vector<string>>(item.second))
- di.masters.push_back(ComboAddress(master, 53));
+ for (const auto& primary : boost::get<vector<string>>(item.second))
+ di.primaries.push_back(ComboAddress(primary, 53));
else if (item.first == "id")
di.id = static_cast<int>(boost::get<long>(item.second));
else if (item.first == "notified_serial")
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <limits>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
{
di.id = intFromJson(obj, "id", -1);
di.zone = DNSName(stringFromJson(obj, "zone"));
- for (const auto& master : obj["masters"].array_items()) {
- di.masters.emplace_back(master.string_value(), 53);
+ for (const auto& primary : obj["masters"].array_items()) {
+ di.primaries.emplace_back(primary.string_value(), 53);
}
di.notified_serial = static_cast<unsigned int>(doubleFromJson(obj, "notified_serial", 0));
kind = stringFromJson(obj, "kind");
}
if (kind == "master") {
- di.kind = DomainInfo::Master;
+ di.kind = DomainInfo::Primary;
}
else if (kind == "slave") {
- di.kind = DomainInfo::Slave;
+ di.kind = DomainInfo::Secondary;
}
else {
di.kind = DomainInfo::Native;
}
}
-bool RemoteBackend::superMasterBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** ddb)
+bool RemoteBackend::autoPrimaryBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** ddb)
{
Json::array rrset;
return true;
}
-bool RemoteBackend::createSlaveDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account)
+bool RemoteBackend::createSecondaryDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account)
{
Json query = Json::object{
{"method", "createSlaveDomain"},
return asString(answer["result"]);
}
-bool RemoteBackend::searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result)
+bool RemoteBackend::searchRecords(const string& pattern, size_t maxResults, vector<DNSResourceRecord>& result)
{
+ const auto intMax = static_cast<decltype(maxResults)>(std::numeric_limits<int>::max());
+ if (maxResults > intMax) {
+ throw std::out_of_range("Remote backend: length of list of result (" + std::to_string(maxResults) + ") is larger than what the JSON library supports for serialization (" + std::to_string(intMax) + ")");
+ }
+
Json query = Json::object{
{"method", "searchRecords"},
- {"parameters", Json::object{{"pattern", pattern}, {"maxResults", maxResults}}}};
+ {"parameters", Json::object{{"pattern", pattern}, {"maxResults", static_cast<int>(maxResults)}}}};
Json answer;
if (!this->send(query) || !this->recv(answer)) {
return true;
}
-bool RemoteBackend::searchComments(const string& /* pattern */, int /* maxResults */, vector<Comment>& /* result */)
+bool RemoteBackend::searchComments(const string& /* pattern */, size_t /* maxResults */, vector<Comment>& /* result */)
{
// FIXME: Implement Comment API
return false;
}
}
-void RemoteBackend::getUpdatedMasters(vector<DomainInfo>& domains, std::unordered_set<DNSName>& /* catalogs */, CatalogHashMap& /* catalogHashes */)
+void RemoteBackend::getUpdatedPrimaries(vector<DomainInfo>& domains, std::unordered_set<DNSName>& /* catalogs */, CatalogHashMap& /* catalogHashes */)
{
Json query = Json::object{
{"method", "getUpdatedMasters"},
}
}
-void RemoteBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains)
+void RemoteBackend::getUnfreshSecondaryInfos(vector<DomainInfo>* domains)
{
Json query = Json::object{
{"method", "getUnfreshSlaveInfos"},
bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getSerial = true) override;
void setNotified(uint32_t id, uint32_t serial) override;
bool doesDNSSEC() override;
- bool superMasterBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** ddb) override;
- bool createSlaveDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account) override;
+ bool autoPrimaryBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** ddb) override;
+ bool createSecondaryDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account) override;
bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset) override;
bool feedRecord(const DNSResourceRecord& r, const DNSName& ordername, bool ordernameIsNSEC3 = false) override;
bool feedEnts(int domain_id, map<DNSName, bool>& nonterm) override;
bool deleteTSIGKey(const DNSName& name) override;
bool getTSIGKeys(std::vector<struct TSIGKey>& keys) override;
string directBackendCmd(const string& querystr) override;
- bool searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result) override;
- bool searchComments(const string& pattern, int maxResults, vector<Comment>& result) override;
+ bool searchRecords(const string& pattern, size_t maxResults, vector<DNSResourceRecord>& result) override;
+ bool searchComments(const string& pattern, size_t maxResults, vector<Comment>& result) override;
void getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled) override;
- void getUpdatedMasters(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
- void getUnfreshSlaveInfos(vector<DomainInfo>* domains) override;
+ void getUpdatedPrimaries(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
+ void getUnfreshSecondaryInfos(vector<DomainInfo>* domains) override;
void setStale(uint32_t domain_id) override;
void setFresh(uint32_t domain_id) override;
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <memory>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
RemoteLoader();
};
-DNSBackend* be;
+std::unique_ptr<DNSBackend> backendUnderTest;
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
{
RemotebackendSetup()
{
- be = nullptr;
+ backendUnderTest = nullptr;
try {
// setup minimum arguments
::arg().set("module-dir") = "./.libs";
// then get us a instance of it
::arg().set("remote-connection-string") = "http:url=http://localhost:62434/dns";
::arg().set("remote-dnssec") = "yes";
- be = BackendMakers().all()[0];
+ backendUnderTest = std::move(BackendMakers().all()[0]);
}
catch (PDNSException& ex) {
BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason);
RemoteLoader();
};
-DNSBackend* be;
+std::unique_ptr<DNSBackend> backendUnderTest;
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
{
RemotebackendSetup()
{
- be = nullptr;
+ backendUnderTest = nullptr;
try {
// setup minimum arguments
::arg().set("module-dir") = "./.libs";
// then get us a instance of it
::arg().set("remote-connection-string") = "http:url=http://localhost:62434/dns/endpoint.json,post=1,post_json=1";
::arg().set("remote-dnssec") = "yes";
- be = BackendMakers().all()[0];
+ backendUnderTest = std::move(BackendMakers().all()[0]);
}
catch (PDNSException& ex) {
BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason);
RemoteLoader();
};
-DNSBackend* be;
+std::unique_ptr<DNSBackend> backendUnderTest;
struct RemotebackendSetup
{
RemotebackendSetup()
{
- be = nullptr;
+ backendUnderTest = nullptr;
try {
// setup minimum arguments
::arg().set("module-dir") = "./.libs";
// then get us a instance of it
::arg().set("remote-connection-string") = "pipe:command=unittest_pipe.rb";
::arg().set("remote-dnssec") = "yes";
- be = BackendMakers().all()[0];
+ backendUnderTest = std::move(BackendMakers().all()[0]);
// load few record types to help out
SOARecordContent::report();
NSRecordContent::report();
RemoteLoader();
};
-DNSBackend* be;
+std::unique_ptr<DNSBackend> backendUnderTest;
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
{
RemotebackendSetup()
{
- be = nullptr;
+ backendUnderTest = nullptr;
try {
// setup minimum arguments
::arg().set("module-dir") = "./.libs";
// then get us a instance of it
::arg().set("remote-connection-string") = "http:url=http://localhost:62434/dns,post=1";
::arg().set("remote-dnssec") = "yes";
- be = BackendMakers().all()[0];
+ backendUnderTest = std::move(BackendMakers().all()[0]);
}
catch (PDNSException& ex) {
BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason);
RemoteLoader();
};
-DNSBackend* be;
+std::unique_ptr<DNSBackend> backendUnderTest;
struct RemotebackendSetup
{
RemotebackendSetup()
{
- be = nullptr;
+ backendUnderTest = nullptr;
try {
// setup minimum arguments
::arg().set("module-dir") = "./.libs";
// then get us a instance of it
::arg().set("remote-connection-string") = "unix:path=/tmp/remotebackend.sock";
::arg().set("remote-dnssec") = "yes";
- be = BackendMakers().all()[0];
+ backendUnderTest = std::move(BackendMakers().all()[0]);
// load few record types to help out
SOARecordContent::report();
NSRecordContent::report();
RemoteLoader();
};
-DNSBackend* be;
+std::unique_ptr<DNSBackend> backendUnderTest;
#ifdef REMOTEBACKEND_ZEROMQ
#include <boost/test/unit_test.hpp>
{
RemotebackendSetup()
{
- be = nullptr;
+ backendUnderTest = nullptr;
try {
// setup minimum arguments
::arg().set("module-dir") = "./.libs";
// then get us a instance of it
::arg().set("remote-connection-string") = "zeromq:endpoint=ipc:///tmp/remotebackend.0";
::arg().set("remote-dnssec") = "yes";
- be = BackendMakers().all()[0];
+ backendUnderTest = std::move(BackendMakers().all()[0]);
// load few record types to help out
SOARecordContent::report();
NSRecordContent::report();
#include "test-remotebackend-keys.hh"
-extern DNSBackend* be;
+extern std::unique_ptr<DNSBackend> backendUnderTest;
BOOST_AUTO_TEST_SUITE(test_remotebackend_so)
BOOST_AUTO_TEST_CASE(test_method_lookup)
{
BOOST_TEST_MESSAGE("Testing lookup method");
- DNSResourceRecord rr;
- be->lookup(QType(QType::SOA), DNSName("unit.test."));
+ DNSResourceRecord resourceRecord;
+ backendUnderTest->lookup(QType(QType::SOA), DNSName("unit.test."));
// then try to get()
- BOOST_CHECK(be->get(rr)); // and this should be TRUE.
+ BOOST_CHECK(backendUnderTest->get(resourceRecord)); // and this should be TRUE.
// then we check rr contains what we expect
- BOOST_CHECK_EQUAL(rr.qname.toString(), "unit.test.");
- BOOST_CHECK_MESSAGE(rr.qtype == QType::SOA, "returned qtype was not SOA");
- BOOST_CHECK_EQUAL(rr.content, "ns.unit.test. hostmaster.unit.test. 1 2 3 4 5");
- BOOST_CHECK_EQUAL(rr.ttl, 300);
+ BOOST_CHECK_EQUAL(resourceRecord.qname.toString(), "unit.test.");
+ BOOST_CHECK_MESSAGE(resourceRecord.qtype == QType::SOA, "returned qtype was not SOA");
+ BOOST_CHECK_EQUAL(resourceRecord.content, "ns.unit.test. hostmaster.unit.test. 1 2 3 4 5");
+ BOOST_CHECK_EQUAL(resourceRecord.ttl, 300);
}
BOOST_AUTO_TEST_CASE(test_method_lookup_empty)
{
BOOST_TEST_MESSAGE("Testing lookup method with empty result");
- DNSResourceRecord rr;
- be->lookup(QType(QType::SOA), DNSName("empty.unit.test."));
+ DNSResourceRecord resourceRecord;
+ backendUnderTest->lookup(QType(QType::SOA), DNSName("empty.unit.test."));
// then try to get()
- BOOST_CHECK(!be->get(rr)); // and this should be FALSE
+ BOOST_CHECK(!backendUnderTest->get(resourceRecord)); // and this should be FALSE
}
BOOST_AUTO_TEST_CASE(test_method_list)
{
int record_count = 0;
- DNSResourceRecord rr;
+ DNSResourceRecord resourceRecord;
BOOST_TEST_MESSAGE("Testing list method");
- be->list(DNSName("unit.test."), -1);
- while (be->get(rr)) {
+ backendUnderTest->list(DNSName("unit.test."), -1);
+ while (backendUnderTest->get(resourceRecord)) {
record_count++;
}
BOOST_AUTO_TEST_CASE(test_method_doesDNSSEC)
{
BOOST_TEST_MESSAGE("Testing doesDNSSEC method");
- BOOST_CHECK(be->doesDNSSEC()); // should be true
+ BOOST_CHECK(backendUnderTest->doesDNSSEC()); // should be true
}
BOOST_AUTO_TEST_CASE(test_method_setDomainMetadata)
std::vector<std::string> meta;
meta.emplace_back("VALUE");
BOOST_TEST_MESSAGE("Testing setDomainMetadata method");
- BOOST_CHECK(be->setDomainMetadata(DNSName("unit.test."), "TEST", meta));
+ BOOST_CHECK(backendUnderTest->setDomainMetadata(DNSName("unit.test."), "TEST", meta));
}
BOOST_AUTO_TEST_CASE(test_method_alsoNotifies)
{
- BOOST_CHECK(be->setDomainMetadata(DNSName("unit.test."), "ALSO-NOTIFY", {"192.0.2.1"}));
+ BOOST_CHECK(backendUnderTest->setDomainMetadata(DNSName("unit.test."), "ALSO-NOTIFY", {"192.0.2.1"}));
std::set<std::string> alsoNotifies;
BOOST_TEST_MESSAGE("Testing alsoNotifies method");
- be->alsoNotifies(DNSName("unit.test."), &alsoNotifies);
+ backendUnderTest->alsoNotifies(DNSName("unit.test."), &alsoNotifies);
BOOST_CHECK_EQUAL(alsoNotifies.size(), 1);
if (!alsoNotifies.empty()) {
BOOST_CHECK_EQUAL(alsoNotifies.count("192.0.2.1"), 1);
}
- BOOST_CHECK(be->setDomainMetadata(DNSName("unit.test."), "ALSO-NOTIFY", std::vector<std::string>()));
+ BOOST_CHECK(backendUnderTest->setDomainMetadata(DNSName("unit.test."), "ALSO-NOTIFY", std::vector<std::string>()));
}
BOOST_AUTO_TEST_CASE(test_method_getDomainMetadata)
{
std::vector<std::string> meta;
BOOST_TEST_MESSAGE("Testing getDomainMetadata method");
- be->getDomainMetadata(DNSName("unit.test."), "TEST", meta);
+ backendUnderTest->getDomainMetadata(DNSName("unit.test."), "TEST", meta);
BOOST_CHECK_EQUAL(meta.size(), 1);
// in case we got more than one value, which would be unexpected
// but not fatal
{
std::map<std::string, std::vector<std::string>> meta;
BOOST_TEST_MESSAGE("Testing getAllDomainMetadata method");
- be->getAllDomainMetadata(DNSName("unit.test."), meta);
+ backendUnderTest->getAllDomainMetadata(DNSName("unit.test."), meta);
BOOST_CHECK_EQUAL(meta.size(), 1);
// in case we got more than one value, which would be unexpected
// but not fatal
BOOST_AUTO_TEST_CASE(test_method_addDomainKey)
{
BOOST_TEST_MESSAGE("Testing addDomainKey method");
- int64_t id = 0;
- be->addDomainKey(DNSName("unit.test."), k1, id);
- BOOST_CHECK_EQUAL(id, 1);
- be->addDomainKey(DNSName("unit.test."), k2, id);
- BOOST_CHECK_EQUAL(id, 2);
+ int64_t keyID = 0;
+ backendUnderTest->addDomainKey(DNSName("unit.test."), k1, keyID);
+ BOOST_CHECK_EQUAL(keyID, 1);
+ backendUnderTest->addDomainKey(DNSName("unit.test."), k2, keyID);
+ BOOST_CHECK_EQUAL(keyID, 2);
}
BOOST_AUTO_TEST_CASE(test_method_getDomainKeys)
std::vector<DNSBackend::KeyData> keys;
BOOST_TEST_MESSAGE("Testing getDomainKeys method");
// we expect to get two keys
- be->getDomainKeys(DNSName("unit.test."), keys);
+ backendUnderTest->getDomainKeys(DNSName("unit.test."), keys);
BOOST_CHECK_EQUAL(keys.size(), 2);
// in case we got more than 2 keys, which would be unexpected
// but not fatal
if (keys.size() > 1) {
// check that we have two keys
- for (DNSBackend::KeyData& kd : keys) {
- BOOST_CHECK(kd.id > 0);
- BOOST_CHECK(kd.flags == 256 || kd.flags == 257);
- BOOST_CHECK(kd.active == true);
- BOOST_CHECK(kd.published == true);
- BOOST_CHECK(kd.content.size() > 500);
+ for (DNSBackend::KeyData& keyData : keys) {
+ BOOST_CHECK(keyData.id > 0);
+ BOOST_CHECK(keyData.flags == 256 || keyData.flags == 257);
+ BOOST_CHECK(keyData.active == true);
+ BOOST_CHECK(keyData.published == true);
+ BOOST_CHECK(keyData.content.size() > 500);
}
}
}
BOOST_AUTO_TEST_CASE(test_method_deactivateDomainKey)
{
BOOST_TEST_MESSAGE("Testing deactivateDomainKey method");
- BOOST_CHECK(be->deactivateDomainKey(DNSName("unit.test."), 1));
+ BOOST_CHECK(backendUnderTest->deactivateDomainKey(DNSName("unit.test."), 1));
}
BOOST_AUTO_TEST_CASE(test_method_activateDomainKey)
{
BOOST_TEST_MESSAGE("Testing activateDomainKey method");
- BOOST_CHECK(be->activateDomainKey(DNSName("unit.test."), 1));
+ BOOST_CHECK(backendUnderTest->activateDomainKey(DNSName("unit.test."), 1));
}
BOOST_AUTO_TEST_CASE(test_method_removeDomainKey)
{
- BOOST_CHECK(be->removeDomainKey(DNSName("unit.test."), 2));
- BOOST_CHECK(be->removeDomainKey(DNSName("unit.test."), 1));
+ BOOST_CHECK(backendUnderTest->removeDomainKey(DNSName("unit.test."), 2));
+ BOOST_CHECK(backendUnderTest->removeDomainKey(DNSName("unit.test."), 1));
}
BOOST_AUTO_TEST_CASE(test_method_getBeforeAndAfterNamesAbsolute)
DNSName after;
BOOST_TEST_MESSAGE("Testing getBeforeAndAfterNamesAbsolute method");
- be->getBeforeAndAfterNamesAbsolute(-1, DNSName("middle.unit.test."), unhashed, before, after);
+ backendUnderTest->getBeforeAndAfterNamesAbsolute(-1, DNSName("middle.unit.test."), unhashed, before, after);
BOOST_CHECK_EQUAL(unhashed.toString(), "middle.");
BOOST_CHECK_EQUAL(before.toString(), "begin.");
BOOST_CHECK_EQUAL(after.toString(), "stop.");
std::string algorithm;
std::string content;
BOOST_TEST_MESSAGE("Testing setTSIGKey method");
- BOOST_CHECK_MESSAGE(be->setTSIGKey(DNSName("unit.test."), DNSName("hmac-md5."), "kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="), "did not return true");
+ BOOST_CHECK_MESSAGE(backendUnderTest->setTSIGKey(DNSName("unit.test."), DNSName("hmac-md5."), "kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="), "did not return true");
}
BOOST_AUTO_TEST_CASE(test_method_getTSIGKey)
DNSName algorithm;
std::string content;
BOOST_TEST_MESSAGE("Testing getTSIGKey method");
- be->getTSIGKey(DNSName("unit.test."), algorithm, content);
+ backendUnderTest->getTSIGKey(DNSName("unit.test."), algorithm, content);
BOOST_CHECK_EQUAL(algorithm.toString(), "hmac-md5.");
BOOST_CHECK_EQUAL(content, "kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=");
}
std::string algorithm;
std::string content;
BOOST_TEST_MESSAGE("Testing deleteTSIGKey method");
- BOOST_CHECK_MESSAGE(be->deleteTSIGKey(DNSName("unit.test.")), "did not return true");
+ BOOST_CHECK_MESSAGE(backendUnderTest->deleteTSIGKey(DNSName("unit.test.")), "did not return true");
}
BOOST_AUTO_TEST_CASE(test_method_getTSIGKeys)
{
std::vector<struct TSIGKey> keys;
BOOST_TEST_MESSAGE("Testing getTSIGKeys method");
- be->getTSIGKeys(keys);
+ backendUnderTest->getTSIGKeys(keys);
BOOST_CHECK(!keys.empty());
if (!keys.empty()) {
BOOST_CHECK_EQUAL(keys[0].name.toString(), "test.");
BOOST_AUTO_TEST_CASE(test_method_setNotified)
{
BOOST_TEST_MESSAGE("Testing setNotified method");
- be->setNotified(1, 2);
+ backendUnderTest->setNotified(1, 2);
BOOST_CHECK(true); // we check this on next step
}
BOOST_AUTO_TEST_CASE(test_method_getDomainInfo)
{
- DomainInfo di;
+ DomainInfo domainInfo;
BOOST_TEST_MESSAGE("Testing getDomainInfo method");
- be->getDomainInfo(DNSName("unit.test."), di);
- BOOST_CHECK_EQUAL(di.zone.toString(), "unit.test.");
- BOOST_CHECK_EQUAL(di.serial, 2);
- BOOST_CHECK_EQUAL(di.notified_serial, 2);
- BOOST_CHECK_EQUAL(di.kind, DomainInfo::Native);
- BOOST_CHECK_EQUAL(di.backend, be);
+ backendUnderTest->getDomainInfo(DNSName("unit.test."), domainInfo);
+ BOOST_CHECK_EQUAL(domainInfo.zone.toString(), "unit.test.");
+ BOOST_CHECK_EQUAL(domainInfo.serial, 2);
+ BOOST_CHECK_EQUAL(domainInfo.notified_serial, 2);
+ BOOST_CHECK_EQUAL(domainInfo.kind, DomainInfo::Native);
+ BOOST_CHECK_EQUAL(domainInfo.backend, backendUnderTest.get());
}
BOOST_AUTO_TEST_CASE(test_method_getAllDomains)
{
- DomainInfo di;
+ DomainInfo domainInfo;
BOOST_TEST_MESSAGE("Testing getAllDomains method");
vector<DomainInfo> result;
- be->getAllDomains(&result, true, true);
+ backendUnderTest->getAllDomains(&result, true, true);
BOOST_REQUIRE(!result.empty());
- di = result.at(0);
- BOOST_CHECK_EQUAL(di.zone.toString(), "unit.test.");
- BOOST_CHECK_EQUAL(di.serial, 2);
- BOOST_CHECK_EQUAL(di.notified_serial, 2);
- BOOST_CHECK_EQUAL(di.kind, DomainInfo::Native);
- BOOST_CHECK_EQUAL(di.backend, be);
+ domainInfo = result.at(0);
+ BOOST_CHECK_EQUAL(domainInfo.zone.toString(), "unit.test.");
+ BOOST_CHECK_EQUAL(domainInfo.serial, 2);
+ BOOST_CHECK_EQUAL(domainInfo.notified_serial, 2);
+ BOOST_CHECK_EQUAL(domainInfo.kind, DomainInfo::Native);
+ BOOST_CHECK_EQUAL(domainInfo.backend, backendUnderTest.get());
}
-BOOST_AUTO_TEST_CASE(test_method_superMasterBackend)
+BOOST_AUTO_TEST_CASE(test_method_autoPrimaryBackend)
{
- DNSResourceRecord rr;
+ DNSResourceRecord resourceRecord;
std::vector<DNSResourceRecord> nsset;
DNSBackend* dbd = nullptr;
- BOOST_TEST_MESSAGE("Testing superMasterBackend method");
-
- rr.qname = DNSName("example.com.");
- rr.qtype = QType::NS;
- rr.qclass = QClass::IN;
- rr.ttl = 300;
- rr.content = "ns1.example.com.";
- nsset.push_back(rr);
- rr.qname = DNSName("example.com.");
- rr.qtype = QType::NS;
- rr.qclass = QClass::IN;
- rr.ttl = 300;
- rr.content = "ns2.example.com.";
- nsset.push_back(rr);
-
- BOOST_CHECK(be->superMasterBackend("10.0.0.1", DNSName("example.com."), nsset, nullptr, nullptr, &dbd));
+ BOOST_TEST_MESSAGE("Testing autoPrimaryBackend method");
+
+ resourceRecord.qname = DNSName("example.com.");
+ resourceRecord.qtype = QType::NS;
+ resourceRecord.qclass = QClass::IN;
+ resourceRecord.ttl = 300;
+ resourceRecord.content = "ns1.example.com.";
+ nsset.push_back(resourceRecord);
+ resourceRecord.qname = DNSName("example.com.");
+ resourceRecord.qtype = QType::NS;
+ resourceRecord.qclass = QClass::IN;
+ resourceRecord.ttl = 300;
+ resourceRecord.content = "ns2.example.com.";
+ nsset.push_back(resourceRecord);
+
+ BOOST_CHECK(backendUnderTest->autoPrimaryBackend("10.0.0.1", DNSName("example.com."), nsset, nullptr, nullptr, &dbd));
// let's see what we got
- BOOST_CHECK_EQUAL(dbd, be);
+ BOOST_CHECK_EQUAL(dbd, backendUnderTest.get());
}
-BOOST_AUTO_TEST_CASE(test_method_createSlaveDomain)
+BOOST_AUTO_TEST_CASE(test_method_createSecondaryDomain)
{
- BOOST_TEST_MESSAGE("Testing createSlaveDomain method");
- BOOST_CHECK(be->createSlaveDomain("10.0.0.1", DNSName("pirate.unit.test."), "", ""));
+ BOOST_TEST_MESSAGE("Testing createSecondaryDomain method");
+ BOOST_CHECK(backendUnderTest->createSecondaryDomain("10.0.0.1", DNSName("pirate.unit.test."), "", ""));
}
BOOST_AUTO_TEST_CASE(test_method_feedRecord)
{
- DNSResourceRecord rr;
+ DNSResourceRecord resourceRecord;
BOOST_TEST_MESSAGE("Testing feedRecord method");
- be->startTransaction(DNSName("example.com."), 2);
- rr.qname = DNSName("example.com.");
- rr.qtype = QType::SOA;
- rr.qclass = QClass::IN;
- rr.ttl = 300;
- rr.content = "ns1.example.com. hostmaster.example.com. 2013013441 7200 3600 1209600 300";
- BOOST_CHECK(be->feedRecord(rr, DNSName()));
- rr.qname = DNSName("replace.example.com.");
- rr.qtype = QType::A;
- rr.qclass = QClass::IN;
- rr.ttl = 300;
- rr.content = "127.0.0.1";
- BOOST_CHECK(be->feedRecord(rr, DNSName()));
- be->commitTransaction();
+ backendUnderTest->startTransaction(DNSName("example.com."), 2);
+ resourceRecord.qname = DNSName("example.com.");
+ resourceRecord.qtype = QType::SOA;
+ resourceRecord.qclass = QClass::IN;
+ resourceRecord.ttl = 300;
+ resourceRecord.content = "ns1.example.com. hostmaster.example.com. 2013013441 7200 3600 1209600 300";
+ BOOST_CHECK(backendUnderTest->feedRecord(resourceRecord, DNSName()));
+ resourceRecord.qname = DNSName("replace.example.com.");
+ resourceRecord.qtype = QType::A;
+ resourceRecord.qclass = QClass::IN;
+ resourceRecord.ttl = 300;
+ resourceRecord.content = "127.0.0.1";
+ BOOST_CHECK(backendUnderTest->feedRecord(resourceRecord, DNSName()));
+ backendUnderTest->commitTransaction();
}
BOOST_AUTO_TEST_CASE(test_method_replaceRRSet)
{
- be->startTransaction(DNSName("example.com."), 2);
- DNSResourceRecord rr;
+ backendUnderTest->startTransaction(DNSName("example.com."), 2);
+ DNSResourceRecord resourceRecord;
std::vector<DNSResourceRecord> rrset;
BOOST_TEST_MESSAGE("Testing replaceRRSet method");
- rr.qname = DNSName("replace.example.com.");
- rr.qtype = QType::A;
- rr.qclass = QClass::IN;
- rr.ttl = 300;
- rr.content = "1.1.1.1";
- rrset.push_back(rr);
- BOOST_CHECK(be->replaceRRSet(2, DNSName("replace.example.com."), QType(QType::A), rrset));
- be->commitTransaction();
+ resourceRecord.qname = DNSName("replace.example.com.");
+ resourceRecord.qtype = QType::A;
+ resourceRecord.qclass = QClass::IN;
+ resourceRecord.ttl = 300;
+ resourceRecord.content = "1.1.1.1";
+ rrset.push_back(resourceRecord);
+ BOOST_CHECK(backendUnderTest->replaceRRSet(2, DNSName("replace.example.com."), QType(QType::A), rrset));
+ backendUnderTest->commitTransaction();
}
BOOST_AUTO_TEST_CASE(test_method_feedEnts)
{
BOOST_TEST_MESSAGE("Testing feedEnts method");
- be->startTransaction(DNSName("example.com."), 2);
+ backendUnderTest->startTransaction(DNSName("example.com."), 2);
map<DNSName, bool> nonterm = boost::assign::map_list_of(DNSName("_udp"), true)(DNSName("_sip._udp"), true);
- BOOST_CHECK(be->feedEnts(2, nonterm));
- be->commitTransaction();
+ BOOST_CHECK(backendUnderTest->feedEnts(2, nonterm));
+ backendUnderTest->commitTransaction();
}
BOOST_AUTO_TEST_CASE(test_method_feedEnts3)
{
BOOST_TEST_MESSAGE("Testing feedEnts3 method");
- be->startTransaction(DNSName("example.com"), 2);
+ backendUnderTest->startTransaction(DNSName("example.com"), 2);
NSEC3PARAMRecordContent ns3prc;
ns3prc.d_iterations = 1;
ns3prc.d_salt = "\u00aa\u00bb\u00cc\u00dd";
map<DNSName, bool> nonterm = boost::assign::map_list_of(DNSName("_udp"), true)(DNSName("_sip._udp"), true);
- BOOST_CHECK(be->feedEnts3(2, DNSName("example.com."), nonterm, ns3prc, 0));
- be->commitTransaction();
+ BOOST_CHECK(backendUnderTest->feedEnts3(2, DNSName("example.com."), nonterm, ns3prc, 0));
+ backendUnderTest->commitTransaction();
}
BOOST_AUTO_TEST_CASE(test_method_abortTransaction)
{
BOOST_TEST_MESSAGE("Testing abortTransaction method");
- be->startTransaction(DNSName("example.com."), 2);
- BOOST_CHECK(be->abortTransaction());
+ backendUnderTest->startTransaction(DNSName("example.com."), 2);
+ BOOST_CHECK(backendUnderTest->abortTransaction());
}
BOOST_AUTO_TEST_CASE(test_method_directBackendCmd)
{
BOOST_TEST_MESSAGE("Testing directBackendCmd method");
- BOOST_CHECK_EQUAL(be->directBackendCmd("PING 1234"), "PING 1234");
+ BOOST_CHECK_EQUAL(backendUnderTest->directBackendCmd("PING 1234"), "PING 1234");
}
-BOOST_AUTO_TEST_CASE(test_method_getUpdatedMasters)
+BOOST_AUTO_TEST_CASE(test_method_getUpdatedPrimaries)
{
- DomainInfo di;
- BOOST_TEST_MESSAGE("Testing getUpdatedMasters method");
+ DomainInfo domainInfo;
+ BOOST_TEST_MESSAGE("Testing getUpdatedPrimaries method");
vector<DomainInfo> result;
std::unordered_set<DNSName> catalogs;
CatalogHashMap hashes;
- be->getUpdatedMasters(result, catalogs, hashes);
+ backendUnderTest->getUpdatedPrimaries(result, catalogs, hashes);
BOOST_REQUIRE(!result.empty());
- di = result.at(0);
- BOOST_CHECK_EQUAL(di.zone.toString(), "master.test.");
- BOOST_CHECK_EQUAL(di.serial, 2);
- BOOST_CHECK_EQUAL(di.notified_serial, 2);
- BOOST_CHECK_EQUAL(di.kind, DomainInfo::Master);
- BOOST_CHECK_EQUAL(di.backend, be);
+ domainInfo = result.at(0);
+ BOOST_CHECK_EQUAL(domainInfo.zone.toString(), "master.test.");
+ BOOST_CHECK_EQUAL(domainInfo.serial, 2);
+ BOOST_CHECK_EQUAL(domainInfo.notified_serial, 2);
+ BOOST_CHECK_EQUAL(domainInfo.kind, DomainInfo::Primary);
+ BOOST_CHECK_EQUAL(domainInfo.backend, backendUnderTest.get());
}
BOOST_AUTO_TEST_SUITE_END();
d_isWildcardQuery = false;
}
-void TinyDNSBackend::getUpdatedMasters(vector<DomainInfo>& retDomains, std::unordered_set<DNSName>& /* catalogs */, CatalogHashMap& /* catalogHashes */)
+void TinyDNSBackend::getUpdatedPrimaries(vector<DomainInfo>& retDomains, std::unordered_set<DNSName>& /* catalogs */, CatalogHashMap& /* catalogHashes */)
{
auto domainInfo = s_domainInfo.lock(); //TODO: We could actually lock less if we do it per suffix.
if (!domainInfo->count(d_suffix)) {
di.id = -1; //TODO: Check if this is ok.
di.backend = this;
di.zone = rr.qname;
- di.kind = DomainInfo::Master;
+ di.kind = DomainInfo::Primary;
di.last_check = time(0);
if (getSerial) {
dr.d_type = rr.qtype.getCode();
dr.d_clen = val.size() - pr.getPosition();
- auto drc = DNSRecordContent::mastermake(dr, pr);
+ auto drc = DNSRecordContent::make(dr, pr);
rr.content = drc->getZoneRepresentation();
DLOG(cerr << "CONTENT: " << rr.content << endl);
}
void declareArguments(const string& suffix = "") override
{
- declare(suffix, "notify-on-startup", "Tell the TinyDNSBackend to notify all the slave nameservers on startup. Default is no.", "no");
+ declare(suffix, "notify-on-startup", "Tell the TinyDNSBackend to notify all the secondary nameservers on startup. Default is no.", "no");
declare(suffix, "dbfile", "Location of the cdb data file", "data.cdb");
declare(suffix, "tai-adjust", "This adjusts the TAI value if timestamps are used. These seconds will be added to the start point (1970) and will allow you to adjust for leap seconds. The default is 11.", "11");
declare(suffix, "locations", "Enable or Disable location support in the backend. Changing the value to 'no' will make the backend ignore the locations. This then returns all records!", "yes");
bool get(DNSResourceRecord& rr) override;
void getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled) override;
- //Master mode operation
- void getUpdatedMasters(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
+ // Primary mode operation
+ void getUpdatedPrimaries(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
void setNotified(uint32_t id, uint32_t serial) override;
private:
auth-catalogzone.cc auth-catalogzone.hh \
auth-main.cc auth-main.hh \
auth-packetcache.cc auth-packetcache.hh \
+ auth-primarycommunicator.cc \
auth-querycache.cc auth-querycache.hh \
+ auth-secondarycommunicator.cc \
auth-zonecache.cc auth-zonecache.hh \
axfr-retriever.cc axfr-retriever.hh \
backends/gsql/gsqlbackend.cc backends/gsql/gsqlbackend.hh \
logging.hh \
lua-auth4.cc lua-auth4.hh \
lua-base4.cc lua-base4.hh \
- mastercommunicator.cc \
misc.cc misc.hh \
nameserver.cc nameserver.hh \
namespaces.hh \
shuffle.cc shuffle.hh \
signingpipe.cc signingpipe.hh \
sillyrecords.cc \
- slavecommunicator.cc \
stat_t.hh \
statbag.cc statbag.hh \
stubresolver.cc stubresolver.hh \
{"snmp-master-socket", "snmp-daemon-socket"},
{"xpf-allow-from", "Proxy Protocol"},
{"xpf-rr-code", "Proxy Protocol"},
- {"allow-unsigned-supermaster", "allow-unsigned-autoprimary"},
- {"master", "primary"},
- {"slave-cycle-interval", "xfr-cycle-interval"},
- {"slave-renotify", "secondary-do-renotify"},
- {"slave", "secondary"},
- {"superslave", "autosecondary"},
{"domain-metadata-cache-ttl", "zone-metadata-cache-ttl"},
};
::arg().set("proxy-protocol-maximum-size", "The maximum size of a proxy protocol payload, including the TLV values") = "512";
::arg().setSwitch("send-signed-notify", "Send TSIG secured NOTIFY if TSIG key is configured for a zone") = "yes";
::arg().set("allow-unsigned-notify", "Allow unsigned notifications for TSIG secured zones") = "yes"; // FIXME: change to 'no' later
- ::arg().set("allow-unsigned-supermaster", "Allow supermasters to create zones without TSIG signed NOTIFY") = "yes";
::arg().set("allow-unsigned-autoprimary", "Allow autoprimaries to create zones without TSIG signed NOTIFY") = "yes";
- ::arg().setSwitch("forward-dnsupdate", "A global setting to allow DNS update packages that are for a Slave zone, to be forwarded to the master.") = "yes";
+ ::arg().setSwitch("forward-dnsupdate", "A global setting to allow DNS update packages that are for a Secondary zone, to be forwarded to the primary.") = "yes";
::arg().setSwitch("log-dns-details", "If PDNS should log DNS non-erroneous details") = "no";
::arg().setSwitch("log-dns-queries", "If PDNS should log all incoming DNS queries") = "no";
::arg().set("local-address", "Local IP addresses to which we bind") = "0.0.0.0, ::";
::arg().set("overload-queue-length", "Maximum queuelength moving to packetcache only") = "0";
::arg().set("max-queue-length", "Maximum queuelength before considering situation lost") = "5000";
- ::arg().set("retrieval-threads", "Number of AXFR-retrieval threads for slave operation") = "2";
+ ::arg().set("retrieval-threads", "Number of AXFR-retrieval threads for secondary operation") = "2";
::arg().setSwitch("api", "Enable/disable the REST API (including HTTP listener)") = "no";
::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
::arg().setSwitch("default-api-rectify", "Default API-RECTIFY value for zones") = "yes";
::arg().set("only-notify", "Only send AXFR NOTIFY to these IP addresses or netmasks") = "0.0.0.0/0,::/0";
::arg().set("also-notify", "When notifying a zone, also notify these nameservers") = "";
::arg().set("allow-notify-from", "Allow AXFR NOTIFY from these IP ranges. If empty, drop all incoming notifies.") = "0.0.0.0/0,::/0";
- ::arg().set("slave-cycle-interval", "Schedule slave freshness checks once every .. seconds") = "";
::arg().set("xfr-cycle-interval", "Schedule primary/secondary SOA freshness checks once every .. seconds") = "60";
::arg().set("secondary-check-signature-freshness", "Check signatures in SOA freshness check. Sets DO flag on SOA queries. Outside some very problematic scenarios, say yes here.") = "yes";
::arg().set("tcp-control-secret", "If set, PowerDNS can be controlled over TCP after passing this secret") = "";
::arg().set("tcp-control-range", "If set, remote control of PowerDNS is possible over these networks only") = "127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10";
- ::arg().setSwitch("slave", "Act as a secondary") = "no";
::arg().setSwitch("secondary", "Act as a secondary") = "no";
- ::arg().setSwitch("master", "Act as a primary") = "no";
::arg().setSwitch("primary", "Act as a primary") = "no";
- ::arg().setSwitch("superslave", "Act as a autosecondary") = "no";
- ::arg().setSwitch("autosecondary", "Act as an autosecondary (formerly superslave)") = "no";
+ ::arg().setSwitch("autosecondary", "Act as an autosecondary") = "no";
::arg().setSwitch("disable-axfr-rectify", "Disable the rectify step during an outgoing AXFR. Only required for regression testing.") = "no";
::arg().setSwitch("guardian", "Run within a guardian process") = "no";
::arg().setSwitch("prevent-self-notification", "Don't send notifications to what we think is ourself") = "yes";
::arg().set("zone-metadata-cache-ttl", "Seconds to cache zone metadata from the database") = "60";
::arg().set("trusted-notification-proxy", "IP address of incoming notification proxy") = "";
- ::arg().set("slave-renotify", "If we should send out notifications for secondaried updates") = "no";
::arg().set("secondary-do-renotify", "If this secondary should send out notifications after receiving zone transfers from a primary") = "no";
- ::arg().set("forward-notify", "IP addresses to forward received notifications to regardless of master or slave settings") = "";
+ ::arg().set("forward-notify", "IP addresses to forward received notifications to regardless of primary or secondary settings") = "";
::arg().set("default-ttl", "Seconds a result is valid if not set otherwise") = "3600";
::arg().set("max-tcp-connections", "Maximum number of TCP connections") = "20";
::arg().set("lua-health-checks-expire-delay", "Stops doing health checks after the record hasn't been used for that delay (in seconds)") = "3600";
::arg().set("lua-health-checks-interval", "LUA records health checks monitoring interval in seconds") = "5";
#endif
- ::arg().setSwitch("axfr-lower-serial", "Also AXFR a zone from a master with a lower serial") = "no";
+ ::arg().setSwitch("axfr-lower-serial", "Also AXFR a zone from a primary with a lower serial") = "no";
::arg().set("lua-axfr-script", "Script to be used to edit incoming AXFRs") = "";
::arg().set("xfr-max-received-mbytes", "Maximum number of megabytes received from an incoming XFR") = "100";
if (::arg().mustDo("version")) {
showProductVersion();
showBuildConfiguration();
- exit(99);
+ return 0;
}
if (::arg()["config-name"] != "")
g_log << Logger::Error << "Unknown logging facility " << ::arg().asNum("logging-facility") << endl;
}
- if (::arg().mustDo("master"))
- ::arg().set("primary") = "yes";
- if (::arg().mustDo("slave"))
- ::arg().set("secondary") = "yes";
- if (::arg().mustDo("slave-renotify"))
- ::arg().set("secondary-do-renotify") = "yes";
- if (::arg().mustDo("superslave"))
- ::arg().set("autosecondary") = "yes";
- if (::arg().mustDo("allow-unsigned-supermaster"))
- ::arg().set("allow-unsigned-autoprimary") = "yes";
if (!::arg().isEmpty("domain-metadata-cache-ttl"))
::arg().set("zone-metadata-cache-ttl") = ::arg()["domain-metadata-cache-ttl"];
- if (!::arg().isEmpty("slave-cycle-interval"))
- ::arg().set("xfr-cycle-interval") = ::arg()["slave-cycle-interval"];
// this mirroring back is on purpose, so that config dumps reflect the actual setting on both names
- if (::arg().mustDo("primary"))
- ::arg().set("master") = "yes";
- if (::arg().mustDo("secondary"))
- ::arg().set("slave") = "yes";
- if (::arg().mustDo("secondary-do-renotify"))
- ::arg().set("slave-renotify") = "yes";
- if (::arg().mustDo("autosecondary"))
- ::arg().set("superslave") = "yes";
- if (::arg().mustDo("allow-unsigned-autoprimary"))
- ::arg().set("allow-unsigned-supermaster") = "yes";
::arg().set("domain-metadata-cache-ttl") = ::arg()["zone-metadata-cache-ttl"];
- ::arg().set("slave-cycle-interval") = ::arg()["xfr-cycle-interval"];
g_log.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
g_log.disableSyslog(::arg().mustDo("disable-syslog"));
DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes");
DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes");
DynListener::registerFunc("SET", &DLSettingsHandler, "set config variables", "<var> <value>");
- DynListener::registerFunc("RETRIEVE", &DLNotifyRetrieveHandler, "retrieve slave zone", "<zone> [<ip>]");
+ DynListener::registerFunc("RETRIEVE", &DLNotifyRetrieveHandler, "retrieve secondary zone", "<zone> [<ip>]");
DynListener::registerFunc("CURRENT-CONFIG", &DLCurrentConfigHandler, "retrieve the current configuration", "[diff]");
DynListener::registerFunc("LIST-ZONES", &DLListZones, "show list of zones", "[primary|secondary|native|consumer|producer]");
DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>");
#include "namespaces.hh"
#include "query-local-address.hh"
-
void CommunicatorClass::queueNotifyDomain(const DomainInfo& di, UeberBackend* B)
{
- bool hasQueuedItem=false;
+ bool hasQueuedItem = false;
set<string> ips;
set<DNSName> nsset;
DNSZoneRecord rr;
FindNS fns;
try {
- if (d_onlyNotify.size()) {
- B->lookup(QType(QType::NS), di.zone, di.id);
- while(B->get(rr))
- nsset.insert(getRR<NSRecordContent>(rr.dr)->getNS());
-
- for(const auto & ns : nsset) {
- vector<string> nsips=fns.lookup(ns, B);
- if(nsips.empty())
- g_log<<Logger::Warning<<"Unable to queue notification of domain '"<<di.zone<<"' to nameserver '"<<ns<<"': nameserver does not resolve!"<<endl;
- else
- for(const auto & nsip : nsips) {
- const ComboAddress caIp(nsip, 53);
- if(!d_preventSelfNotification || !AddressIsUs(caIp)) {
- if(!d_onlyNotify.match(&caIp))
- g_log<<Logger::Notice<<"Skipped notification of domain '"<<di.zone<<"' to "<<ns<<" because "<<caIp<<" does not match only-notify."<<endl;
- else
- ips.insert(caIp.toStringWithPort());
+ if (d_onlyNotify.size()) {
+ B->lookup(QType(QType::NS), di.zone, di.id);
+ while (B->get(rr))
+ nsset.insert(getRR<NSRecordContent>(rr.dr)->getNS());
+
+ for (const auto& ns : nsset) {
+ vector<string> nsips = fns.lookup(ns, B);
+ if (nsips.empty())
+ g_log << Logger::Warning << "Unable to queue notification of domain '" << di.zone << "' to nameserver '" << ns << "': nameserver does not resolve!" << endl;
+ else
+ for (const auto& nsip : nsips) {
+ const ComboAddress caIp(nsip, 53);
+ if (!d_preventSelfNotification || !AddressIsUs(caIp)) {
+ if (!d_onlyNotify.match(&caIp))
+ g_log << Logger::Notice << "Skipped notification of domain '" << di.zone << "' to " << ns << " because " << caIp << " does not match only-notify." << endl;
+ else
+ ips.insert(caIp.toStringWithPort());
+ }
}
- }
- }
+ }
- for(const auto & ip : ips) {
- g_log<<Logger::Notice<<"Queued notification of domain '"<<di.zone<<"' to "<<ip<<endl;
- d_nq.add(di.zone,ip);
- hasQueuedItem=true;
+ for (const auto& ip : ips) {
+ g_log << Logger::Notice << "Queued notification of domain '" << di.zone << "' to " << ip << endl;
+ d_nq.add(di.zone, ip);
+ hasQueuedItem = true;
+ }
}
}
- }
- catch (PDNSException &ae) {
+ catch (PDNSException& ae) {
g_log << Logger::Error << "Error looking up name servers for " << di.zone << ", cannot notify: " << ae.reason << endl;
return;
}
- catch (std::exception &e) {
+ catch (std::exception& e) {
g_log << Logger::Error << "Error looking up name servers for " << di.zone << ", cannot notify: " << e.what() << endl;
return;
}
-
set<string> alsoNotify(d_alsoNotify);
B->alsoNotifies(di.zone, &alsoNotify);
- for(const auto & j : alsoNotify) {
+ for (const auto& j : alsoNotify) {
try {
const ComboAddress caIp(j, 53);
- g_log<<Logger::Notice<<"Queued also-notification of domain '"<<di.zone<<"' to "<<caIp.toStringWithPort()<<endl;
+ g_log << Logger::Notice << "Queued also-notification of domain '" << di.zone << "' to " << caIp.toStringWithPort() << endl;
if (!ips.count(caIp.toStringWithPort())) {
ips.insert(caIp.toStringWithPort());
d_nq.add(di.zone, caIp.toStringWithPort());
}
- hasQueuedItem=true;
+ hasQueuedItem = true;
}
- catch(PDNSException &e) {
- g_log<<Logger::Warning<<"Unparseable IP in ALSO-NOTIFY metadata of domain '"<<di.zone<<"'. Warning: "<<e.reason<<endl;
+ catch (PDNSException& e) {
+ g_log << Logger::Warning << "Unparseable IP in ALSO-NOTIFY metadata of domain '" << di.zone << "'. Warning: " << e.reason << endl;
}
}
if (!hasQueuedItem)
- g_log<<Logger::Warning<<"Request to queue notification for domain '"<<di.zone<<"' was processed, but no valid nameservers or ALSO-NOTIFYs found. Not notifying!"<<endl;
+ g_log << Logger::Warning << "Request to queue notification for domain '" << di.zone << "' was processed, but no valid nameservers or ALSO-NOTIFYs found. Not notifying!" << endl;
}
-
-bool CommunicatorClass::notifyDomain(const DNSName &domain, UeberBackend* B)
+bool CommunicatorClass::notifyDomain(const DNSName& domain, UeberBackend* B)
{
DomainInfo di;
- if(!B->getDomainInfo(domain, di)) {
- g_log<<Logger::Warning<<"No such domain '"<<domain<<"' in our database"<<endl;
+ if (!B->getDomainInfo(domain, di)) {
+ g_log << Logger::Warning << "No such domain '" << domain << "' in our database" << endl;
return false;
}
queueNotifyDomain(di, B);
void NotificationQueue::dump()
{
- cerr<<"Waiting for notification responses: "<<endl;
- for(NotificationRequest& nr : d_nqueue) {
- cerr<<nr.domain<<", "<<nr.ip<<endl;
+ cerr << "Waiting for notification responses: " << endl;
+ for (NotificationRequest& nr : d_nqueue) {
+ cerr << nr.domain << ", " << nr.ip << endl;
}
}
}
}
-void CommunicatorClass::masterUpdateCheck(PacketHandler *P)
+void CommunicatorClass::primaryUpdateCheck(PacketHandler* P)
{
- if(!::arg().mustDo("primary"))
+ if (!::arg().mustDo("primary"))
return;
- UeberBackend *B=P->getBackend();
+ UeberBackend* B = P->getBackend();
vector<DomainInfo> cmdomains;
std::unordered_set<DNSName> catalogs;
CatalogHashMap catalogHashes;
- B->getUpdatedMasters(cmdomains, catalogs, catalogHashes);
+ B->getUpdatedPrimaries(cmdomains, catalogs, catalogHashes);
getUpdatedProducers(B, cmdomains, catalogs, catalogHashes);
- if(cmdomains.empty()) {
+ if (cmdomains.empty()) {
g_log << Logger::Info << "no primary or producer domains need notifications" << endl;
}
else {
g_log << Logger::Info << cmdomains.size() << " domain" << addS(cmdomains.size()) << " for which we are primary or consumer need" << addS(cmdomains.size()) << " notifications" << endl;
}
- for(auto& di : cmdomains) {
+ for (auto& di : cmdomains) {
purgeAuthCachesExact(di.zone);
g_zoneCache.add(di.zone, di.id);
queueNotifyDomain(di, B);
return d_nq.earliest();
}
-void CommunicatorClass::sendNotification(int sock, const DNSName& domain, const ComboAddress& remote, uint16_t id, UeberBackend *B)
+void CommunicatorClass::sendNotification(int sock, const DNSName& domain, const ComboAddress& remote, uint16_t id, UeberBackend* B)
{
vector<string> meta;
DNSName tsigkeyname;
trc.d_algoName = tsigalgorithm;
trc.d_time = time(nullptr);
trc.d_fudge = 300;
- trc.d_origID=ntohs(id);
- trc.d_eRcode=0;
+ trc.d_origID = ntohs(id);
+ trc.d_eRcode = 0;
if (B64Decode(tsigsecret64, tsigsecret) == -1) {
- g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<domain<<"'"<<endl;
+ g_log << Logger::Error << "Unable to Base-64 decode TSIG key '" << tsigkeyname << "' for domain '" << domain << "'" << endl;
return;
}
addTSIG(pw, trc, tsigkeyname, tsigsecret, "", false);
}
- if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) {
- throw ResolverException("Unable to send notify to "+remote.toStringWithPort()+": "+stringerror());
+ if (sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) {
+ throw ResolverException("Unable to send notify to " + remote.toStringWithPort() + ": " + stringerror());
}
}
-void CommunicatorClass::drillHole(const DNSName &domain, const string &ip)
+void CommunicatorClass::drillHole(const DNSName& domain, const string& ip)
{
- (*d_holes.lock())[pair(domain,ip)]=time(nullptr);
+ (*d_holes.lock())[pair(domain, ip)] = time(nullptr);
}
-bool CommunicatorClass::justNotified(const DNSName &domain, const string &ip)
+bool CommunicatorClass::justNotified(const DNSName& domain, const string& ip)
{
auto holes = d_holes.lock();
- auto it = holes->find(pair(domain,ip));
+ auto it = holes->find(pair(domain, ip));
if (it == holes->end()) {
// no hole
return false;
}
- if (it->second > time(nullptr)-900) {
+ if (it->second > time(nullptr) - 900) {
// recent hole
return true;
}
void CommunicatorClass::makeNotifySockets()
{
- if(pdns::isQueryLocalAddressFamilyEnabled(AF_INET)) {
+ if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET)) {
d_nsock4 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET, 0), true, ::arg().mustDo("non-local-bind"));
- } else {
+ }
+ else {
d_nsock4 = -1;
}
- if(pdns::isQueryLocalAddressFamilyEnabled(AF_INET6)) {
+ if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET6)) {
d_nsock6 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET6, 0), true, ::arg().mustDo("non-local-bind"));
- } else {
+ }
+ else {
d_nsock6 = -1;
}
}
-void CommunicatorClass::notify(const DNSName &domain, const string &ip)
+void CommunicatorClass::notify(const DNSName& domain, const string& ip)
{
d_nq.add(domain, ip);
}
#include "ixfr.hh"
-void CommunicatorClass::addSuckRequest(const DNSName &domain, const ComboAddress& master, SuckRequest::RequestPriority priority, bool force)
+void CommunicatorClass::addSuckRequest(const DNSName& domain, const ComboAddress& primary, SuckRequest::RequestPriority priority, bool force)
{
auto data = d_data.lock();
SuckRequest sr;
sr.domain = domain;
- sr.master = master;
+ sr.primary = primary;
sr.force = force;
sr.priorityAndOrder.first = priority;
sr.priorityAndOrder.second = data->d_sorthelper++;
- pair<UniQueue::iterator, bool> res;
+ pair<UniQueue::iterator, bool> res;
res = data->d_suckdomains.insert(sr);
- if(res.second) {
+ if (res.second) {
d_suck_sem.post();
- } else {
- data->d_suckdomains.modify(res.first, [priorityAndOrder = sr.priorityAndOrder] (SuckRequest& so) {
+ }
+ else {
+ data->d_suckdomains.modify(res.first, [priorityAndOrder = sr.priorityAndOrder](SuckRequest& so) {
if (priorityAndOrder.first < so.priorityAndOrder.first) {
so.priorityAndOrder = priorityAndOrder;
}
{
bool isDnssecZone{false};
bool isPresigned{false};
- bool isNSEC3 {false};
- bool optOutFlag {false};
+ bool isNSEC3{false};
+ bool optOutFlag{false};
NSEC3PARAMRecordContent ns3pr;
bool isNarrow{false};
di.backend->setOptions(ciXFR.d_zone, ciDB.toJson());
}
- if (di.masters != ciDB.d_primaries) { // update primaries
+ if (di.primaries != ciDB.d_primaries) { // update primaries
if (doTransaction && (inTransaction = di.backend->startTransaction(di.zone))) {
g_log << Logger::Warning << logPrefix << "backend transaction started" << endl;
doTransaction = false;
}
vector<string> primaries;
- for (const auto& primary : di.masters) {
+ for (const auto& primary : di.primaries) {
primaries.push_back(primary.toStringWithPortExcept(53));
}
g_log << Logger::Warning << logPrefix << "update primaries for zone '" << ciXFR.d_zone << "' to '" << boost::join(primaries, ", ") << "'" << endl;
- di.backend->setMasters(ciXFR.d_zone, di.masters);
+ di.backend->setPrimaries(ciXFR.d_zone, di.primaries);
retrieve.emplace_back(ciXFR);
}
doTransaction = false;
}
- di.backend->setMasters(ciCreate.d_zone, di.masters);
+ di.backend->setPrimaries(ciCreate.d_zone, di.primaries);
di.backend->setOptions(ciCreate.d_zone, ciCreate.toJson());
di.backend->setCatalog(ciCreate.d_zone, di.zone);
}
g_log << Logger::Warning << logPrefix << "create zone '" << ciCreate.d_zone << "'" << endl;
- di.backend->createDomain(ciCreate.d_zone, DomainInfo::Slave, ciCreate.d_primaries, "");
+ di.backend->createDomain(ciCreate.d_zone, DomainInfo::Secondary, ciCreate.d_primaries, "");
- di.backend->setMasters(ciCreate.d_zone, di.masters);
+ di.backend->setPrimaries(ciCreate.d_zone, di.primaries);
di.backend->setOptions(ciCreate.d_zone, ciCreate.toJson());
di.backend->setCatalog(ciCreate.d_zone, di.zone);
}
// retrieve new and updated zones with new primaries
- auto masters = di.masters;
- if (!masters.empty()) {
+ auto primaries = di.primaries;
+ if (!primaries.empty()) {
for (auto& ret : retrieve) {
- shuffle(masters.begin(), masters.end(), pdns::dns_random_engine());
- const auto& master = masters.front();
- Communicator.addSuckRequest(ret.d_zone, master, SuckRequest::Notify);
+ shuffle(primaries.begin(), primaries.end(), pdns::dns_random_engine());
+ const auto& primary = primaries.front();
+ Communicator.addSuckRequest(ret.d_zone, primary, SuckRequest::Notify);
}
}
void CommunicatorClass::ixfrSuck(const DNSName& domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, ZoneStatus& zs, vector<DNSRecord>* axfr)
{
- string logPrefix="IXFR-in zone '"+domain.toLogString()+"', primary '"+remote.toString()+"', ";
+ string logPrefix = "IXFR-in zone '" + domain.toLogString() + "', primary '" + remote.toString() + "', ";
UeberBackend B; // fresh UeberBackend
DomainInfo di;
- di.backend=nullptr;
+ di.backend = nullptr;
// bool transaction=false;
try {
- DNSSECKeeper dk (&B); // reuse our UeberBackend copy for DNSSECKeeper
+ DNSSECKeeper dk(&B); // reuse our UeberBackend copy for DNSSECKeeper
bool wrongDomainKind = false;
// this checks three error conditions, and sets wrongDomainKind if we hit the third & had an error
- if(!B.getDomainInfo(domain, di) || !di.backend || (wrongDomainKind = true, di.kind != DomainInfo::Slave)) { // di.backend and B are mostly identical
- if(wrongDomainKind)
- g_log<<Logger::Warning<<logPrefix<<"can't determine backend, not configured as slave"<<endl;
+ if (!B.getDomainInfo(domain, di) || !di.backend || (wrongDomainKind = true, di.kind != DomainInfo::Secondary)) { // di.backend and B are mostly identical
+ if (wrongDomainKind)
+ g_log << Logger::Warning << logPrefix << "can't determine backend, not configured as secondary" << endl;
else
- g_log<<Logger::Warning<<logPrefix<<"can't determine backend"<<endl;
+ g_log << Logger::Warning << logPrefix << "can't determine backend" << endl;
return;
}
uint16_t xfrTimeout = ::arg().asNum("axfr-fetch-timeout");
soatimes st;
memset(&st, 0, sizeof(st));
- st.serial=di.serial;
+ st.serial = di.serial;
DNSRecord drsoa;
drsoa.setContent(std::make_shared<SOARecordContent>(g_rootdnsname, g_rootdnsname, st));
- auto deltas = getIXFRDeltas(remote, domain, drsoa, xfrTimeout, false, tt, laddr.sin4.sin_family ? &laddr : nullptr, ((size_t) ::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024);
- zs.numDeltas=deltas.size();
+ auto deltas = getIXFRDeltas(remote, domain, drsoa, xfrTimeout, false, tt, laddr.sin4.sin_family ? &laddr : nullptr, ((size_t)::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024);
+ zs.numDeltas = deltas.size();
// cout<<"Got "<<deltas.size()<<" deltas from serial "<<di.serial<<", applying.."<<endl;
- for(const auto& d : deltas) {
+ for (const auto& d : deltas) {
const auto& remove = d.first;
const auto& add = d.second;
// cout<<"Delta sizes: "<<remove.size()<<", "<<add.size()<<endl;
- if(remove.empty()) { // we got passed an AXFR!
+ if (remove.empty()) { // we got passed an AXFR!
*axfr = add;
return;
}
-
// our hammer is 'replaceRRSet(domain_id, qname, qt, vector<DNSResourceRecord>& rrset)
// which thinks in terms of RRSETs
// however, IXFR does not, and removes and adds *records* (bummer)
// this means that we must group updates by {qname,qtype}, retrieve the RRSET, apply
// the add/remove updates, and replaceRRSet the whole thing.
+ map<pair<DNSName, uint16_t>, pair<vector<DNSRecord>, vector<DNSRecord>>> grouped;
- map<pair<DNSName,uint16_t>, pair<vector<DNSRecord>, vector<DNSRecord> > > grouped;
-
- for(const auto& x: remove)
+ for (const auto& x : remove)
grouped[{x.d_name, x.d_type}].first.push_back(x);
- for(const auto& x: add)
+ for (const auto& x : add)
grouped[{x.d_name, x.d_type}].second.push_back(x);
di.backend->startTransaction(domain, -1);
- for(const auto& g : grouped) {
+ for (const auto& g : grouped) {
vector<DNSRecord> rrset;
{
DNSZoneRecord zrr;
- di.backend->lookup(QType(g.first.second), g.first.first+domain, di.id);
- while(di.backend->get(zrr)) {
+ di.backend->lookup(QType(g.first.second), g.first.first + domain, di.id);
+ while (di.backend->get(zrr)) {
zrr.dr.d_name.makeUsRelative(domain);
rrset.push_back(zrr.dr);
}
[&g](const DNSRecord& dr) {
return count(g.second.first.cbegin(),
g.second.first.cend(), dr);
- }), rrset.end());
+ }),
+ rrset.end());
// the DNSRecord== operator compares on name, type, class and lowercase content representation
- for(const auto& x : g.second.second) {
+ for (const auto& x : g.second.second) {
rrset.push_back(x);
}
vector<DNSResourceRecord> replacement;
- for(const auto& dr : rrset) {
+ for (const auto& dr : rrset) {
auto rr = DNSResourceRecord::fromWire(dr);
rr.qname += domain;
rr.domain_id = di.id;
- if(dr.d_type == QType::SOA) {
+ if (dr.d_type == QType::SOA) {
// cout<<"New SOA: "<<x.d_content->getZoneRepresentation()<<endl;
auto sr = getRR<SOARecordContent>(dr);
- zs.soa_serial=sr->d_st.serial;
+ zs.soa_serial = sr->d_st.serial;
}
replacement.push_back(rr);
}
- di.backend->replaceRRSet(di.id, g.first.first+domain, QType(g.first.second), replacement);
+ di.backend->replaceRRSet(di.id, g.first.first + domain, QType(g.first.second), replacement);
}
di.backend->commitTransaction();
}
}
- catch(std::exception& p) {
- g_log<<Logger::Error<<logPrefix<<"got exception (std::exception): "<<p.what()<<endl;
+ catch (std::exception& p) {
+ g_log << Logger::Error << logPrefix << "got exception (std::exception): " << p.what() << endl;
throw;
}
- catch(PDNSException& p) {
- g_log<<Logger::Error<<logPrefix<<"got exception (PDNSException): "<<p.reason<<endl;
+ catch (PDNSException& p) {
+ g_log << Logger::Error << logPrefix << "got exception (PDNSException): " << p.reason << endl;
throw;
}
}
static bool processRecordForZS(const DNSName& domain, bool& firstNSEC3, DNSResourceRecord& rr, ZoneStatus& zs)
{
- switch(rr.qtype.getCode()) {
+ switch (rr.qtype.getCode()) {
case QType::NSEC3PARAM:
zs.ns3pr = NSEC3PARAMRecordContent(rr.content);
zs.isDnssecZone = zs.isNSEC3 = true;
if (firstNSEC3) {
zs.isDnssecZone = zs.isPresigned = true;
firstNSEC3 = false;
- } else if (zs.optOutFlag != (ns3rc.d_flags & 1))
+ }
+ else if (zs.optOutFlag != (ns3rc.d_flags & 1))
throw PDNSException("Zones with a mixture of Opt-Out NSEC3 RRs and non-Opt-Out NSEC3 RRs are not supported.");
zs.optOutFlag = ns3rc.d_flags & 1;
- if (ns3rc.isSet(QType::NS) && !(rr.qname==domain)) {
+ if (ns3rc.isSet(QType::NS) && !(rr.qname == domain)) {
DNSName hashPart = rr.qname.makeRelative(domain);
zs.secured.insert(hashPart);
}
return false;
case QType::NS:
- if(rr.qname!=domain)
+ if (rr.qname != domain)
zs.nsset.insert(rr.qname);
break;
}
zs.qnames.insert(rr.qname);
- rr.domain_id=zs.domain_id;
+ rr.domain_id = zs.domain_id;
return true;
}
/* So this code does a number of things.
- 1) It will AXFR a domain from a master
+ 1) It will AXFR a domain from a primary
The code can retrieve the current serial number in the database itself.
It may attempt an IXFR
2) It will filter the zone through a lua *filter* script
5) It updates the Empty Non Terminals
*/
-static vector<DNSResourceRecord> doAxfr(const ComboAddress& raddr, const DNSName& domain, const TSIGTriplet& tt, const ComboAddress& laddr, unique_ptr<AuthLua4>& pdl, ZoneStatus& zs)
+static vector<DNSResourceRecord> doAxfr(const ComboAddress& raddr, const DNSName& domain, const TSIGTriplet& tt, const ComboAddress& laddr, unique_ptr<AuthLua4>& pdl, ZoneStatus& zs)
{
- uint16_t axfr_timeout=::arg().asNum("axfr-fetch-timeout");
+ uint16_t axfr_timeout = ::arg().asNum("axfr-fetch-timeout");
vector<DNSResourceRecord> rrs;
- AXFRRetriever retriever(raddr, domain, tt, (laddr.sin4.sin_family == 0) ? nullptr : &laddr, ((size_t) ::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024, axfr_timeout);
+ AXFRRetriever retriever(raddr, domain, tt, (laddr.sin4.sin_family == 0) ? nullptr : &laddr, ((size_t)::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024, axfr_timeout);
Resolver::res_t recs;
- bool first=true;
+ bool first = true;
bool firstNSEC3{true};
- bool soa_received {false};
- string logPrefix="AXFR-in zone '"+domain.toLogString()+"', primary '"+raddr.toString()+"', ";
- while(retriever.getChunk(recs, nullptr, axfr_timeout)) {
- if(first) {
- g_log<<Logger::Notice<<logPrefix<<"retrieval started"<<endl;
- first=false;
+ bool soa_received{false};
+ string logPrefix = "AXFR-in zone '" + domain.toLogString() + "', primary '" + raddr.toString() + "', ";
+ while (retriever.getChunk(recs, nullptr, axfr_timeout)) {
+ if (first) {
+ g_log << Logger::Notice << logPrefix << "retrieval started" << endl;
+ first = false;
}
- for(auto & rec : recs) {
+ for (auto& rec : recs) {
rec.qname.makeUsLowerCase();
- if(rec.qtype.getCode() == QType::OPT || rec.qtype.getCode() == QType::TSIG) // ignore EDNS0 & TSIG
+ if (rec.qtype.getCode() == QType::OPT || rec.qtype.getCode() == QType::TSIG) // ignore EDNS0 & TSIG
continue;
- if(!rec.qname.isPartOf(domain)) {
- g_log<<Logger::Warning<<logPrefix<<"primary tried to sneak in out-of-zone data '"<<rec.qname<<"'|"<<rec.qtype.toString()<<", ignoring"<<endl;
+ if (!rec.qname.isPartOf(domain)) {
+ g_log << Logger::Warning << logPrefix << "primary tried to sneak in out-of-zone data '" << rec.qname << "'|" << rec.qtype.toString() << ", ignoring" << endl;
continue;
}
vector<DNSResourceRecord> out;
- if(!pdl || !pdl->axfrfilter(raddr, domain, rec, out)) {
+ if (!pdl || !pdl->axfrfilter(raddr, domain, rec, out)) {
out.push_back(rec); // if axfrfilter didn't do anything, we put our record in 'out' ourselves
}
- for(auto& rr : out) {
- if(!rr.qname.isPartOf(domain)) {
- g_log<<Logger::Error<<logPrefix<<"axfrfilter() filter tried to sneak in out-of-zone data '"<<rr.qname<<"'|"<<rr.qtype.toString()<<", ignoring"<<endl;
+ for (auto& rr : out) {
+ if (!rr.qname.isPartOf(domain)) {
+ g_log << Logger::Error << logPrefix << "axfrfilter() filter tried to sneak in out-of-zone data '" << rr.qname << "'|" << rr.qtype.toString() << ", ignoring" << endl;
continue;
}
- if(!processRecordForZS(domain, firstNSEC3, rr, zs))
+ if (!processRecordForZS(domain, firstNSEC3, rr, zs))
continue;
- if(rr.qtype.getCode() == QType::SOA) {
- if(soa_received)
- continue; //skip the last SOA
+ if (rr.qtype.getCode() == QType::SOA) {
+ if (soa_received)
+ continue; // skip the last SOA
SOAData sd;
- fillSOAData(rr.content,sd);
+ fillSOAData(rr.content, sd);
zs.soa_serial = sd.serial;
soa_received = true;
}
rrs.push_back(rr);
-
}
}
}
return rrs;
}
-
-void CommunicatorClass::suck(const DNSName &domain, const ComboAddress& remote, bool force)
+void CommunicatorClass::suck(const DNSName& domain, const ComboAddress& remote, bool force)
{
{
auto data = d_data.lock();
}
RemoveSentinel rs(domain, this); // this removes us from d_inprogress when we go out of scope
- string logPrefix="XFR-in zone: '"+domain.toLogString()+"', primary: '"+remote.toString()+"', ";
+ string logPrefix = "XFR-in zone: '" + domain.toLogString() + "', primary: '" + remote.toString() + "', ";
- g_log<<Logger::Notice<<logPrefix<<"initiating transfer"<<endl;
+ g_log << Logger::Notice << logPrefix << "initiating transfer" << endl;
UeberBackend B; // fresh UeberBackend
DomainInfo di;
- di.backend=nullptr;
- bool transaction=false;
+ di.backend = nullptr;
+ bool transaction = false;
try {
- DNSSECKeeper dk (&B); // reuse our UeberBackend copy for DNSSECKeeper
+ DNSSECKeeper dk(&B); // reuse our UeberBackend copy for DNSSECKeeper
bool wrongDomainKind = false;
// this checks three error conditions & sets wrongDomainKind if we hit the third
if (!B.getDomainInfo(domain, di) || !di.backend || (wrongDomainKind = true, !force && !di.isSecondaryType())) { // di.backend and B are mostly identical
- if(wrongDomainKind)
+ if (wrongDomainKind)
g_log << Logger::Warning << logPrefix << "can't determine backend, not configured as secondary" << endl;
else
- g_log<<Logger::Warning<<logPrefix<<"can't determine backend"<<endl;
+ g_log << Logger::Warning << logPrefix << "can't determine backend" << endl;
return;
}
ZoneStatus zs;
- zs.domain_id=di.id;
+ zs.domain_id = di.id;
TSIGTriplet tt;
- if(dk.getTSIGForAccess(domain, remote, &tt.name)) {
+ if (dk.getTSIGForAccess(domain, remote, &tt.name)) {
string tsigsecret64;
if (B.getTSIGKey(tt.name, tt.algo, tsigsecret64)) {
- if(B64Decode(tsigsecret64, tt.secret)) {
- g_log<<Logger::Error<<logPrefix<<"unable to Base-64 decode TSIG key '"<<tt.name<<"' or zone not found"<<endl;
+ if (B64Decode(tsigsecret64, tt.secret)) {
+ g_log << Logger::Error << logPrefix << "unable to Base-64 decode TSIG key '" << tt.name << "' or zone not found" << endl;
return;
}
}
else {
- g_log<<Logger::Warning<<logPrefix<<"TSIG key '"<<tt.name<<"' for zone not found"<<endl;
+ g_log << Logger::Warning << logPrefix << "TSIG key '" << tt.name << "' for zone not found" << endl;
return;
}
}
-
unique_ptr<AuthLua4> pdl{nullptr};
vector<string> scripts;
- string script=::arg()["lua-axfr-script"];
- if(B.getDomainMetadata(domain, "LUA-AXFR-SCRIPT", scripts) && !scripts.empty()) {
+ string script = ::arg()["lua-axfr-script"];
+ if (B.getDomainMetadata(domain, "LUA-AXFR-SCRIPT", scripts) && !scripts.empty()) {
if (pdns_iequals(scripts[0], "NONE")) {
script.clear();
- } else {
- script=scripts[0];
+ }
+ else {
+ script = scripts[0];
}
}
- if(!script.empty()){
+ if (!script.empty()) {
try {
pdl = make_unique<AuthLua4>();
pdl->loadFile(script);
- g_log<<Logger::Info<<logPrefix<<"loaded Lua script '"<<script<<"'"<<endl;
+ g_log << Logger::Info << logPrefix << "loaded Lua script '" << script << "'" << endl;
}
- catch(std::exception& e) {
- g_log<<Logger::Error<<logPrefix<<"failed to load Lua script '"<<script<<"': "<<e.what()<<endl;
+ catch (std::exception& e) {
+ g_log << Logger::Error << logPrefix << "failed to load Lua script '" << script << "': " << e.what() << endl;
return;
}
}
vector<string> localaddr;
ComboAddress laddr;
- if(B.getDomainMetadata(domain, "AXFR-SOURCE", localaddr) && !localaddr.empty()) {
+ if (B.getDomainMetadata(domain, "AXFR-SOURCE", localaddr) && !localaddr.empty()) {
try {
laddr = ComboAddress(localaddr[0]);
- g_log<<Logger::Info<<logPrefix<<"xfr source set to "<<localaddr[0]<<endl;
+ g_log << Logger::Info << logPrefix << "xfr source set to " << localaddr[0] << endl;
}
- catch(std::exception& e) {
- g_log<<Logger::Error<<logPrefix<<"failed to set xfr source '"<<localaddr[0]<<"': "<<e.what()<<endl;
+ catch (std::exception& e) {
+ g_log << Logger::Error << logPrefix << "failed to set xfr source '" << localaddr[0] << "': " << e.what() << endl;
return;
}
- } else {
+ }
+ else {
if (!pdns::isQueryLocalAddressFamilyEnabled(remote.sin4.sin_family)) {
bool isV6 = remote.sin4.sin_family == AF_INET6;
- g_log<<Logger::Warning<<logPrefix<<"unable to xfr, address family (IPv"<< (isV6 ? "6" : "4") <<
- " is not enabled for outgoing traffic (query-local-address)"<<endl;
+ g_log << Logger::Warning << logPrefix << "unable to xfr, address family (IPv" << (isV6 ? "6" : "4") << " is not enabled for outgoing traffic (query-local-address)" << endl;
return;
}
laddr = pdns::getQueryLocalAddress(remote.sin4.sin_family, 0);
bool hadPresigned = false;
bool hadNSEC3 = false;
NSEC3PARAMRecordContent hadNs3pr;
- bool hadNarrow=false;
-
+ bool hadNarrow = false;
vector<DNSResourceRecord> rrs;
if (dk.isSecuredZone(domain, false)) {
- hadDnssecZone=true;
+ hadDnssecZone = true;
hadPresigned = dk.isPresigned(domain, false);
if (dk.getNSEC3PARAM(domain, &zs.ns3pr, &zs.isNarrow, false)) {
hadNSEC3 = true;
hadNarrow = zs.isNarrow;
}
}
- else if(di.serial) {
+ else if (di.serial) {
vector<string> meta;
B.getDomainMetadata(domain, "IXFR", meta);
- if(!meta.empty() && meta[0]=="1") {
+ if (!meta.empty() && meta[0] == "1") {
logPrefix = "I" + logPrefix; // XFR -> IXFR
vector<DNSRecord> axfr;
- g_log<<Logger::Notice<<logPrefix<<"starting IXFR"<<endl;
+ g_log << Logger::Notice << logPrefix << "starting IXFR" << endl;
ixfrSuck(domain, tt, laddr, remote, zs, &axfr);
- if(!axfr.empty()) {
- g_log<<Logger::Notice<<logPrefix<<"IXFR turned into an AXFR"<<endl;
- logPrefix[0]='A'; // IXFR -> AXFR
- bool firstNSEC3=true;
+ if (!axfr.empty()) {
+ g_log << Logger::Notice << logPrefix << "IXFR turned into an AXFR" << endl;
+ logPrefix[0] = 'A'; // IXFR -> AXFR
+ bool firstNSEC3 = true;
rrs.reserve(axfr.size());
- for(const auto& dr : axfr) {
+ for (const auto& dr : axfr) {
auto rr = DNSResourceRecord::fromWire(dr);
(rr.qname += domain).makeUsLowerCase();
rr.domain_id = zs.domain_id;
- if(!processRecordForZS(domain, firstNSEC3, rr, zs))
+ if (!processRecordForZS(domain, firstNSEC3, rr, zs))
continue;
- if(dr.d_type == QType::SOA) {
+ if (dr.d_type == QType::SOA) {
auto sd = getRR<SOARecordContent>(dr);
zs.soa_serial = sd->d_st.serial;
}
}
}
else {
- g_log<<Logger::Warning<<logPrefix<<"got "<<zs.numDeltas<<" delta"<<addS(zs.numDeltas)<<", zone committed with serial "<<zs.soa_serial<<endl;
- purgeAuthCaches(domain.toString()+"$");
+ g_log << Logger::Warning << logPrefix << "got " << zs.numDeltas << " delta" << addS(zs.numDeltas) << ", zone committed with serial " << zs.soa_serial << endl;
+ purgeAuthCaches(domain.toString() + "$");
return;
}
}
}
- if(rrs.empty()) {
- g_log<<Logger::Notice<<logPrefix<<"starting AXFR"<<endl;
+ if (rrs.empty()) {
+ g_log << Logger::Notice << logPrefix << "starting AXFR" << endl;
rrs = doAxfr(remote, domain, tt, laddr, pdl, zs);
logPrefix = "A" + logPrefix; // XFR -> AXFR
- g_log<<Logger::Notice<<logPrefix<<"retrieval finished"<<endl;
+ g_log << Logger::Notice << logPrefix << "retrieval finished" << endl;
}
if (di.kind == DomainInfo::Consumer) {
}
}
- if(zs.isNSEC3) {
+ if (zs.isNSEC3) {
zs.ns3pr.d_flags = zs.optOutFlag ? 1 : 0;
}
- if(!zs.isPresigned) {
+ if (!zs.isPresigned) {
DNSSECKeeper::keyset_t keys = dk.getKeys(domain, false);
- if(!keys.empty()) {
+ if (!keys.empty()) {
zs.isDnssecZone = true;
zs.isNSEC3 = hadNSEC3;
zs.ns3pr = hadNs3pr;
}
}
- if(zs.isDnssecZone) {
- if(!zs.isNSEC3)
- g_log<<Logger::Debug<<logPrefix<<"adding NSEC ordering information"<<endl;
- else if(!zs.isNarrow)
- g_log<<Logger::Debug<<logPrefix<<"adding NSEC3 hashed ordering information"<<endl;
+ if (zs.isDnssecZone) {
+ if (!zs.isNSEC3)
+ g_log << Logger::Debug << logPrefix << "adding NSEC ordering information" << endl;
+ else if (!zs.isNarrow)
+ g_log << Logger::Debug << logPrefix << "adding NSEC3 hashed ordering information" << endl;
else
- g_log<<Logger::Debug<<logPrefix<<"zone is narrow, only setting 'auth' fields"<<endl;
+ g_log << Logger::Debug << logPrefix << "zone is narrow, only setting 'auth' fields" << endl;
}
-
- transaction=di.backend->startTransaction(domain, zs.domain_id);
- g_log<<Logger::Info<<logPrefix<<"storage transaction started"<<endl;
+ transaction = di.backend->startTransaction(domain, zs.domain_id);
+ g_log << Logger::Info << logPrefix << "storage transaction started" << endl;
// update the presigned flag and NSEC3PARAM
if (zs.isDnssecZone) {
if (zs.isPresigned && !hadPresigned) {
// zone is now presigned
dk.setPresigned(domain);
- } else if (hadPresigned && !zs.isPresigned) {
+ }
+ else if (hadPresigned && !zs.isPresigned) {
// zone is no longer presigned
dk.unsetPresigned(domain);
}
// update NSEC3PARAM
if (zs.isNSEC3) {
// zone is NSEC3, only update if there was a change
- if (!hadNSEC3 || (hadNarrow != zs.isNarrow) ||
- (zs.ns3pr.d_algorithm != hadNs3pr.d_algorithm) ||
- (zs.ns3pr.d_flags != hadNs3pr.d_flags) ||
- (zs.ns3pr.d_iterations != hadNs3pr.d_iterations) ||
- (zs.ns3pr.d_salt != hadNs3pr.d_salt)) {
+ if (!hadNSEC3 || (hadNarrow != zs.isNarrow) || (zs.ns3pr.d_algorithm != hadNs3pr.d_algorithm) || (zs.ns3pr.d_flags != hadNs3pr.d_flags) || (zs.ns3pr.d_iterations != hadNs3pr.d_iterations) || (zs.ns3pr.d_salt != hadNs3pr.d_salt)) {
dk.setNSEC3PARAM(domain, zs.ns3pr, zs.isNarrow);
}
- } else if (hadNSEC3 ) {
- // zone is no longer NSEC3
- dk.unsetNSEC3PARAM(domain);
}
- } else if (hadDnssecZone) {
+ else if (hadNSEC3) {
+ // zone is no longer NSEC3
+ dk.unsetNSEC3PARAM(domain);
+ }
+ }
+ else if (hadDnssecZone) {
// zone is no longer signed
if (hadPresigned) {
// remove presigned
}
}
- bool doent=true;
+ bool doent = true;
uint32_t maxent = ::arg().asNum("max-ent-entries");
DNSName shorter, ordername;
set<DNSName> rrterm;
- map<DNSName,bool> nonterm;
-
+ map<DNSName, bool> nonterm;
- for(DNSResourceRecord& rr : rrs) {
- if(!zs.isPresigned) {
+ for (DNSResourceRecord& rr : rrs) {
+ if (!zs.isPresigned) {
if (rr.qtype.getCode() == QType::RRSIG)
continue;
- if(zs.isDnssecZone && rr.qtype.getCode() == QType::DNSKEY && !::arg().mustDo("direct-dnskey"))
+ if (zs.isDnssecZone && rr.qtype.getCode() == QType::DNSKEY && !::arg().mustDo("direct-dnskey"))
continue;
}
// Figure out auth and ents
- rr.auth=true;
- shorter=rr.qname;
+ rr.auth = true;
+ shorter = rr.qname;
rrterm.clear();
do {
- if(doent) {
+ if (doent) {
if (!zs.qnames.count(shorter))
rrterm.insert(shorter);
}
- if(zs.nsset.count(shorter) && rr.qtype.getCode() != QType::DS)
- rr.auth=false;
+ if (zs.nsset.count(shorter) && rr.qtype.getCode() != QType::DS)
+ rr.auth = false;
- if (shorter==domain) // stop at apex
+ if (shorter == domain) // stop at apex
break;
- }while(shorter.chopOff());
+ } while (shorter.chopOff());
// Insert ents
- if(doent && !rrterm.empty()) {
+ if (doent && !rrterm.empty()) {
bool auth;
if (!rr.auth && rr.qtype.getCode() == QType::NS) {
if (zs.isNSEC3)
- ordername=DNSName(toBase32Hex(hashQNameWithSalt(zs.ns3pr, rr.qname)));
- auth=(!zs.isNSEC3 || !zs.optOutFlag || zs.secured.count(ordername));
- } else
- auth=rr.auth;
+ ordername = DNSName(toBase32Hex(hashQNameWithSalt(zs.ns3pr, rr.qname)));
+ auth = (!zs.isNSEC3 || !zs.optOutFlag || zs.secured.count(ordername));
+ }
+ else
+ auth = rr.auth;
- for(const auto &nt: rrterm){
+ for (const auto& nt : rrterm) {
if (!nonterm.count(nt))
- nonterm.insert(pair<DNSName, bool>(nt, auth));
- else if (auth)
- nonterm[nt]=true;
+ nonterm.insert(pair<DNSName, bool>(nt, auth));
+ else if (auth)
+ nonterm[nt] = true;
}
- if(nonterm.size() > maxent) {
- g_log<<Logger::Warning<<logPrefix<<"zone has too many empty non terminals"<<endl;
+ if (nonterm.size() > maxent) {
+ g_log << Logger::Warning << logPrefix << "zone has too many empty non terminals" << endl;
nonterm.clear();
- doent=false;
+ doent = false;
}
}
// RRSIG is always auth, even inside a delegation
if (rr.qtype.getCode() == QType::RRSIG)
- rr.auth=true;
+ rr.auth = true;
// Add ordername and insert record
if (zs.isDnssecZone && rr.qtype.getCode() != QType::RRSIG) {
if (zs.isNSEC3) {
// NSEC3
- ordername=DNSName(toBase32Hex(hashQNameWithSalt(zs.ns3pr, rr.qname)));
- if(!zs.isNarrow && (rr.auth || (rr.qtype.getCode() == QType::NS && (!zs.optOutFlag || zs.secured.count(ordername))))) {
+ ordername = DNSName(toBase32Hex(hashQNameWithSalt(zs.ns3pr, rr.qname)));
+ if (!zs.isNarrow && (rr.auth || (rr.qtype.getCode() == QType::NS && (!zs.optOutFlag || zs.secured.count(ordername))))) {
di.backend->feedRecord(rr, ordername, true);
- } else
+ }
+ else
di.backend->feedRecord(rr, DNSName());
- } else {
+ }
+ else {
// NSEC
if (rr.auth || rr.qtype.getCode() == QType::NS) {
- ordername=rr.qname.makeRelative(domain);
+ ordername = rr.qname.makeRelative(domain);
di.backend->feedRecord(rr, ordername);
- } else
+ }
+ else
di.backend->feedRecord(rr, DNSName());
}
- } else
+ }
+ else
di.backend->feedRecord(rr, DNSName());
}
// Insert empty non-terminals
- if(doent && !nonterm.empty()) {
+ if (doent && !nonterm.empty()) {
if (zs.isNSEC3) {
di.backend->feedEnts3(zs.domain_id, domain, nonterm, zs.ns3pr, zs.isNarrow);
- } else
+ }
+ else
di.backend->feedEnts(zs.domain_id, nonterm);
}
di.backend->commitTransaction();
transaction = false;
di.backend->setFresh(zs.domain_id);
- purgeAuthCaches(domain.toString()+"$");
+ purgeAuthCaches(domain.toString() + "$");
- g_log<<Logger::Warning<<logPrefix<<"zone committed with serial "<<zs.soa_serial<<endl;
+ g_log << Logger::Warning << logPrefix << "zone committed with serial " << zs.soa_serial << endl;
- // Send slave re-notifications
+ // Send secondary re-notifications
bool doNotify;
vector<string> meta;
- if(B.getDomainMetadata(domain, "SLAVE-RENOTIFY", meta ) && !meta.empty()) {
- doNotify=(meta.front() == "1");
- } else {
- doNotify=(::arg().mustDo("slave-renotify"));
+ if (B.getDomainMetadata(domain, "SLAVE-RENOTIFY", meta) && !meta.empty()) {
+ doNotify = (meta.front() == "1");
+ }
+ else {
+ doNotify = (::arg().mustDo("secondary-do-renotify"));
}
- if(doNotify) {
+ if (doNotify) {
notifyDomain(domain, &B);
}
-
}
- catch(DBException &re) {
- g_log<<Logger::Error<<logPrefix<<"unable to feed record: "<<re.reason<<endl;
- if(di.backend && transaction) {
- g_log<<Logger::Info<<logPrefix<<"aborting possible open transaction"<<endl;
+ catch (DBException& re) {
+ g_log << Logger::Error << logPrefix << "unable to feed record: " << re.reason << endl;
+ if (di.backend && transaction) {
+ g_log << Logger::Info << logPrefix << "aborting possible open transaction" << endl;
di.backend->abortTransaction();
}
}
- catch(const MOADNSException &mde) {
- g_log<<Logger::Error<<logPrefix<<"unable to parse record (MOADNSException): "<<mde.what()<<endl;
- if(di.backend && transaction) {
- g_log<<Logger::Info<<logPrefix<<"aborting possible open transaction"<<endl;
+ catch (const MOADNSException& mde) {
+ g_log << Logger::Error << logPrefix << "unable to parse record (MOADNSException): " << mde.what() << endl;
+ if (di.backend && transaction) {
+ g_log << Logger::Info << logPrefix << "aborting possible open transaction" << endl;
di.backend->abortTransaction();
}
}
- catch(std::exception &re) {
- g_log<<Logger::Error<<logPrefix<<"unable to xfr zone (std::exception): "<<re.what()<<endl;
- if(di.backend && transaction) {
- g_log<<Logger::Info<<logPrefix<<"aborting possible open transaction"<<endl;
+ catch (std::exception& re) {
+ g_log << Logger::Error << logPrefix << "unable to xfr zone (std::exception): " << re.what() << endl;
+ if (di.backend && transaction) {
+ g_log << Logger::Info << logPrefix << "aborting possible open transaction" << endl;
di.backend->abortTransaction();
}
}
- catch(ResolverException &re) {
+ catch (ResolverException& re) {
{
auto data = d_data.lock();
- // The AXFR probably failed due to a problem on the master server. If SOA-checks against this master
+ // The AXFR probably failed due to a problem on the primary server. If SOA-checks against this primary
// still succeed, we would constantly try to AXFR the zone. To avoid this, we add the zone to the list of
- // failed slave-checks. This will suspend slave-checks (and subsequent AXFR) for this zone for some time.
+ // failed secondary-checks. This will suspend secondary-checks (and subsequent AXFR) for this zone for some time.
uint64_t newCount = 1;
time_t now = time(nullptr);
- const auto failedEntry = data->d_failedSlaveRefresh.find(domain);
- if (failedEntry != data->d_failedSlaveRefresh.end()) {
- newCount = data->d_failedSlaveRefresh[domain].first + 1;
+ const auto failedEntry = data->d_failedSecondaryRefresh.find(domain);
+ if (failedEntry != data->d_failedSecondaryRefresh.end()) {
+ newCount = data->d_failedSecondaryRefresh[domain].first + 1;
}
time_t nextCheck = now + std::min(newCount * d_tickinterval, (uint64_t)::arg().asNum("default-ttl"));
- data->d_failedSlaveRefresh[domain] = {newCount, nextCheck};
- g_log<<Logger::Warning<<logPrefix<<"unable to xfr zone (ResolverException): "<<re.reason<<" (This was attempt number "<<newCount<<". Excluding zone from slave-checks until "<<nextCheck<<")"<<endl;
+ data->d_failedSecondaryRefresh[domain] = {newCount, nextCheck};
+ g_log << Logger::Warning << logPrefix << "unable to xfr zone (ResolverException): " << re.reason << " (This was attempt number " << newCount << ". Excluding zone from secondary-checks until " << nextCheck << ")" << endl;
}
- if(di.backend && transaction) {
- g_log<<Logger::Info<<"aborting possible open transaction"<<endl;
+ if (di.backend && transaction) {
+ g_log << Logger::Info << "aborting possible open transaction" << endl;
di.backend->abortTransaction();
}
}
- catch(PDNSException &ae) {
- g_log<<Logger::Error<<logPrefix<<"unable to xfr zone (PDNSException): "<<ae.reason<<endl;
- if(di.backend && transaction) {
- g_log<<Logger::Info<<logPrefix<<"aborting possible open transaction"<<endl;
+ catch (PDNSException& ae) {
+ g_log << Logger::Error << logPrefix << "unable to xfr zone (PDNSException): " << ae.reason << endl;
+ if (di.backend && transaction) {
+ g_log << Logger::Info << logPrefix << "aborting possible open transaction" << endl;
di.backend->abortTransaction();
}
}
}
-namespace {
+namespace
+{
struct DomainNotificationInfo
{
DomainInfo di;
};
}
-
-struct SlaveSenderReceiver
+struct SecondarySenderReceiver
{
typedef std::tuple<DNSName, ComboAddress, uint16_t> Identifier;
- struct Answer {
+ struct Answer
+ {
uint32_t theirSerial;
uint32_t theirInception;
uint32_t theirExpire;
map<uint32_t, Answer> d_freshness;
- SlaveSenderReceiver()
+ SecondarySenderReceiver()
{
}
Identifier send(DomainNotificationInfo& dni)
{
- shuffle(dni.di.masters.begin(), dni.di.masters.end(), pdns::dns_random_engine());
+ shuffle(dni.di.primaries.begin(), dni.di.primaries.end(), pdns::dns_random_engine());
try {
return {dni.di.zone,
- *dni.di.masters.begin(),
- d_resolver.sendResolve(*dni.di.masters.begin(),
- dni.localaddr,
- dni.di.zone,
- QType::SOA,
- nullptr,
- dni.dnssecOk, dni.tsigkeyname, dni.tsigalgname, dni.tsigsecret)
- };
+ *dni.di.primaries.begin(),
+ d_resolver.sendResolve(*dni.di.primaries.begin(),
+ dni.localaddr,
+ dni.di.zone,
+ QType::SOA,
+ nullptr,
+ dni.dnssecOk, dni.tsigkeyname, dni.tsigalgname, dni.tsigsecret)};
}
- catch(PDNSException& e) {
- throw runtime_error("While attempting to query freshness of '"+dni.di.zone.toLogString()+"': "+e.reason);
+ catch (PDNSException& e) {
+ throw runtime_error("While attempting to query freshness of '" + dni.di.zone.toLogString() + "': " + e.reason);
}
}
void deliverAnswer(const DomainNotificationInfo& dni, const Answer& a, unsigned int /* usec */)
{
- d_freshness[dni.di.id]=a;
+ d_freshness[dni.di.id] = a;
}
Resolver d_resolver;
};
-void CommunicatorClass::addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote)
+void CommunicatorClass::addSecondaryCheckRequest(const DomainInfo& di, const ComboAddress& remote)
{
auto data = d_data.lock();
DomainInfo ours = di;
ours.backend = nullptr;
// When adding a check, if the remote addr from which notification was
- // received is a master, clear all other masters so we can be sure the
+ // received is a primary, clear all other primaries so we can be sure the
// query goes to that one.
- for (const auto& master : di.masters) {
- if (ComboAddress::addressOnlyEqual()(remote, master)) {
- ours.masters.clear();
- ours.masters.push_back(master);
+ for (const auto& primary : di.primaries) {
+ if (ComboAddress::addressOnlyEqual()(remote, primary)) {
+ ours.primaries.clear();
+ ours.primaries.push_back(primary);
break;
}
}
d_any_sem.post(); // kick the loop!
}
-void CommunicatorClass::addTrySuperMasterRequest(const DNSPacket& p)
+void CommunicatorClass::addTryAutoPrimaryRequest(const DNSPacket& p)
{
const DNSPacket& ours = p;
auto data = d_data.lock();
- if (data->d_potentialsupermasters.insert(ours).second) {
+ if (data->d_potentialautoprimaries.insert(ours).second) {
d_any_sem.post(); // kick the loop!
}
}
-void CommunicatorClass::slaveRefresh(PacketHandler *P)
+void CommunicatorClass::secondaryRefresh(PacketHandler* P)
{
- // not unless we are slave
- if (!::arg().mustDo("secondary")) return;
+ // not unless we are secondary
+ if (!::arg().mustDo("secondary"))
+ return;
- UeberBackend *B=P->getBackend();
+ UeberBackend* B = P->getBackend();
vector<DomainInfo> rdomains;
vector<DomainNotificationInfo> sdomains;
set<DNSPacket, Data::cmp> trysuperdomains;
auto data = d_data.lock();
set<DomainInfo> requeue;
rdomains.reserve(data->d_tocheck.size());
- for (const auto& di: data->d_tocheck) {
+ for (const auto& di : data->d_tocheck) {
if (data->d_inprogress.count(di.zone)) {
- g_log<<Logger::Debug<<"Got NOTIFY for "<<di.zone<<" while AXFR in progress, requeueing SOA check"<<endl;
+ g_log << Logger::Debug << "Got NOTIFY for " << di.zone << " while AXFR in progress, requeueing SOA check" << endl;
requeue.insert(di);
}
else {
- // We received a NOTIFY for a zone. This means at least one of the zone's master server is working.
- // Therefore we delete the zone from the list of failed slave-checks to allow immediate checking.
- const auto wasFailedDomain = data->d_failedSlaveRefresh.find(di.zone);
- if (wasFailedDomain != data->d_failedSlaveRefresh.end()) {
- g_log<<Logger::Debug<<"Got NOTIFY for "<<di.zone<<", removing zone from list of failed slave-checks and going to check SOA serial"<<endl;
- data->d_failedSlaveRefresh.erase(di.zone);
- } else {
- g_log<<Logger::Debug<<"Got NOTIFY for "<<di.zone<<", going to check SOA serial"<<endl;
+ // We received a NOTIFY for a zone. This means at least one of the zone's primary server is working.
+ // Therefore we delete the zone from the list of failed secondary-checks to allow immediate checking.
+ const auto wasFailedDomain = data->d_failedSecondaryRefresh.find(di.zone);
+ if (wasFailedDomain != data->d_failedSecondaryRefresh.end()) {
+ g_log << Logger::Debug << "Got NOTIFY for " << di.zone << ", removing zone from list of failed secondary-checks and going to check SOA serial" << endl;
+ data->d_failedSecondaryRefresh.erase(di.zone);
+ }
+ else {
+ g_log << Logger::Debug << "Got NOTIFY for " << di.zone << ", going to check SOA serial" << endl;
}
rdomains.push_back(di);
}
}
data->d_tocheck.swap(requeue);
- trysuperdomains = std::move(data->d_potentialsupermasters);
- data->d_potentialsupermasters.clear();
+ trysuperdomains = std::move(data->d_potentialautoprimaries);
+ data->d_potentialautoprimaries.clear();
}
- for(const DNSPacket& dp : trysuperdomains) {
+ for (const DNSPacket& dp : trysuperdomains) {
// get the TSIG key name
TSIGRecordContent trc;
DNSName tsigkeyname;
dp.getTSIGDetails(&trc, &tsigkeyname);
- P->trySuperMasterSynchronous(dp, tsigkeyname); // FIXME could use some error logging
+ P->tryAutoPrimarySynchronous(dp, tsigkeyname); // FIXME could use some error logging
}
- if(rdomains.empty()) { // if we have priority domains, check them first
- B->getUnfreshSlaveInfos(&rdomains);
+ if (rdomains.empty()) { // if we have priority domains, check them first
+ B->getUnfreshSecondaryInfos(&rdomains);
}
sdomains.reserve(rdomains.size());
DNSSECKeeper dk(B); // NOW HEAR THIS! This DK uses our B backend, so no interleaved access!
bool checkSignatures = ::arg().mustDo("secondary-check-signature-freshness") && dk.doesDNSSEC();
{
auto data = d_data.lock();
- domains_by_name_t& nameindex=boost::multi_index::get<IDTag>(data->d_suckdomains);
+ domains_by_name_t& nameindex = boost::multi_index::get<IDTag>(data->d_suckdomains);
time_t now = time(nullptr);
- for(DomainInfo& di : rdomains) {
- const auto failed = data->d_failedSlaveRefresh.find(di.zone);
- if (failed != data->d_failedSlaveRefresh.end() && now < failed->second.second ) {
+ for (DomainInfo& di : rdomains) {
+ const auto failed = data->d_failedSecondaryRefresh.find(di.zone);
+ if (failed != data->d_failedSecondaryRefresh.end() && now < failed->second.second) {
// If the domain has failed before and the time before the next check has not expired, skip this domain
- g_log<<Logger::Debug<<"Zone '"<<di.zone<<"' is on the list of failed SOA checks. Skipping SOA checks until "<< failed->second.second<<endl;
+ g_log << Logger::Debug << "Zone '" << di.zone << "' is on the list of failed SOA checks. Skipping SOA checks until " << failed->second.second << endl;
continue;
}
std::vector<std::string> localaddr;
SuckRequest sr;
- sr.domain=di.zone;
- if(di.masters.empty()) // slave domains w/o masters are ignored
+ sr.domain = di.zone;
+ if (di.primaries.empty()) // secondary domains w/o primaries are ignored
continue;
// remove unfresh domains already queued for AXFR, no sense polling them again
- sr.master=*di.masters.begin();
- if(nameindex.count(sr)) { // this does NOT however protect us against AXFRs already in progress!
+ sr.primary = *di.primaries.begin();
+ if (nameindex.count(sr)) { // this does NOT however protect us against AXFRs already in progress!
continue;
}
- if(data->d_inprogress.count(sr.domain)) { // this does
+ if (data->d_inprogress.count(sr.domain)) { // this does
continue;
}
dni.di = di;
dni.dnssecOk = checkSignatures;
- if(dk.getTSIGForAccess(di.zone, sr.master, &dni.tsigkeyname)) {
+ if (dk.getTSIGForAccess(di.zone, sr.primary, &dni.tsigkeyname)) {
string secret64;
if (!B->getTSIGKey(dni.tsigkeyname, dni.tsigalgname, secret64)) {
- g_log<<Logger::Warning<<"TSIG key '"<<dni.tsigkeyname<<"' for domain '"<<di.zone<<"' not found, can not AXFR."<<endl;
+ g_log << Logger::Warning << "TSIG key '" << dni.tsigkeyname << "' for domain '" << di.zone << "' not found, can not AXFR." << endl;
continue;
}
if (B64Decode(secret64, dni.tsigsecret) == -1) {
- g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<dni.tsigkeyname<<"' for domain '"<<di.zone<<"', can not AXFR."<<endl;
+ g_log << Logger::Error << "Unable to Base-64 decode TSIG key '" << dni.tsigkeyname << "' for domain '" << di.zone << "', can not AXFR." << endl;
continue;
}
}
localaddr.clear();
// check for AXFR-SOURCE
- if(B->getDomainMetadata(di.zone, "AXFR-SOURCE", localaddr) && !localaddr.empty()) {
+ if (B->getDomainMetadata(di.zone, "AXFR-SOURCE", localaddr) && !localaddr.empty()) {
try {
dni.localaddr = ComboAddress(localaddr[0]);
- g_log<<Logger::Info<<"Freshness check source (AXFR-SOURCE) for domain '"<<di.zone<<"' set to "<<localaddr[0]<<endl;
+ g_log << Logger::Info << "Freshness check source (AXFR-SOURCE) for domain '" << di.zone << "' set to " << localaddr[0] << endl;
}
- catch(std::exception& e) {
- g_log<<Logger::Error<<"Failed to load freshness check source '"<<localaddr[0]<<"' for '"<<di.zone<<"': "<<e.what()<<endl;
+ catch (std::exception& e) {
+ g_log << Logger::Error << "Failed to load freshness check source '" << localaddr[0] << "' for '" << di.zone << "': " << e.what() << endl;
return;
}
- } else {
+ }
+ else {
dni.localaddr.sin4.sin_family = 0;
}
sdomains.push_back(std::move(dni));
}
}
- if(sdomains.empty())
- {
- if (d_slaveschanged) {
+ if (sdomains.empty()) {
+ if (d_secondarieschanged) {
auto data = d_data.lock();
- g_log<<Logger::Info<<"No new unfresh slave domains, "<<data->d_suckdomains.size()<<" queued for AXFR already, "<<data->d_inprogress.size()<<" in progress"<<endl;
+ g_log << Logger::Info << "No new unfresh secondary domains, " << data->d_suckdomains.size() << " queued for AXFR already, " << data->d_inprogress.size() << " in progress" << endl;
}
- d_slaveschanged = !rdomains.empty();
+ d_secondarieschanged = !rdomains.empty();
return;
}
else {
auto data = d_data.lock();
- g_log<<Logger::Info<<sdomains.size()<<" slave domain"<<(sdomains.size()>1 ? "s" : "")<<" need"<<
- (sdomains.size()>1 ? "" : "s")<<
- " checking, "<<data->d_suckdomains.size()<<" queued for AXFR"<<endl;
+ g_log << Logger::Info << sdomains.size() << " secondary domain" << (sdomains.size() > 1 ? "s" : "") << " need" << (sdomains.size() > 1 ? "" : "s") << " checking, " << data->d_suckdomains.size() << " queued for AXFR" << endl;
}
- SlaveSenderReceiver ssr;
+ SecondarySenderReceiver ssr;
- Inflighter<vector<DomainNotificationInfo>, SlaveSenderReceiver> ifl(sdomains, ssr);
+ Inflighter<vector<DomainNotificationInfo>, SecondarySenderReceiver> ifl(sdomains, ssr);
ifl.d_maxInFlight = 200;
- for(;;) {
+ for (;;) {
try {
ifl.run();
break;
}
- catch(std::exception& e) {
- g_log<<Logger::Error<<"While checking domain freshness: " << e.what()<<endl;
+ catch (std::exception& e) {
+ g_log << Logger::Error << "While checking domain freshness: " << e.what() << endl;
}
- catch(PDNSException &re) {
- g_log<<Logger::Error<<"While checking domain freshness: " << re.reason<<endl;
+ catch (PDNSException& re) {
+ g_log << Logger::Error << "While checking domain freshness: " << re.reason << endl;
}
}
if (ifl.getTimeouts()) {
- g_log<<Logger::Warning<<"Received serial number updates for "<<ssr.d_freshness.size()<<" zone"<<addS(ssr.d_freshness.size())<<", had "<<ifl.getTimeouts()<<" timeout"<<addS(ifl.getTimeouts())<<endl;
- } else {
- g_log<<Logger::Info<<"Received serial number updates for "<<ssr.d_freshness.size()<<" zone"<<addS(ssr.d_freshness.size())<<endl;
+ g_log << Logger::Warning << "Received serial number updates for " << ssr.d_freshness.size() << " zone" << addS(ssr.d_freshness.size()) << ", had " << ifl.getTimeouts() << " timeout" << addS(ifl.getTimeouts()) << endl;
+ }
+ else {
+ g_log << Logger::Info << "Received serial number updates for " << ssr.d_freshness.size() << " zone" << addS(ssr.d_freshness.size()) << endl;
}
time_t now = time(nullptr);
- for(auto& val : sdomains) {
+ for (auto& val : sdomains) {
DomainInfo& di(val.di);
// If our di comes from packethandler (caused by incoming NOTIFY), di.backend will not be filled out,
// and di.serial will not either.
- // Conversely, if our di came from getUnfreshSlaveInfos, di.backend and di.serial are valid.
- if(!di.backend) {
+ // Conversely, if our di came from getUnfreshSecondaryInfos, di.backend and di.serial are valid.
+ if (!di.backend) {
// Do not overwrite received DI just to make sure it exists in backend:
- // di.masters should contain the picked master (as first entry)!
+ // di.primaries should contain the picked primary (as first entry)!
DomainInfo tempdi;
if (!B->getDomainInfo(di.zone, tempdi, false)) {
- g_log<<Logger::Info<<"Ignore domain "<< di.zone<<" since it has been removed from our backend"<<endl;
+ g_log << Logger::Info << "Ignore domain " << di.zone << " since it has been removed from our backend" << endl;
continue;
}
// Backend for di still doesn't exist and this might cause us to
di.backend = tempdi.backend;
}
- if(!ssr.d_freshness.count(di.id)) { // If we don't have an answer for the domain
+ if (!ssr.d_freshness.count(di.id)) { // If we don't have an answer for the domain
uint64_t newCount = 1;
auto data = d_data.lock();
- const auto failedEntry = data->d_failedSlaveRefresh.find(di.zone);
- if (failedEntry != data->d_failedSlaveRefresh.end())
- newCount = data->d_failedSlaveRefresh[di.zone].first + 1;
+ const auto failedEntry = data->d_failedSecondaryRefresh.find(di.zone);
+ if (failedEntry != data->d_failedSecondaryRefresh.end())
+ newCount = data->d_failedSecondaryRefresh[di.zone].first + 1;
time_t nextCheck = now + std::min(newCount * d_tickinterval, (uint64_t)::arg().asNum("default-ttl"));
- data->d_failedSlaveRefresh[di.zone] = {newCount, nextCheck};
+ data->d_failedSecondaryRefresh[di.zone] = {newCount, nextCheck};
if (newCount == 1) {
- g_log<<Logger::Warning<<"Unable to retrieve SOA for "<<di.zone<<
- ", this was the first time. NOTE: For every subsequent failed SOA check the domain will be suspended from freshness checks for 'num-errors x "<<
- d_tickinterval<<" seconds', with a maximum of "<<(uint64_t)::arg().asNum("default-ttl")<<" seconds. Skipping SOA checks until "<<nextCheck<<endl;
- } else if (newCount % 10 == 0) {
- g_log<<Logger::Notice<<"Unable to retrieve SOA for "<<di.zone<<", this was the "<<std::to_string(newCount)<<"th time. Skipping SOA checks until "<<nextCheck<<endl;
+ g_log << Logger::Warning << "Unable to retrieve SOA for " << di.zone << ", this was the first time. NOTE: For every subsequent failed SOA check the domain will be suspended from freshness checks for 'num-errors x " << d_tickinterval << " seconds', with a maximum of " << (uint64_t)::arg().asNum("default-ttl") << " seconds. Skipping SOA checks until " << nextCheck << endl;
+ }
+ else if (newCount % 10 == 0) {
+ g_log << Logger::Notice << "Unable to retrieve SOA for " << di.zone << ", this was the " << std::to_string(newCount) << "th time. Skipping SOA checks until " << nextCheck << endl;
}
// Make sure we recheck SOA for notifies
if (di.receivedNotify) {
{
auto data = d_data.lock();
- const auto wasFailedDomain = data->d_failedSlaveRefresh.find(di.zone);
- if (wasFailedDomain != data->d_failedSlaveRefresh.end())
- data->d_failedSlaveRefresh.erase(di.zone);
+ const auto wasFailedDomain = data->d_failedSecondaryRefresh.find(di.zone);
+ if (wasFailedDomain != data->d_failedSecondaryRefresh.end())
+ data->d_failedSecondaryRefresh.erase(di.zone);
}
bool hasSOA = false;
hasSOA = B->get(zr);
if (hasSOA) {
fillSOAData(zr, sd);
- while(B->get(zr));
+ while (B->get(zr))
+ ;
}
}
- catch(...) {}
+ catch (...) {
+ }
uint32_t theirserial = ssr.d_freshness[di.id].theirSerial;
uint32_t ourserial = sd.serial;
- const ComboAddress remote = *di.masters.begin();
+ const ComboAddress remote = *di.primaries.begin();
- if(hasSOA && rfc1982LessThan(theirserial, ourserial) && !::arg().mustDo("axfr-lower-serial")) {
- g_log<<Logger::Warning<<"Domain '" << di.zone << "' more recent than master " << remote.toStringWithPortExcept(53) << ", our serial "<< ourserial<< " > their serial "<< theirserial << endl;
+ if (hasSOA && rfc1982LessThan(theirserial, ourserial) && !::arg().mustDo("axfr-lower-serial")) {
+ g_log << Logger::Warning << "Domain '" << di.zone << "' more recent than primary " << remote.toStringWithPortExcept(53) << ", our serial " << ourserial << " > their serial " << theirserial << endl;
di.backend->setFresh(di.id);
}
- else if(hasSOA && theirserial == ourserial) {
- uint32_t maxExpire=0, maxInception=0;
- if(checkSignatures && dk.isPresigned(di.zone)) {
+ else if (hasSOA && theirserial == ourserial) {
+ uint32_t maxExpire = 0, maxInception = 0;
+ if (checkSignatures && dk.isPresigned(di.zone)) {
B->lookup(QType(QType::RRSIG), di.zone, di.id); // can't use DK before we are done with this lookup!
DNSZoneRecord zr;
- while(B->get(zr)) {
+ while (B->get(zr)) {
auto rrsig = getRR<RRSIGRecordContent>(zr.dr);
- if(rrsig->d_type == QType::SOA) {
+ if (rrsig->d_type == QType::SOA) {
maxInception = std::max(maxInception, rrsig->d_siginception);
maxExpire = std::max(maxExpire, rrsig->d_sigexpire);
}
prio = SuckRequest::Notify;
}
- if(! maxInception && ! ssr.d_freshness[di.id].theirInception) {
- g_log<<Logger::Info<<"Domain '"<< di.zone << "' is fresh (no DNSSEC), serial is " << ourserial << " (checked master " << remote.toStringWithPortExcept(53) << ")" << endl;
+ if (!maxInception && !ssr.d_freshness[di.id].theirInception) {
+ g_log << Logger::Info << "Domain '" << di.zone << "' is fresh (no DNSSEC), serial is " << ourserial << " (checked primary " << remote.toStringWithPortExcept(53) << ")" << endl;
di.backend->setFresh(di.id);
}
- else if(maxInception == ssr.d_freshness[di.id].theirInception && maxExpire == ssr.d_freshness[di.id].theirExpire) {
- g_log<<Logger::Info<<"Domain '"<< di.zone << "' is fresh and SOA RRSIGs match, serial is " << ourserial << " (checked master " << remote.toStringWithPortExcept(53) << ")" << endl;
+ else if (maxInception == ssr.d_freshness[di.id].theirInception && maxExpire == ssr.d_freshness[di.id].theirExpire) {
+ g_log << Logger::Info << "Domain '" << di.zone << "' is fresh and SOA RRSIGs match, serial is " << ourserial << " (checked primary " << remote.toStringWithPortExcept(53) << ")" << endl;
di.backend->setFresh(di.id);
}
- else if(maxExpire >= now && ! ssr.d_freshness[di.id].theirInception ) {
- g_log<<Logger::Info<<"Domain '"<< di.zone << "' is fresh, master " << remote.toStringWithPortExcept(53) << " is no longer signed but (some) signatures are still valid, serial is " << ourserial << endl;
+ else if (maxExpire >= now && !ssr.d_freshness[di.id].theirInception) {
+ g_log << Logger::Info << "Domain '" << di.zone << "' is fresh, primary " << remote.toStringWithPortExcept(53) << " is no longer signed but (some) signatures are still valid, serial is " << ourserial << endl;
di.backend->setFresh(di.id);
}
- else if(maxInception && ! ssr.d_freshness[di.id].theirInception ) {
- g_log<<Logger::Notice<<"Domain '"<< di.zone << "' is stale, master " << remote.toStringWithPortExcept(53) << " is no longer signed and all signatures have expired, serial is " << ourserial << endl;
+ else if (maxInception && !ssr.d_freshness[di.id].theirInception) {
+ g_log << Logger::Notice << "Domain '" << di.zone << "' is stale, primary " << remote.toStringWithPortExcept(53) << " is no longer signed and all signatures have expired, serial is " << ourserial << endl;
addSuckRequest(di.zone, remote, prio);
}
- else if(dk.doesDNSSEC() && ! maxInception && ssr.d_freshness[di.id].theirInception) {
- g_log<<Logger::Notice<<"Domain '"<< di.zone << "' is stale, master " << remote.toStringWithPortExcept(53) << " has signed, serial is " << ourserial << endl;
+ else if (dk.doesDNSSEC() && !maxInception && ssr.d_freshness[di.id].theirInception) {
+ g_log << Logger::Notice << "Domain '" << di.zone << "' is stale, primary " << remote.toStringWithPortExcept(53) << " has signed, serial is " << ourserial << endl;
addSuckRequest(di.zone, remote, prio);
}
else {
- g_log<<Logger::Notice<<"Domain '"<< di.zone << "' is fresh, but RRSIGs differ on master " << remote.toStringWithPortExcept(53)<<", so DNSSEC is stale, serial is " << ourserial << endl;
+ g_log << Logger::Notice << "Domain '" << di.zone << "' is fresh, but RRSIGs differ on primary " << remote.toStringWithPortExcept(53) << ", so DNSSEC is stale, serial is " << ourserial << endl;
addSuckRequest(di.zone, remote, prio);
}
}
}
if (hasSOA) {
- g_log<<Logger::Notice<<"Domain '"<< di.zone << "' is stale, master " << remote.toStringWithPortExcept(53) << " serial " << theirserial << ", our serial " << ourserial << endl;
+ g_log << Logger::Notice << "Domain '" << di.zone << "' is stale, primary " << remote.toStringWithPortExcept(53) << " serial " << theirserial << ", our serial " << ourserial << endl;
}
else {
- g_log<<Logger::Notice<<"Domain '"<< di.zone << "' is empty, master " << remote.toStringWithPortExcept(53) << " serial " << theirserial << endl;
+ g_log << Logger::Notice << "Domain '" << di.zone << "' is empty, primary " << remote.toStringWithPortExcept(53) << " serial " << theirserial << endl;
}
addSuckRequest(di.zone, remote, prio);
}
}
}
-vector<pair<DNSName, ComboAddress> > CommunicatorClass::getSuckRequests() {
- vector<pair<DNSName, ComboAddress> > ret;
+vector<pair<DNSName, ComboAddress>> CommunicatorClass::getSuckRequests()
+{
+ vector<pair<DNSName, ComboAddress>> ret;
auto data = d_data.lock();
ret.reserve(data->d_suckdomains.size());
- for (auto const &d : data->d_suckdomains) {
- ret.emplace_back(d.domain, d.master);
+ for (auto const& d : data->d_suckdomains) {
+ ret.emplace_back(d.domain, d.primary);
}
return ret;
}
-size_t CommunicatorClass::getSuckRequestsWaiting() {
+size_t CommunicatorClass::getSuckRequestsWaiting()
+{
return d_data.lock()->d_suckdomains.size();
}
d_listSubZoneQuery=getArg("list-subzone-query");
d_InfoOfDomainsZoneQuery=getArg("info-zone-query");
- d_InfoOfAllSlaveDomainsQuery=getArg("info-all-slaves-query");
- d_SuperMasterInfoQuery=getArg("supermaster-query");
- d_GetSuperMasterIPs=getArg("supermaster-name-to-ips");
- d_AddSuperMaster=getArg("supermaster-add");
+ d_InfoOfAllSecondaryDomainsQuery = getArg("info-all-secondaries-query");
+ d_AutoPrimaryInfoQuery = getArg("autoprimary-query");
+ d_GetAutoPrimaryIPs = getArg("autoprimary-name-to-ips");
+ d_AddAutoPrimary = getArg("autoprimary-add");
d_RemoveAutoPrimaryQuery=getArg("autoprimary-remove");
d_ListAutoPrimariesQuery=getArg("list-autoprimaries");
d_InsertZoneQuery=getArg("insert-zone-query");
d_InsertRecordQuery=getArg("insert-record-query");
- d_UpdateMasterOfZoneQuery=getArg("update-master-query");
+ d_UpdatePrimaryOfZoneQuery = getArg("update-primary-query");
d_UpdateKindOfZoneQuery=getArg("update-kind-query");
d_UpdateSerialOfZoneQuery=getArg("update-serial-query");
d_UpdateLastCheckOfZoneQuery=getArg("update-lastcheck-query");
d_UpdateOptionsOfZoneQuery = getArg("update-options-query");
d_UpdateCatalogOfZoneQuery = getArg("update-catalog-query");
d_UpdateAccountOfZoneQuery=getArg("update-account-query");
- d_InfoOfAllMasterDomainsQuery=getArg("info-all-master-query");
+ d_InfoOfAllPrimaryDomainsQuery = getArg("info-all-primary-query");
d_InfoProducerMembersQuery = getArg("info-producer-members-query");
d_InfoConsumerMembersQuery = getArg("info-consumer-members-query");
d_DeleteDomainQuery=getArg("delete-domain-query");
d_listQuery_stmt = nullptr;
d_listSubZoneQuery_stmt = nullptr;
d_InfoOfDomainsZoneQuery_stmt = nullptr;
- d_InfoOfAllSlaveDomainsQuery_stmt = nullptr;
- d_SuperMasterInfoQuery_stmt = nullptr;
- d_GetSuperMasterIPs_stmt = nullptr;
- d_AddSuperMaster_stmt = nullptr;
+ d_InfoOfAllSecondaryDomainsQuery_stmt = nullptr;
+ d_AutoPrimaryInfoQuery_stmt = nullptr;
+ d_GetAutoPrimaryIPs_stmt = nullptr;
+ d_AddAutoPrimary_stmt = nullptr;
d_RemoveAutoPrimary_stmt = nullptr;
d_ListAutoPrimaries_stmt = nullptr;
d_InsertZoneQuery_stmt = nullptr;
d_InsertRecordQuery_stmt = nullptr;
d_InsertEmptyNonTerminalOrderQuery_stmt = nullptr;
- d_UpdateMasterOfZoneQuery_stmt = nullptr;
+ d_UpdatePrimaryOfZoneQuery_stmt = nullptr;
d_UpdateKindOfZoneQuery_stmt = nullptr;
d_UpdateSerialOfZoneQuery_stmt = nullptr;
d_UpdateLastCheckOfZoneQuery_stmt = nullptr;
d_UpdateOptionsOfZoneQuery_stmt = nullptr;
d_UpdateCatalogOfZoneQuery_stmt = nullptr;
d_UpdateAccountOfZoneQuery_stmt = nullptr;
- d_InfoOfAllMasterDomainsQuery_stmt = nullptr;
+ d_InfoOfAllPrimaryDomainsQuery_stmt = nullptr;
d_InfoProducerMembersQuery_stmt = nullptr;
d_InfoConsumerMembersQuery_stmt = nullptr;
d_DeleteDomainQuery_stmt = nullptr;
try {
reconnectIfNeeded();
+ // clang-format off
d_UpdateSerialOfZoneQuery_stmt->
bind("serial", serial)->
bind("domain_id", domain_id)->
execute()->
reset();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to refresh domain_id "+std::to_string(domain_id)+": "+e.txtReason());
try {
reconnectIfNeeded();
- d_UpdateLastCheckOfZoneQuery_stmt->bind("last_check", lastcheck)->bind("domain_id", domain_id)->execute()->reset();
+ // clang-format off
+ d_UpdateLastCheckOfZoneQuery_stmt->
+ bind("last_check", lastcheck)->
+ bind("domain_id", domain_id)->
+ execute()->reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to update last_check for domain_id " + std::to_string(domain_id) + ": " + e.txtReason());
setLastCheck(domain_id, time(nullptr));
}
-bool GSQLBackend::setMasters(const DNSName &domain, const vector<ComboAddress> &masters)
+bool GSQLBackend::setPrimaries(const DNSName& domain, const vector<ComboAddress>& primaries)
{
- vector<string> masters_s;
- masters_s.reserve(masters.size());
- for (const auto& master : masters) {
- masters_s.push_back(master.toStringWithPortExcept(53));
+ vector<string> primaries_s;
+ primaries_s.reserve(primaries.size());
+ for (const auto& primary : primaries) {
+ primaries_s.push_back(primary.toStringWithPortExcept(53));
}
- auto tmp = boost::join(masters_s, ", ");
+ auto tmp = boost::join(primaries_s, ", ");
try {
reconnectIfNeeded();
- d_UpdateMasterOfZoneQuery_stmt->
+ // clang-format off
+ d_UpdatePrimaryOfZoneQuery_stmt->
bind("master", tmp)->
bind("domain", domain)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
- throw PDNSException("GSQLBackend unable to set masters of domain '"+domain.toLogString()+"' to " + tmp + ": "+e.txtReason());
+ throw PDNSException("GSQLBackend unable to set primaries of domain '" + domain.toLogString() + "' to " + tmp + ": " + e.txtReason());
}
return true;
}
try {
reconnectIfNeeded();
+ // clang-format off
d_UpdateKindOfZoneQuery_stmt->
bind("kind", toUpper(DomainInfo::getKindString(kind)))->
bind("domain", domain)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to set kind of domain '"+domain.toLogString()+"' to " + toUpper(DomainInfo::getKindString(kind)) + ": "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_UpdateAccountOfZoneQuery_stmt->
- bind("account", account)->
- bind("domain", domain)->
- execute()->
- reset();
+ bind("account", account)->
+ bind("domain", domain)->
+ execute()->
+ reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to set account of domain '"+domain.toLogString()+"' to '" + account + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_InfoOfDomainsZoneQuery_stmt->
bind("domain", domain)->
execute()->
getResult(d_result)->
reset();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to retrieve information about domain '" + domain.toLogString() + "': "+e.txtReason());
di.account = d_result[0][8];
di.kind = DomainInfo::stringToKind(type);
- vector<string> masters;
- stringtok(masters, d_result[0][2], " ,\t");
- for(const auto& m : masters)
- di.masters.emplace_back(m, 53);
+ vector<string> primaries;
+ stringtok(primaries, d_result[0][2], " ,\t");
+ for (const auto& m : primaries)
+ di.primaries.emplace_back(m, 53);
pdns::checked_stoi_into(di.last_check, d_result[0][3]);
pdns::checked_stoi_into(di.notified_serial, d_result[0][4]);
di.backend=this;
return true;
}
-void GSQLBackend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
+void GSQLBackend::getUnfreshSecondaryInfos(vector<DomainInfo>* unfreshDomains)
{
/*
list all domains that need refreshing for which we are secondary, and insert into
reconnectIfNeeded();
// clang-format off
- d_InfoOfAllSlaveDomainsQuery_stmt->
+ d_InfoOfAllSecondaryDomainsQuery_stmt->
execute()->
getResult(d_result)->
reset();
// clang-format on
}
catch (SSqlException &e) {
- throw PDNSException(std::string(__PRETTY_FUNCTION__) + " unable to retrieve list of slave domains: " + e.txtReason());
+ throw PDNSException(std::string(__PRETTY_FUNCTION__) + " unable to retrieve list of secondary domains: " + e.txtReason());
}
SOAData sd;
DomainInfo di;
- vector<string> masters;
+ vector<string> primaries;
unfreshDomains->reserve(d_result.size());
for (const auto& row : d_result) { // id, name, type, master, last_check, catalog, content
- ASSERT_ROW_COLUMNS("info-all-slaves-query", row, 6);
+ ASSERT_ROW_COLUMNS("info-all-secondaries-query", row, 6);
try {
di.zone = DNSName(row[1]);
continue;
}
- di.masters.clear();
- masters.clear();
- stringtok(masters, row[3], ", \t");
- for(const auto& m : masters) {
+ di.primaries.clear();
+ primaries.clear();
+ stringtok(primaries, row[3], ", \t");
+ for (const auto& m : primaries) {
try {
- di.masters.emplace_back(m, 53);
+ di.primaries.emplace_back(m, 53);
} catch(const PDNSException &e) {
- g_log << Logger::Warning << __PRETTY_FUNCTION__ << " could not parse master address '" << m << "' for zone '" << di.zone << "': " << e.reason << endl;
+ g_log << Logger::Warning << __PRETTY_FUNCTION__ << " could not parse primary address '" << m << "' for zone '" << di.zone << "': " << e.reason << endl;
}
}
- if (di.masters.empty()) {
- g_log << Logger::Warning << __PRETTY_FUNCTION__ << " no masters for secondary zone '" << di.zone << "' found in the database" << endl;
+ if (di.primaries.empty()) {
+ g_log << Logger::Warning << __PRETTY_FUNCTION__ << " no primaries for secondary zone '" << di.zone << "' found in the database" << endl;
continue;
}
if (pdns_iequals(row[2], "SLAVE")) {
- di.kind = DomainInfo::Slave;
+ di.kind = DomainInfo::Secondary;
}
else if (pdns_iequals(row[2], "CONSUMER")) {
di.kind = DomainInfo::Consumer;
}
}
-void GSQLBackend::getUpdatedMasters(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
+void GSQLBackend::getUpdatedPrimaries(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
{
/*
list all domains that need notifications for which we are promary, and insert into
reconnectIfNeeded();
// clang-format off
- d_InfoOfAllMasterDomainsQuery_stmt->
+ d_InfoOfAllPrimaryDomainsQuery_stmt->
execute()->
getResult(d_result)->
reset();
// clang-format on
}
catch(SSqlException &e) {
- throw PDNSException(std::string(__PRETTY_FUNCTION__) + " unable to retrieve list of master domains: " + e.txtReason());
+ throw PDNSException(std::string(__PRETTY_FUNCTION__) + " unable to retrieve list of primary domains: " + e.txtReason());
}
SOAData sd;
updatedDomains.reserve(d_result.size());
for (const auto& row : d_result) { // id, name, type, notified_serial, options, catalog, content
- ASSERT_ROW_COLUMNS("info-all-master-query", row, 7);
+ ASSERT_ROW_COLUMNS("info-all-primary-query", row, 7);
di.backend = this;
}
if (di.notified_serial != sd.serial) {
- di.kind = DomainInfo::Master;
+ di.kind = DomainInfo::Primary;
di.serial = sd.serial;
di.catalog.clear();
}
if (row.size() >= 4) { // Consumer only
- vector<string> masters;
- stringtok(masters, row[3], ", \t");
- for (const auto& m : masters) {
+ vector<string> primaries;
+ stringtok(primaries, row[3], ", \t");
+ for (const auto& m : primaries) {
try {
ci.d_primaries.emplace_back(m, 53);
}
catch (const PDNSException& e) {
- g_log << Logger::Warning << __PRETTY_FUNCTION__ << " could not parse master address '" << m << "' for zone '" << ci.d_zone << "': " << e.reason << endl;
+ g_log << Logger::Warning << __PRETTY_FUNCTION__ << " could not parse primary address '" << m << "' for zone '" << ci.d_zone << "': " << e.reason << endl;
members.clear();
return false;
}
try {
reconnectIfNeeded();
+ // clang-format off
d_updateOrderNameAndAuthQuery_stmt->
bind("ordername", ordername.labelReverse().toString(" ", false))->
bind("auth", auth)->
bind("qname", qname)->
execute()->
reset();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to update ordername and auth for " + qname.toLogString() + " for domain_id "+std::to_string(domain_id)+", domain name '" + qname.toLogString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_updateOrderNameAndAuthTypeQuery_stmt->
bind("ordername", ordername.labelReverse().toString(" ", false))->
bind("auth", auth)->
bind("qtype", QType(qtype).toString())->
execute()->
reset();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to update ordername and auth for " + qname.toLogString() + "|" + QType(qtype).toString() + " for domain_id "+std::to_string(domain_id)+": "+e.txtReason());
reconnectIfNeeded();
try {
+ // clang-format off
d_nullifyOrderNameAndUpdateAuthQuery_stmt->
bind("auth", auth)->
bind("domain_id", domain_id)->
bind("qname", qname)->
execute()->
reset();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to nullify ordername and update auth for " + qname.toLogString() + " for domain_id "+std::to_string(domain_id)+": "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt->
bind("auth", auth)->
bind("domain_id", domain_id)->
bind("qtype", QType(qtype).toString())->
execute()->
reset();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to nullify ordername and update auth for " + qname.toLogString() + "|" + QType(qtype).toString() + " for domain_id "+std::to_string(domain_id)+": "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_RemoveEmptyNonTerminalsFromZoneQuery_stmt->
bind("domain_id", domain_id)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to delete empty non-terminal records from domain_id "+std::to_string(domain_id)+": "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_DeleteEmptyNonTerminalQuery_stmt->
bind("domain_id", domain_id)->
bind("qname", qname)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to delete empty non-terminal rr '"+qname.toLogString()+"' from domain_id "+std::to_string(domain_id)+": "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_InsertEmptyNonTerminalOrderQuery_stmt->
bind("domain_id", domain_id)->
bind("qname", qname)->
bind("auth", true)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to insert empty non-terminal rr '"+qname.toLogString()+"' in domain_id "+std::to_string(domain_id)+": "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_afterOrderQuery_stmt->
bind("ordername", qname.labelReverse().toString(" ", false))->
bind("domain_id", id)->
execute();
+ // clang-format on
while(d_afterOrderQuery_stmt->hasNextRow()) {
d_afterOrderQuery_stmt->nextRow(row);
ASSERT_ROW_COLUMNS("get-order-after-query", row, 1);
try {
reconnectIfNeeded();
+ // clang-format off
d_firstOrderQuery_stmt->
bind("domain_id", id)->
execute();
+ // clang-format on
while(d_firstOrderQuery_stmt->hasNextRow()) {
d_firstOrderQuery_stmt->nextRow(row);
ASSERT_ROW_COLUMNS("get-order-first-query", row, 1);
try {
reconnectIfNeeded();
+ // clang-format off
d_beforeOrderQuery_stmt->
bind("ordername", qname.labelReverse().toString(" ", false))->
bind("domain_id", id)->
execute();
+ // clang-format on
while(d_beforeOrderQuery_stmt->hasNextRow()) {
d_beforeOrderQuery_stmt->nextRow(row);
ASSERT_ROW_COLUMNS("get-order-before-query", row, 2);
try {
reconnectIfNeeded();
+ // clang-format off
d_lastOrderQuery_stmt->
bind("domain_id", id)->
execute();
+ // clang-format on
while(d_lastOrderQuery_stmt->hasNextRow()) {
d_lastOrderQuery_stmt->nextRow(row);
ASSERT_ROW_COLUMNS("get-order-last-query", row, 2);
try {
reconnectIfNeeded();
+ // clang-format off
d_AddDomainKeyQuery_stmt->
bind("flags", key.flags)->
bind("active", key.active)->
bind("content", key.content)->
bind("domain", name)->
execute();
+ // clang-format on
if (d_AddDomainKeyQuery_stmt->hasNextRow()) {
SSqlStatement::row_t row;
try {
reconnectIfNeeded();
+ // clang-format off
d_ActivateDomainKeyQuery_stmt->
bind("domain", name)->
bind("key_id", id)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to activate key with id "+ std::to_string(id) + " for domain '" + name.toLogString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_DeactivateDomainKeyQuery_stmt->
bind("domain", name)->
bind("key_id", id)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to deactivate key with id "+ std::to_string(id) + " for domain '" + name.toLogString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_PublishDomainKeyQuery_stmt->
bind("domain", name)->
bind("key_id", id)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to publish key with id "+ std::to_string(id) + " for domain '" + name.toLogString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_UnpublishDomainKeyQuery_stmt->
bind("domain", name)->
bind("key_id", id)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to unpublish key with id "+ std::to_string(id) + " for domain '" + name.toLogString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_RemoveDomainKeyQuery_stmt->
bind("domain", name)->
bind("key_id", id)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to remove key with id "+ std::to_string(id) + " for domain '" + name.toLogString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_getTSIGKeyQuery_stmt->
bind("key_name", name)->
execute();
+ // clang-format on
SSqlStatement::row_t row;
try {
reconnectIfNeeded();
+ // clang-format off
d_setTSIGKeyQuery_stmt->
bind("key_name", name)->
bind("algorithm", algorithm)->
bind("content", content)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to store TSIG key with name '" + name.toLogString() + "' and algorithm '" + algorithm.toString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_deleteTSIGKeyQuery_stmt->
bind("key_name", name)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to delete TSIG key with name '" + name.toLogString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_getTSIGKeysQuery_stmt->
execute();
+ // clang-format on
SSqlStatement::row_t row;
try {
reconnectIfNeeded();
+ // clang-format off
d_ListDomainKeysQuery_stmt->
bind("domain", name)->
execute();
+ // clang-format on
SSqlStatement::row_t row;
KeyData kd;
try {
reconnectIfNeeded();
+ // clang-format off
d_GetAllDomainMetadataQuery_stmt->
bind("domain", name)->
execute();
+ // clang-format on
SSqlStatement::row_t row;
try {
reconnectIfNeeded();
+ // clang-format off
d_GetDomainMetadataQuery_stmt->
bind("domain", name)->
bind("kind", kind)->
execute();
+ // clang-format on
SSqlStatement::row_t row;
try {
reconnectIfNeeded();
+ // clang-format off
d_ClearDomainMetadataQuery_stmt->
bind("domain", name)->
bind("kind", kind)->
execute()->
reset();
+ // clang-format on
if(!meta.empty()) {
for(const auto& value: meta) {
+ // clang-format off
d_SetDomainMetadataQuery_stmt->
bind("kind", kind)->
bind("content", value)->
bind("domain", name)->
execute()->
reset();
+ // clang-format on
}
}
}
if(domain_id < 0) {
d_query_name = "basic-query";
d_query_stmt = &d_NoIdQuery_stmt;
+ // clang-format off
(*d_query_stmt)->
bind("qtype", qtype.toString())->
bind("qname", qname);
+ // clang-format on
} else {
d_query_name = "id-query";
d_query_stmt = &d_IdQuery_stmt;
+ // clang-format off
(*d_query_stmt)->
bind("qtype", qtype.toString())->
bind("qname", qname)->
bind("domain_id", domain_id);
+ // clang-format on
}
} else {
// qtype==ANY
if(domain_id < 0) {
d_query_name = "any-query";
d_query_stmt = &d_ANYNoIdQuery_stmt;
+ // clang-format off
(*d_query_stmt)->
bind("qname", qname);
+ // clang-format on
} else {
d_query_name = "any-id-query";
d_query_stmt = &d_ANYIdQuery_stmt;
+ // clang-format off
(*d_query_stmt)->
bind("qname", qname)->
bind("domain_id", domain_id);
+ // clang-format on
}
}
d_query_name = "list-query";
d_query_stmt = &d_listQuery_stmt;
+ // clang-format off
(*d_query_stmt)->
bind("include_disabled", (int)include_disabled)->
bind("domain_id", domain_id)->
execute();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to list domain '" + target.toLogString() + "': "+e.txtReason());
d_query_name = "list-subzone-query";
d_query_stmt = &d_listSubZoneQuery_stmt;
+ // clang-format off
(*d_query_stmt)->
bind("zone", zone)->
bind("wildzone", wildzone)->
bind("domain_id", domain_id)->
execute();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to list SubZones for domain '" + zone.toLogString() + "': "+e.txtReason());
return false;
}
-bool GSQLBackend::superMasterAdd(const AutoPrimary& primary)
+bool GSQLBackend::autoPrimaryAdd(const AutoPrimary& primary)
{
try{
reconnectIfNeeded();
- d_AddSuperMaster_stmt ->
+ // clang-format off
+ d_AddAutoPrimary_stmt ->
bind("ip",primary.ip)->
bind("nameserver",primary.nameserver)->
bind("account",primary.account)->
execute()->
reset();
-
+ // clang-format on
}
catch (SSqlException &e){
throw PDNSException("GSQLBackend unable to insert an autoprimary with IP " + primary.ip + " and nameserver name '" + primary.nameserver + "' and account '" + primary.account + "': " + e.txtReason());
try{
reconnectIfNeeded();
+ // clang-format off
d_RemoveAutoPrimary_stmt ->
bind("ip",primary.ip)->
bind("nameserver",primary.nameserver)->
execute()->
reset();
-
+ // clang-format on
}
catch (SSqlException &e){
throw PDNSException("GSQLBackend unable to remove an autoprimary with IP " + primary.ip + " and nameserver name '" + primary.nameserver + "': " + e.txtReason());
try{
reconnectIfNeeded();
+ // clang-format off
d_ListAutoPrimaries_stmt->
execute()->
getResult(d_result)->
reset();
+ // clang-format on
}
catch (SSqlException &e){
throw PDNSException("GSQLBackend unable to list autoprimaries: " + e.txtReason());
return true;
}
-bool GSQLBackend::superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **ddb)
+bool GSQLBackend::autoPrimaryBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** ddb)
{
// check if we know the ip/ns couple in the database
for(const auto & i : nsset) {
try {
reconnectIfNeeded();
- d_SuperMasterInfoQuery_stmt->
+ // clang-format off
+ d_AutoPrimaryInfoQuery_stmt->
bind("ip", ip)->
bind("nameserver", i.content)->
execute()->
getResult(d_result)->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
- throw PDNSException("GSQLBackend unable to search for a supermaster with IP " + ip + " and nameserver name '" + i.content + "' for domain '" + domain.toLogString() + "': "+e.txtReason());
+ throw PDNSException("GSQLBackend unable to search for a autoprimary with IP " + ip + " and nameserver name '" + i.content + "' for domain '" + domain.toLogString() + "': " + e.txtReason());
}
if(!d_result.empty()) {
- ASSERT_ROW_COLUMNS("supermaster-query", d_result[0], 1);
+ ASSERT_ROW_COLUMNS("autoprimary-query", d_result[0], 1);
*nameserver=i.content;
*account=d_result[0][0];
*ddb=this;
return false;
}
-bool GSQLBackend::createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& masters, const string& account)
+bool GSQLBackend::createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& primaries, const string& account)
{
- vector<string> masters_s;
- masters_s.reserve(masters.size());
- for (const auto& master : masters) {
- masters_s.push_back(master.toStringWithPortExcept(53));
+ vector<string> primaries_s;
+ primaries_s.reserve(primaries.size());
+ for (const auto& primary : primaries) {
+ primaries_s.push_back(primary.toStringWithPortExcept(53));
}
try {
d_InsertZoneQuery_stmt->
bind("type", toUpper(DomainInfo::getKindString(kind)))->
bind("domain", domain)->
- bind("masters", boost::join(masters_s, ", "))->
+ bind("primaries", boost::join(primaries_s, ", "))->
bind("account", account)->
execute()->
reset();
return true;
}
-bool GSQLBackend::createSlaveDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account)
+bool GSQLBackend::createSecondaryDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account)
{
string name;
- vector<ComboAddress> masters({ComboAddress(ip, 53)});
+ vector<ComboAddress> primaries({ComboAddress(ip, 53)});
try {
if (!nameserver.empty()) {
- // figure out all IP addresses for the master
+ // figure out all IP addresses for the primary
reconnectIfNeeded();
- d_GetSuperMasterIPs_stmt->
+ // clang-format off
+ d_GetAutoPrimaryIPs_stmt->
bind("nameserver", nameserver)->
bind("account", account)->
execute()->
getResult(d_result)->
reset();
+ // clang-format on
if (!d_result.empty()) {
// collect all IP addresses
vector<ComboAddress> tmp;
if (account == row[1])
tmp.emplace_back(row[0], 53);
}
- // set them as domain's masters, comma separated
- masters = tmp;
+ // set them as domain's primaries, comma separated
+ primaries = tmp;
}
}
- createDomain(domain, DomainInfo::Slave, masters, account);
+ createDomain(domain, DomainInfo::Secondary, primaries, account);
}
catch(SSqlException &e) {
- throw PDNSException("Database error trying to insert new slave domain '"+domain.toLogString()+"': "+ e.txtReason());
+ throw PDNSException("Database error trying to insert new secondary domain '" + domain.toLogString() + "': " + e.txtReason());
}
return true;
}
try {
reconnectIfNeeded();
+ // clang-format off
d_DeleteZoneQuery_stmt->
bind("domain_id", di.id)->
execute()->
bind("domain", domain)->
execute()->
reset();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("Database error trying to delete domain '"+domain.toLogString()+"': "+ e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_getAllDomainsQuery_stmt->
bind("include_disabled", (int)include_disabled)->
execute();
+ // clang-format on
SSqlStatement::row_t row;
while (d_getAllDomainsQuery_stmt->hasNextRow()) {
}
if (pdns_iequals(row[3], "MASTER")) {
- di.kind = DomainInfo::Master;
+ di.kind = DomainInfo::Primary;
} else if (pdns_iequals(row[3], "SLAVE")) {
- di.kind = DomainInfo::Slave;
+ di.kind = DomainInfo::Secondary;
} else if (pdns_iequals(row[3], "NATIVE")) {
di.kind = DomainInfo::Native;
}
}
if (!row[4].empty()) {
- vector<string> masters;
- stringtok(masters, row[4], " ,\t");
- for(const auto& m : masters) {
+ vector<string> primaries;
+ stringtok(primaries, row[4], " ,\t");
+ for (const auto& m : primaries) {
try {
- di.masters.emplace_back(m, 53);
+ di.primaries.emplace_back(m, 53);
} catch(const PDNSException &e) {
- g_log<<Logger::Warning<<"Could not parse master address ("<<m<<") for zone '"<<di.zone<<"': "<<e.reason;
+ g_log << Logger::Warning << "Could not parse primary address (" << m << ") for zone '" << di.zone << "': " << e.reason;
}
}
}
if (qt != QType::ANY) {
if (d_upgradeContent) {
+ // clang-format off
d_DeleteRRSetQuery_stmt->
bind("domain_id", domain_id)->
bind("qname", qname)->
bind("qtype", "TYPE"+std::to_string(qt.getCode()))->
execute()->
reset();
+ // clang-format on
}
+ // clang-format off
d_DeleteRRSetQuery_stmt->
bind("domain_id", domain_id)->
bind("qname", qname)->
bind("qtype", qt.toString())->
execute()->
reset();
+ // clang-format on
} else {
+ // clang-format off
d_DeleteNamesQuery_stmt->
bind("domain_id", domain_id)->
bind("qname", qname)->
execute()->
reset();
+ // clang-format on
}
}
catch (SSqlException &e) {
try {
reconnectIfNeeded();
+ // clang-format off
d_DeleteCommentRRsetQuery_stmt->
bind("domain_id", domain_id)->
bind("qname", qname)->
bind("qtype", qt.toString())->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to delete comment for RRSet " + qname.toLogString() + "|" + qt.toString() + ": "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_InsertRecordQuery_stmt->
- bind("content",content)->
- bind("ttl",r.ttl)->
- bind("priority",prio)->
- bind("qtype",r.qtype.toString())->
- bind("domain_id",r.domain_id)->
- bind("disabled",r.disabled)->
- bind("qname",r.qname);
+ bind("content", content)->
+ bind("ttl", r.ttl)->
+ bind("priority", prio)->
+ bind("qtype", r.qtype.toString())->
+ bind("domain_id", r.domain_id)->
+ bind("disabled", r.disabled)->
+ bind("qname", r.qname);
+ // clang-format on
if (!ordername.empty())
d_InsertRecordQuery_stmt->bind("ordername", ordername.labelReverse().makeLowerCase().toString(" ", false));
try {
reconnectIfNeeded();
+ // clang-format off
d_InsertEmptyNonTerminalOrderQuery_stmt->
- bind("domain_id",domain_id)->
+ bind("domain_id", domain_id)->
bind("qname", nt.first)->
bindNull("ordername")->
- bind("auth",(nt.second || !d_dnssecQueries))->
+ bind("auth", (nt.second || !d_dnssecQueries))->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to feed empty non-terminal with name '" + nt.first.toLogString() + "': "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_InsertEmptyNonTerminalOrderQuery_stmt->
- bind("domain_id",domain_id)->
+ bind("domain_id", domain_id)->
bind("qname", nt.first);
+ // clang-format on
if (narrow || !nt.second) {
+ // clang-format off
d_InsertEmptyNonTerminalOrderQuery_stmt->
bindNull("ordername");
+ // clang-format on
} else {
ordername=toBase32Hex(hashQNameWithSalt(ns3prc, nt.first));
+ // clang-format off
d_InsertEmptyNonTerminalOrderQuery_stmt->
bind("ordername", ordername);
+ // clang-format on
}
+ // clang-format off
d_InsertEmptyNonTerminalOrderQuery_stmt->
- bind("auth",nt.second)->
+ bind("auth", nt.second)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to feed empty non-terminal with name '" + nt.first.toLogString() + "' (hashed name '"+ toBase32Hex(hashQNameWithSalt(ns3prc, nt.first)) + "') : "+e.txtReason());
d_db->startTransaction();
d_inTransaction = true;
if(domain_id >= 0) {
+ // clang-format off
d_DeleteZoneQuery_stmt->
bind("domain_id", domain_id)->
execute()->
reset();
+ // clang-format on
}
}
catch (SSqlException &e) {
d_query_name = "list-comments-query";
d_query_stmt = &d_ListCommentsQuery_stmt;
+ // clang-format off
(*d_query_stmt)->
bind("domain_id", domain_id)->
execute();
+ // clang-format on
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to list comments for domain id " + std::to_string(domain_id) + ": "+e.txtReason());
try {
reconnectIfNeeded();
+ // clang-format off
d_InsertCommentQuery_stmt->
- bind("domain_id",comment.domain_id)->
- bind("qname",comment.qname)->
- bind("qtype",comment.qtype.toString())->
- bind("modified_at",comment.modified_at)->
- bind("account",comment.account)->
- bind("content",comment.content)->
+ bind("domain_id", comment.domain_id)->
+ bind("qname", comment.qname)->
+ bind("qtype", comment.qtype.toString())->
+ bind("modified_at", comment.modified_at)->
+ bind("account", comment.account)->
+ bind("content", comment.content)->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to feed comment for RRSet '" + comment.qname.toLogString() + "|" + comment.qtype.toString() + "': "+e.txtReason());
throw PDNSException("replaceComments called outside of transaction");
}
+ // clang-format off
d_DeleteCommentRRsetQuery_stmt->
- bind("domain_id",domain_id)->
+ bind("domain_id", domain_id)->
bind("qname", qname)->
- bind("qtype",qt.toString())->
+ bind("qtype", qt.toString())->
execute()->
reset();
+ // clang-format on
}
catch (SSqlException &e) {
throw PDNSException("GSQLBackend unable to delete comment for RRSet '" + qname.toLogString() + "|" + qt.toString() + "': "+e.txtReason());
return escaped_pattern;
}
-bool GSQLBackend::searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result)
+bool GSQLBackend::searchRecords(const string &pattern, size_t maxResults, vector<DNSResourceRecord>& result)
{
d_qname.clear();
string escaped_pattern = pattern2SQLPattern(pattern);
try {
reconnectIfNeeded();
+ // clang-format off
d_SearchRecordsQuery_stmt->
bind("value", escaped_pattern)->
bind("value2", escaped_pattern)->
bind("limit", maxResults)->
execute();
+ // clang-format on
while(d_SearchRecordsQuery_stmt->hasNextRow())
{
}
}
-bool GSQLBackend::searchComments(const string &pattern, int maxResults, vector<Comment>& result)
+bool GSQLBackend::searchComments(const string &pattern, size_t maxResults, vector<Comment>& result)
{
Comment c;
string escaped_pattern = pattern2SQLPattern(pattern);
try {
reconnectIfNeeded();
+ // clang-format off
d_SearchCommentsQuery_stmt->
bind("value", escaped_pattern)->
bind("value2", escaped_pattern)->
bind("limit", maxResults)->
execute();
+ // clang-format on
while(d_SearchCommentsQuery_stmt->hasNextRow()) {
SSqlStatement::row_t row;
bool isDnssecDomainMetadata (const string& name);
-/*
+/*
GSQLBackend is a generic backend used by other sql backends
*/
class GSQLBackend : public DNSBackend
freeStatements();
d_db.reset();
}
-
+
void setDB(SSql *db)
{
freeStatements();
d_ANYIdQuery_stmt = d_db->prepare(d_ANYIdQuery, 2);
d_listQuery_stmt = d_db->prepare(d_listQuery, 2);
d_listSubZoneQuery_stmt = d_db->prepare(d_listSubZoneQuery, 3);
- d_MasterOfDomainsZoneQuery_stmt = d_db->prepare(d_MasterOfDomainsZoneQuery, 1);
+ d_PrimaryOfDomainsZoneQuery_stmt = d_db->prepare(d_PrimaryOfDomainsZoneQuery, 1);
d_InfoOfDomainsZoneQuery_stmt = d_db->prepare(d_InfoOfDomainsZoneQuery, 1);
- d_InfoOfAllSlaveDomainsQuery_stmt = d_db->prepare(d_InfoOfAllSlaveDomainsQuery, 0);
- d_SuperMasterInfoQuery_stmt = d_db->prepare(d_SuperMasterInfoQuery, 2);
- d_GetSuperMasterIPs_stmt = d_db->prepare(d_GetSuperMasterIPs, 2);
- d_AddSuperMaster_stmt = d_db->prepare(d_AddSuperMaster, 3);
+ d_InfoOfAllSecondaryDomainsQuery_stmt = d_db->prepare(d_InfoOfAllSecondaryDomainsQuery, 0);
+ d_AutoPrimaryInfoQuery_stmt = d_db->prepare(d_AutoPrimaryInfoQuery, 2);
+ d_GetAutoPrimaryIPs_stmt = d_db->prepare(d_GetAutoPrimaryIPs, 2);
+ d_AddAutoPrimary_stmt = d_db->prepare(d_AddAutoPrimary, 3);
d_RemoveAutoPrimary_stmt = d_db->prepare(d_RemoveAutoPrimaryQuery, 2);
d_ListAutoPrimaries_stmt = d_db->prepare(d_ListAutoPrimariesQuery, 0);
d_InsertZoneQuery_stmt = d_db->prepare(d_InsertZoneQuery, 4);
d_InsertRecordQuery_stmt = d_db->prepare(d_InsertRecordQuery, 9);
d_InsertEmptyNonTerminalOrderQuery_stmt = d_db->prepare(d_InsertEmptyNonTerminalOrderQuery, 4);
- d_UpdateMasterOfZoneQuery_stmt = d_db->prepare(d_UpdateMasterOfZoneQuery, 2);
+ d_UpdatePrimaryOfZoneQuery_stmt = d_db->prepare(d_UpdatePrimaryOfZoneQuery, 2);
d_UpdateKindOfZoneQuery_stmt = d_db->prepare(d_UpdateKindOfZoneQuery, 2);
d_UpdateOptionsOfZoneQuery_stmt = d_db->prepare(d_UpdateOptionsOfZoneQuery, 2);
d_UpdateCatalogOfZoneQuery_stmt = d_db->prepare(d_UpdateCatalogOfZoneQuery, 2);
d_UpdateAccountOfZoneQuery_stmt = d_db->prepare(d_UpdateAccountOfZoneQuery, 2);
d_UpdateSerialOfZoneQuery_stmt = d_db->prepare(d_UpdateSerialOfZoneQuery, 2);
d_UpdateLastCheckOfZoneQuery_stmt = d_db->prepare(d_UpdateLastCheckOfZoneQuery, 2);
- d_InfoOfAllMasterDomainsQuery_stmt = d_db->prepare(d_InfoOfAllMasterDomainsQuery, 0);
+ d_InfoOfAllPrimaryDomainsQuery_stmt = d_db->prepare(d_InfoOfAllPrimaryDomainsQuery, 0);
d_InfoProducerMembersQuery_stmt = d_db->prepare(d_InfoProducerMembersQuery, 1);
d_InfoConsumerMembersQuery_stmt = d_db->prepare(d_InfoConsumerMembersQuery, 1);
d_DeleteDomainQuery_stmt = d_db->prepare(d_DeleteDomainQuery, 1);
d_ANYIdQuery_stmt.reset();
d_listQuery_stmt.reset();
d_listSubZoneQuery_stmt.reset();
- d_MasterOfDomainsZoneQuery_stmt.reset();
+ d_PrimaryOfDomainsZoneQuery_stmt.reset();
d_InfoOfDomainsZoneQuery_stmt.reset();
- d_InfoOfAllSlaveDomainsQuery_stmt.reset();
- d_SuperMasterInfoQuery_stmt.reset();
- d_GetSuperMasterIPs_stmt.reset();
- d_AddSuperMaster_stmt.reset();
+ d_InfoOfAllSecondaryDomainsQuery_stmt.reset();
+ d_AutoPrimaryInfoQuery_stmt.reset();
+ d_GetAutoPrimaryIPs_stmt.reset();
+ d_AddAutoPrimary_stmt.reset();
d_RemoveAutoPrimary_stmt.reset();
d_ListAutoPrimaries_stmt.reset();
d_InsertZoneQuery_stmt.reset();
d_InsertRecordQuery_stmt.reset();
d_InsertEmptyNonTerminalOrderQuery_stmt.reset();
- d_UpdateMasterOfZoneQuery_stmt.reset();
+ d_UpdatePrimaryOfZoneQuery_stmt.reset();
d_UpdateKindOfZoneQuery_stmt.reset();
d_UpdateOptionsOfZoneQuery_stmt.reset();
d_UpdateCatalogOfZoneQuery_stmt.reset();
d_UpdateAccountOfZoneQuery_stmt.reset();
d_UpdateSerialOfZoneQuery_stmt.reset();
d_UpdateLastCheckOfZoneQuery_stmt.reset();
- d_InfoOfAllMasterDomainsQuery_stmt.reset();
+ d_InfoOfAllPrimaryDomainsQuery_stmt.reset();
d_InfoProducerMembersQuery_stmt.reset();
d_InfoConsumerMembersQuery_stmt.reset();
d_DeleteDomainQuery_stmt.reset();
bool feedRecord(const DNSResourceRecord &r, const DNSName &ordername, bool ordernameIsNSEC3=false) override;
bool feedEnts(int domain_id, map<DNSName,bool>& nonterm) override;
bool feedEnts3(int domain_id, const DNSName &domain, map<DNSName,bool> &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) override;
- bool createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& masters, const string& account) override;
- bool createSlaveDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account) override;
+ bool createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& primaries, const string& account) override;
+ bool createSecondaryDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account) override;
bool deleteDomain(const DNSName &domain) override;
- bool superMasterAdd(const AutoPrimary& primary) override;
+ bool autoPrimaryAdd(const AutoPrimary& primary) override;
bool autoPrimaryRemove(const AutoPrimary& primary) override;
bool autoPrimariesList(std::vector<AutoPrimary>& primaries) override;
- bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db) override;
+ bool autoPrimaryBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** db) override;
void setStale(uint32_t domain_id) override;
void setFresh(uint32_t domain_id) override;
- void getUnfreshSlaveInfos(vector<DomainInfo> *domains) override;
- void getUpdatedMasters(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
+ void getUnfreshSecondaryInfos(vector<DomainInfo>* domains) override;
+ void getUpdatedPrimaries(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
bool getCatalogMembers(const DNSName& catalog, vector<CatalogInfo>& members, CatalogInfo::CatalogType type) override;
bool getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial=true) override;
void setNotified(uint32_t domain_id, uint32_t serial) override;
- bool setMasters(const DNSName &domain, const vector<ComboAddress> &masters) override;
+ bool setPrimaries(const DNSName& domain, const vector<ComboAddress>& primaries) override;
bool setKind(const DNSName &domain, const DomainInfo::DomainKind kind) override;
bool setOptions(const DNSName& domain, const string& options) override;
bool setCatalog(const DNSName& domain, const DNSName& catalog) override;
bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta) override;
bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override;
bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) override;
-
+
bool removeDomainKey(const DNSName& name, unsigned int id) override;
bool activateDomainKey(const DNSName& name, unsigned int id) override;
bool deactivateDomainKey(const DNSName& name, unsigned int id) override;
bool feedComment(const Comment& comment) override;
bool replaceComments(const uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<Comment>& comments) override;
string directBackendCmd(const string &query) override;
- bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result) override;
- bool searchComments(const string &pattern, int maxResults, vector<Comment>& result) override;
+ bool searchRecords(const string &pattern, size_t maxResults, vector<DNSResourceRecord>& result) override;
+ bool searchComments(const string &pattern, size_t maxResults, vector<Comment>& result) override;
protected:
string pattern2SQLPattern(const string& pattern);
string d_listSubZoneQuery;
string d_logprefix;
- string d_MasterOfDomainsZoneQuery;
+ string d_PrimaryOfDomainsZoneQuery;
string d_InfoOfDomainsZoneQuery;
- string d_InfoOfAllSlaveDomainsQuery;
- string d_SuperMasterInfoQuery;
- string d_GetSuperMasterName;
- string d_GetSuperMasterIPs;
- string d_AddSuperMaster;
+ string d_InfoOfAllSecondaryDomainsQuery;
+ string d_AutoPrimaryInfoQuery;
+ string d_GetAutoPrimaryName;
+ string d_GetAutoPrimaryIPs;
+ string d_AddAutoPrimary;
string d_RemoveAutoPrimaryQuery;
string d_ListAutoPrimariesQuery;
string d_InsertZoneQuery;
string d_InsertRecordQuery;
string d_InsertEmptyNonTerminalOrderQuery;
- string d_UpdateMasterOfZoneQuery;
+ string d_UpdatePrimaryOfZoneQuery;
string d_UpdateKindOfZoneQuery;
string d_UpdateOptionsOfZoneQuery;
string d_UpdateCatalogOfZoneQuery;
string d_UpdateAccountOfZoneQuery;
string d_UpdateSerialOfZoneQuery;
string d_UpdateLastCheckOfZoneQuery;
- string d_InfoOfAllMasterDomainsQuery;
+ string d_InfoOfAllPrimaryDomainsQuery;
string d_InfoProducerMembersQuery;
string d_InfoConsumerMembersQuery;
string d_DeleteDomainQuery;
unique_ptr<SSqlStatement> d_ANYIdQuery_stmt;
unique_ptr<SSqlStatement> d_listQuery_stmt;
unique_ptr<SSqlStatement> d_listSubZoneQuery_stmt;
- unique_ptr<SSqlStatement> d_MasterOfDomainsZoneQuery_stmt;
+ unique_ptr<SSqlStatement> d_PrimaryOfDomainsZoneQuery_stmt;
unique_ptr<SSqlStatement> d_InfoOfDomainsZoneQuery_stmt;
- unique_ptr<SSqlStatement> d_InfoOfAllSlaveDomainsQuery_stmt;
- unique_ptr<SSqlStatement> d_SuperMasterInfoQuery_stmt;
- unique_ptr<SSqlStatement> d_GetSuperMasterIPs_stmt;
- unique_ptr<SSqlStatement> d_AddSuperMaster_stmt;
+ unique_ptr<SSqlStatement> d_InfoOfAllSecondaryDomainsQuery_stmt;
+ unique_ptr<SSqlStatement> d_AutoPrimaryInfoQuery_stmt;
+ unique_ptr<SSqlStatement> d_GetAutoPrimaryIPs_stmt;
+ unique_ptr<SSqlStatement> d_AddAutoPrimary_stmt;
unique_ptr<SSqlStatement> d_RemoveAutoPrimary_stmt;
unique_ptr<SSqlStatement> d_ListAutoPrimaries_stmt;
unique_ptr<SSqlStatement> d_InsertZoneQuery_stmt;
unique_ptr<SSqlStatement> d_InsertRecordQuery_stmt;
unique_ptr<SSqlStatement> d_InsertEmptyNonTerminalOrderQuery_stmt;
- unique_ptr<SSqlStatement> d_UpdateMasterOfZoneQuery_stmt;
+ unique_ptr<SSqlStatement> d_UpdatePrimaryOfZoneQuery_stmt;
unique_ptr<SSqlStatement> d_UpdateKindOfZoneQuery_stmt;
unique_ptr<SSqlStatement> d_UpdateOptionsOfZoneQuery_stmt;
unique_ptr<SSqlStatement> d_UpdateCatalogOfZoneQuery_stmt;
unique_ptr<SSqlStatement> d_UpdateAccountOfZoneQuery_stmt;
unique_ptr<SSqlStatement> d_UpdateSerialOfZoneQuery_stmt;
unique_ptr<SSqlStatement> d_UpdateLastCheckOfZoneQuery_stmt;
- unique_ptr<SSqlStatement> d_InfoOfAllMasterDomainsQuery_stmt;
+ unique_ptr<SSqlStatement> d_InfoOfAllPrimaryDomainsQuery_stmt;
unique_ptr<SSqlStatement> d_InfoProducerMembersQuery_stmt;
unique_ptr<SSqlStatement> d_InfoConsumerMembersQuery_stmt;
unique_ptr<SSqlStatement> d_DeleteDomainQuery_stmt;
primary: AWORD
{
- s_di.masters.push_back(ComboAddress($1, 53));
+ s_di.primaries.push_back(ComboAddress($1, 53));
free($1);
}
;
{
name=DNSName();
filename=type="";
- masters.clear();
+ primaries.clear();
alsoNotify.clear();
d_dev=0;
d_ino=0;
DNSName name;
string viewName;
string filename;
- vector<ComboAddress> masters;
+ vector<ComboAddress> primaries;
set<string> alsoNotify;
string type;
bool hadFileDirective;
return totErased;
}
-template <typename S, typename C, typename T>
-uint64_t pruneMutexCollectionsVector(time_t now, C& container, std::vector<T>& maps, uint64_t maxCached, uint64_t cacheSize)
+template <typename S, typename T>
+uint64_t pruneMutexCollectionsVector(time_t now, std::vector<T>& maps, uint64_t maxCached, uint64_t cacheSize)
{
uint64_t totErased = 0;
uint64_t toTrim = 0;
uint64_t lookedAt = 0;
for (auto i = sidx.begin(); i != sidx.end(); lookedAt++) {
if (i->isStale(now)) {
- container.preRemoval(*shard, *i);
+ shard->preRemoval(*i);
i = sidx.erase(i);
erased++;
content.decEntriesCount();
auto& sidx = boost::multi_index::get<S>(shard->d_map);
size_t removed = 0;
for (auto i = sidx.begin(); i != sidx.end() && removed < toTrimForThisShard; removed++) {
- container.preRemoval(*shard, *i);
+ shard->preRemoval(*i);
i = sidx.erase(i);
content.decEntriesCount();
++totErased;
data->d_sorthelper = 0;
}
}
- suck(sr.domain, sr.master, sr.force);
+ suck(sr.domain, sr.primary, sr.force);
}
}
makeNotifySockets();
for(;;) {
- slaveRefresh(&P);
- masterUpdateCheck(&P);
+ secondaryRefresh(&P);
+ primaryUpdateCheck(&P);
doNotifications(&P); // this processes any notification acknowledgements and actually send out our own notifications
next = time(nullptr) + d_tickinterval;
rc=d_any_sem.tryWait();
if(rc) {
- bool extraSlaveRefresh = false;
+ bool extraSecondaryRefresh = false;
Utility::sleep(1);
{
auto data = d_data.lock();
if (data->d_tocheck.size()) {
- extraSlaveRefresh = true;
+ extraSecondaryRefresh = true;
}
}
- if (extraSlaveRefresh)
- slaveRefresh(&P);
+ if (extraSecondaryRefresh)
+ secondaryRefresh(&P);
}
else {
// eat up extra posts to avoid busy looping if many posts were done
struct SuckRequest
{
DNSName domain;
- ComboAddress master;
+ ComboAddress primary;
bool force;
enum RequestPriority : uint8_t { PdnsControl, Api, Notify, SerialRefresh, SignaturesRefresh };
std::pair<RequestPriority, uint64_t> priorityAndOrder;
bool operator<(const SuckRequest& b) const
{
- return std::tie(domain, master) < std::tie(b.domain, b.master);
+ return std::tie(domain, primary) < std::tie(b.domain, b.primary);
}
};
CommunicatorClass()
{
d_tickinterval=60;
- d_slaveschanged = true;
+ d_secondarieschanged = true;
d_nsock4 = -1;
d_nsock6 = -1;
d_preventSelfNotification = false;
void drillHole(const DNSName &domain, const string &ip);
bool justNotified(const DNSName &domain, const string &ip);
- void addSuckRequest(const DNSName &domain, const ComboAddress& master, SuckRequest::RequestPriority, bool force=false);
- void addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote);
- void addTrySuperMasterRequest(const DNSPacket& p);
+ void addSuckRequest(const DNSName& domain, const ComboAddress& primary, SuckRequest::RequestPriority, bool force = false);
+ void addSecondaryCheckRequest(const DomainInfo& di, const ComboAddress& remote);
+ void addTryAutoPrimaryRequest(const DNSPacket& p);
void notify(const DNSName &domain, const string &ip);
void mainloop();
void retrievalLoopThread();
void suck(const DNSName &domain, const ComboAddress& remote, bool force=false);
void ixfrSuck(const DNSName& domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, ZoneStatus& zs, vector<DNSRecord>* axfr);
- void slaveRefresh(PacketHandler *P);
- void masterUpdateCheck(PacketHandler *P);
+ void secondaryRefresh(PacketHandler* P);
+ void primaryUpdateCheck(PacketHandler* P);
void getUpdatedProducers(UeberBackend* B, vector<DomainInfo>& domains, const std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes);
Semaphore d_suck_sem;
NotificationQueue d_nq;
time_t d_tickinterval;
- bool d_slaveschanged;
+ bool d_secondarieschanged;
bool d_preventSelfNotification;
struct Data
};
};
- std::set<DNSPacket, cmp> d_potentialsupermasters;
+ std::set<DNSPacket, cmp> d_potentialautoprimaries;
// Used to keep some state on domains that failed their freshness checks.
// uint64_t == counter of the number of failures (increased by 1 every consecutive slave-cycle-interval that the domain fails)
// time_t == wait at least until this time before attempting a new check
- map<DNSName, pair<uint64_t, time_t> > d_failedSlaveRefresh;
+ map<DNSName, pair<uint64_t, time_t>> d_failedSecondaryRefresh;
};
LockGuarded<Data> d_data;
return false;
}
-bool DNSSECKeeper::getTSIGForAccess(const DNSName& zone, const ComboAddress& /* master */, DNSName* keyname)
+bool DNSSECKeeper::getTSIGForAccess(const DNSName& zone, const ComboAddress& /* primary */, DNSName* keyname)
{
vector<string> keynames;
d_keymetadb->getDomainMetadata(zone, "AXFR-MASTER-TSIG", keynames);
keyname->trimToLabels(0);
- // XXX FIXME this should check for a specific master!
+ // XXX FIXME this should check for a specific primary!
for(const string& dbkey : keynames) {
*keyname=DNSName(dbkey);
return true;
class Opcode
{
public:
- enum { Query=0, IQuery=1, Status=2, Notify=4, Update=5 };
+ enum opcodes_ : uint8_t { Query=0, IQuery=1, Status=2, Notify=4, Update=5 };
static std::string to_s(uint8_t opcode);
};
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <memory>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
void BackendMakerClass::load_all()
{
// TODO: Implement this?
- DIR *dir=opendir(arg()["module-dir"].c_str());
- if(!dir) {
+ auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(arg()["module-dir"].c_str()), closedir);
+ if (!dir) {
g_log<<Logger::Error<<"Unable to open module directory '"<<arg()["module-dir"]<<"'"<<endl;
return;
}
- struct dirent *entry;
- while((entry=readdir(dir))) {
- if(!strncmp(entry->d_name,"lib",3) &&
- strlen(entry->d_name)>13 &&
- !strcmp(entry->d_name+strlen(entry->d_name)-10,"backend.so"))
+ struct dirent* entry = nullptr;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
+ while ((entry = readdir(dir.get())) != nullptr) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
+ auto name = std::string_view(entry->d_name, strlen(entry->d_name));
+ if (boost::starts_with(name, "lib") &&
+ name.size() > 13 &&
+ boost::ends_with(name, "backend.so")) {
load(entry->d_name);
+ }
}
- closedir(dir);
}
void BackendMakerClass::load(const string &module)
return d_instances.size();
}
-vector<DNSBackend *> BackendMakerClass::all(bool metadataOnly)
+vector<std::unique_ptr<DNSBackend>> BackendMakerClass::all(bool metadataOnly)
{
- vector<DNSBackend *> ret;
- if(d_instances.empty())
+ if(d_instances.empty()) {
throw PDNSException("No database backends configured for launch, unable to function");
+ }
+ vector<unique_ptr<DNSBackend>> ret;
ret.reserve(d_instances.size());
std::string current; // to make the exception text more useful
try {
for (const auto& instance : d_instances) {
current = instance.first + instance.second;
- DNSBackend *made = nullptr;
-
- if (metadataOnly) {
- made = d_repository[instance.first]->makeMetadataOnly(instance.second);
- }
- else {
- made = d_repository[instance.first]->make(instance.second);
- }
-
- if (!made) {
+ auto* repo = d_repository[instance.first];
+ std::unique_ptr<DNSBackend> made{metadataOnly ? repo->makeMetadataOnly(instance.second) : repo->make(instance.second)};
+ if (made == nullptr) {
throw PDNSException("Unable to launch backend '" + instance.first + "'");
}
-
- ret.push_back(made);
+ ret.push_back(std::move(made));
}
}
catch(const PDNSException &ae) {
- g_log<<Logger::Error<<"Caught an exception instantiating a backend (" << current << "): "<<ae.reason<<endl;
- g_log<<Logger::Error<<"Cleaning up"<<endl;
- for (auto i : ret) {
- delete i;
- }
+ g_log << Logger::Error << "Caught an exception instantiating a backend (" << current << "): " << ae.reason << endl;
+ g_log << Logger::Error << "Cleaning up" << endl;
+ ret.clear();
throw;
} catch(...) {
// and cleanup
- g_log<<Logger::Error<<"Caught an exception instantiating a backend (" << current <<"), cleaning up"<<endl;
- for (auto i : ret) {
- delete i;
- }
+ g_log << Logger::Error << "Caught an exception instantiating a backend (" << current << "), cleaning up" << endl;
+ ret.clear();
throw;
}
auto src=getRR<SOARecordContent>(in.dr);
sd.nameserver = src->d_mname;
- sd.hostmaster = src->d_rname;
+ sd.rname = src->d_rname;
sd.serial = src->d_st.serial;
sd.refresh = src->d_st.refresh;
sd.retry = src->d_st.retry;
st.retry = sd.retry;
st.expire = sd.expire;
st.minimum = sd.minimum;
- return std::make_shared<SOARecordContent>(sd.nameserver, sd.hostmaster, st);
+ return std::make_shared<SOARecordContent>(sd.nameserver, sd.rname, st);
}
void fillSOAData(const string &content, SOAData &data)
try {
data.nameserver = DNSName(parts.at(0));
- data.hostmaster = DNSName(parts.at(1));
+ data.rname = DNSName(parts.at(1));
pdns::checked_stoi_into(data.serial, parts.at(2));
pdns::checked_stoi_into(data.refresh, parts.at(3));
pdns::checked_stoi_into(data.retry, parts.at(4));
#pragma once
#include <algorithm>
+#include <cstddef>
class DNSPacket;
#include "utility.hh"
time_t last_check{};
string options;
string account;
- vector<ComboAddress> masters;
+ vector<ComboAddress> primaries;
DNSBackend *backend{};
uint32_t id{};
// Do not reorder (lmdbbackend)!!! One exception 'All' is always last.
enum DomainKind : uint8_t
{
- Master,
- Slave,
+ Primary,
+ Secondary,
Native,
Producer,
Consumer,
static DomainKind stringToKind(const string& kind)
{
if (pdns_iequals(kind, "SECONDARY") || pdns_iequals(kind, "SLAVE")) {
- return DomainInfo::Slave;
+ return DomainInfo::Secondary;
}
if (pdns_iequals(kind, "PRIMARY") || pdns_iequals(kind, "MASTER")) {
- return DomainInfo::Master;
+ return DomainInfo::Primary;
}
if (pdns_iequals(kind, "PRODUCER")) {
return DomainInfo::Producer;
return DomainInfo::Native;
}
- [[nodiscard]] bool isPrimaryType() const { return (kind == DomainInfo::Master || kind == DomainInfo::Producer); }
- [[nodiscard]] bool isSecondaryType() const { return (kind == DomainInfo::Slave || kind == DomainInfo::Consumer); }
+ [[nodiscard]] bool isPrimaryType() const { return (kind == DomainInfo::Primary || kind == DomainInfo::Producer); }
+ [[nodiscard]] bool isSecondaryType() const { return (kind == DomainInfo::Secondary || kind == DomainInfo::Consumer); }
[[nodiscard]] bool isCatalogType() const { return (kind == DomainInfo::Producer || kind == DomainInfo::Consumer); }
- [[nodiscard]] bool isMaster(const ComboAddress& ipAddress) const
+ [[nodiscard]] bool isPrimary(const ComboAddress& ipAddress) const
{
- return std::any_of(masters.begin(), masters.end(), [ipAddress](auto master) { return ComboAddress::addressOnlyEqual()(ipAddress, master); });
+ return std::any_of(primaries.begin(), primaries.end(), [ipAddress](auto primary) { return ComboAddress::addressOnlyEqual()(ipAddress, primary); });
}
};
return false;
}
- //! returns true if master ip is master for domain name.
+ //! returns true if primary ip is primary for domain name.
//! starts the transaction for updating domain qname (FIXME: what is id?)
virtual bool startTransaction(const DNSName& /* qname */, int /* id */ = -1)
{
{
return false;
}
- //! slave capable backends should return a list of slaves that should be rechecked for staleness
- virtual void getUnfreshSlaveInfos(vector<DomainInfo>* /* domains */)
+ //! secondary capable backends should return a list of secondaries that should be rechecked for staleness
+ virtual void getUnfreshSecondaryInfos(vector<DomainInfo>* /* domains */)
{
}
ips->insert(meta.begin(), meta.end());
}
- //! get list of domains that have been changed since their last notification to slaves
- virtual void getUpdatedMasters(vector<DomainInfo>& /* domains */, std::unordered_set<DNSName>& /* catalogs */, CatalogHashMap& /* catalogHashes */)
+ //! get list of domains that have been changed since their last notification to secondaries
+ virtual void getUpdatedPrimaries(vector<DomainInfo>& /* domains */, std::unordered_set<DNSName>& /* catalogs */, CatalogHashMap& /* catalogHashes */)
{
}
{
}
- //! Called by PowerDNS to inform a backend that the changes in the domain have been reported to slaves
+ //! Called by PowerDNS to inform a backend that the changes in the domain have been reported to secondaries
virtual void setNotified(uint32_t /* id */, uint32_t /* serial */)
{
}
- //! Called when the Master list of a domain should be changed
- virtual bool setMasters(const DNSName& /* domain */, const vector<ComboAddress>& /* masters */)
+ //! Called when the Primary list of a domain should be changed
+ virtual bool setPrimaries(const DNSName& /* domain */, const vector<ComboAddress>& /* primaries */)
{
return false;
}
- //! Called when the Kind of a domain should be changed (master -> native and similar)
+ //! Called when the Kind of a domain should be changed (primary -> native and similar)
virtual bool setKind(const DNSName& /* domain */, const DomainInfo::DomainKind /* kind */)
{
return false;
//! Can be called to seed the getArg() function with a prefix
void setArgPrefix(const string &prefix);
- //! Add an entry for a super master
- virtual bool superMasterAdd(const struct AutoPrimary& /* primary */)
+ //! Add an entry for a super primary
+ virtual bool autoPrimaryAdd(const struct AutoPrimary& /* primary */)
{
return false;
}
- //! Remove an entry for a super master
+ //! Remove an entry for a super primary
virtual bool autoPrimaryRemove(const struct AutoPrimary& /* primary */)
{
return false;
}
- //! List all SuperMasters, returns false if feature not supported.
+ //! List all AutoPrimaries, returns false if feature not supported.
virtual bool autoPrimariesList(std::vector<AutoPrimary>& /* primaries */)
{
return false;
}
- //! determine if ip is a supermaster or a domain
- virtual bool superMasterBackend(const string& /* ip */, const DNSName& /* domain */, const vector<DNSResourceRecord>& /* nsset */, string* /* nameserver */, string* /* account */, DNSBackend** /* db */)
+ //! determine if ip is a autoprimary or a domain
+ virtual bool autoPrimaryBackend(const string& /* ip */, const DNSName& /* domain */, const vector<DNSResourceRecord>& /* nsset */, string* /* nameserver */, string* /* account */, DNSBackend** /* db */)
{
return false;
}
//! called by PowerDNS to create a new domain
- virtual bool createDomain(const DNSName& /* domain */, const DomainInfo::DomainKind /* kind */, const vector<ComboAddress>& /* masters */, const string& /* account */)
+ virtual bool createDomain(const DNSName& /* domain */, const DomainInfo::DomainKind /* kind */, const vector<ComboAddress>& /* primaries */, const string& /* account */)
{
return false;
}
- //! called by PowerDNS to create a slave record for a superMaster
- virtual bool createSlaveDomain(const string& /* ip */, const DNSName& /* domain */, const string& /* nameserver */, const string& /* account */)
+ //! called by PowerDNS to create a secondary record for a autoPrimary
+ virtual bool createSecondaryDomain(const string& /* ip */, const DNSName& /* domain */, const string& /* nameserver */, const string& /* account */)
{
return false;
}
}
//! Search for records, returns true if search was done successfully.
- virtual bool searchRecords(const string& /* pattern */, int /* maxResults */, vector<DNSResourceRecord>& /* result */)
+ virtual bool searchRecords(const string& /* pattern */, size_t /* maxResults */, vector<DNSResourceRecord>& /* result */)
{
return false;
}
//! Search for comments, returns true if search was done successfully.
- virtual bool searchComments(const string& /* pattern */, int /* maxResults */, vector<Comment>& /* result */)
+ virtual bool searchComments(const string& /* pattern */, size_t /* maxResults */, vector<Comment>& /* result */)
{
return false;
}
public:
void report(BackendFactory *bf);
void launch(const string &instr);
- vector<DNSBackend *> all(bool skipBIND=false);
+ vector<std::unique_ptr<DNSBackend>> all(bool metadataOnly=false);
void load(const string &module);
[[nodiscard]] size_t numLauncheable() const;
vector<string> getModules();
DNSName qname;
DNSName nameserver;
- DNSName hostmaster;
+ DNSName rname;
uint32_t ttl{};
uint32_t serial{};
uint32_t refresh{};
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
#include <boost/accumulators/accumulators.hpp>
#include <boost/array.hpp>
#include <boost/accumulators/statistics.hpp>
+#pragma GCC diagnostic pop
#include <boost/program_options.hpp>
#include "inflighter.cc"
#include <deque>
return false;
}
- const struct dnsheader * dh = reinterpret_cast<const struct dnsheader *>(packet.data());
- if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || dh->opcode != Opcode::Query)
+ const dnsheader_aligned dh(packet.data());
+ if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || static_cast<uint8_t>(dh->opcode) != Opcode::Query) {
return false;
+ }
unsigned int qnameWireLength;
uint16_t qtype, qclass;
}
/* check for collision */
- if (!cachedValueMatches(value, *(getFlagsFromDNSHeader(dq.getHeader())), dq.ids.qname, dq.ids.qtype, dq.ids.qclass, receivedOverUDP, dnssecOK, subnet)) {
+ if (!cachedValueMatches(value, *(getFlagsFromDNSHeader(dq.getHeader().get())), dq.ids.qname, dq.ids.qtype, dq.ids.qclass, receivedOverUDP, dnssecOK, subnet)) {
++d_lookupCollisions;
return false;
}
{ "SetECSPrefixLengthAction", true, "v4, v6", "Set the ECS prefix length. Subsequent rules are processed after this action" },
{ "SetMacAddrAction", true, "option", "Add the source MAC address to the query as EDNS0 option option. This action is currently only supported on Linux. Subsequent rules are processed after this action" },
{ "SetEDNSOptionAction", true, "option, data", "Add arbitrary EDNS option and data to the query. Subsequent rules are processed after this action" },
+ { "SetExtendedDNSErrorAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be added to the response corresponding to the current query. Subsequent rules are processed after this action" },
+ { "SetExtendedDNSErrorResponseAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be added to this response. Subsequent rules are processed after this action" },
{ "SetNoRecurseAction", true, "", "strip RD bit from the question, let it go through" },
{ "setOutgoingDoHWorkerThreads", true, "n", "Number of outgoing DoH worker threads" },
{ "SetProxyProtocolValuesAction", true, "values", "Set the Proxy-Protocol values for this queries to 'values'" },
d_excludedSubnets.addMasks(group, false);
}
+ void removeRange(const Netmask& range)
+ {
+ d_excludedSubnets.deleteMask(range);
+ }
+
+ void removeRange(const NetmaskGroup& group)
+ {
+ d_excludedSubnets.deleteMasks(group);
+ }
+
void excludeDomain(const DNSName& domain)
{
d_excludedDomains.add(domain);
*/
#include "dolog.hh"
#include "dnsdist.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-ecs.hh"
#include "dnsparser.hh"
#include "dnswriter.hh"
int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent)
{
assert(initialPacket.size() >= sizeof(dnsheader));
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
+ const dnsheader_aligned dh(initialPacket.data());
- if (ntohs(dh->arcount) == 0)
+ if (ntohs(dh->arcount) == 0) {
return ENOENT;
+ }
- if (ntohs(dh->qdcount) == 0)
+ if (ntohs(dh->qdcount) == 0) {
return ENOENT;
+ }
PacketReader pr(std::string_view(reinterpret_cast<const char*>(initialPacket.data()), initialPacket.size()));
bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, const string& newOptionContent)
{
assert(initialPacket.size() >= sizeof(dnsheader));
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
+ const dnsheader_aligned dh(initialPacket.data());
if (ntohs(dh->qdcount) == 0) {
return false;
return false;
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
if (ntohs(dh->qdcount) == 0) {
return false;
assert(optStart != NULL);
assert(optLen != NULL);
assert(last != NULL);
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
- if (ntohs(dh->arcount) == 0)
+ if (ntohs(dh->arcount) == 0) {
return ENOENT;
+ }
PacketReader pr(std::string_view(reinterpret_cast<const char*>(packet.data()), packet.size()));
{
assert(optRDPosition != nullptr);
assert(remaining != nullptr);
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
if (offset >= packet.size()) {
return ENOENT;
}
- if (ntohs(dh->qdcount) != 1 || ntohs(dh->ancount) != 0 || ntohs(dh->arcount) != 1 || ntohs(dh->nscount) != 0)
+ if (ntohs(dh->qdcount) != 1 || ntohs(dh->ancount) != 0 || ntohs(dh->arcount) != 1 || ntohs(dh->nscount) != 0) {
return ENOENT;
+ }
size_t pos = sizeof(dnsheader) + offset;
pos += DNS_TYPE_SIZE + DNS_CLASS_SIZE;
return false;
}
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet.data());
- uint16_t arcount = ntohs(dh->arcount);
- arcount++;
- dh->arcount = htons(arcount);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [](dnsheader& header) {
+ uint16_t arcount = ntohs(header.arcount);
+ arcount++;
+ header.arcount = htons(arcount);
+ return true;
+ });
ednsAdded = true;
ecsAdded = true;
{
assert(qnameWireLength <= packet.size());
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
if (ntohs(dh->ancount) != 0 || ntohs(dh->nscount) != 0 || (ntohs(dh->arcount) != 0 && ntohs(dh->arcount) != 1)) {
PacketBuffer newContent;
int rewriteResponseWithoutEDNSOption(const PacketBuffer& initialPacket, const uint16_t optionCodeToSkip, PacketBuffer& newContent)
{
assert(initialPacket.size() >= sizeof(dnsheader));
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
+ const dnsheader_aligned dh(initialPacket.data());
if (ntohs(dh->arcount) == 0)
return ENOENT;
return false;
}
- auto dh = reinterpret_cast<dnsheader*>(packet.data());
- dh->arcount = htons(ntohs(dh->arcount) + 1);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [](dnsheader& header) {
+ header.arcount = htons(ntohs(header.arcount) + 1);
+ return true;
+ });
return true;
}
/* chop off everything after the question */
packet.resize(queryPartSize);
- dh = dq.getHeader();
- if (nxd) {
- dh->rcode = RCode::NXDomain;
- }
- else {
- dh->rcode = RCode::NoError;
- }
- dh->qr = true;
- dh->ancount = 0;
- dh->nscount = 0;
- dh->arcount = 0;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [nxd](dnsheader& header) {
+ if (nxd) {
+ header.rcode = RCode::NXDomain;
+ }
+ else {
+ header.rcode = RCode::NoError;
+ }
+ header.qr = true;
+ header.ancount = 0;
+ header.nscount = 0;
+ header.arcount = 0;
+ return true;
+ });
rdLength = htons(rdLength);
ttl = htonl(ttl);
}
packet.insert(packet.end(), soa.begin(), soa.end());
- dh = dq.getHeader();
/* We are populating a response with only the query in place, order of sections is QD,AN,NS,AR
NS (authority) is before AR (additional) so we can just decide which section the SOA record is in here
and have EDNS added to AR afterwards */
- if (soaInAuthoritySection) {
- dh->nscount = htons(1);
- } else {
- dh->arcount = htons(1);
- }
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [soaInAuthoritySection](dnsheader& header) {
+ if (soaInAuthoritySection) {
+ header.nscount = htons(1);
+ } else {
+ header.arcount = htons(1);
+ }
+ return true;
+ });
if (hadEDNS) {
/* now we need to add a new OPT record */
/* remove the existing OPT record, and everything else that follows (any SIG or TSIG would be useless anyway) */
packet.resize(packet.size() - existingOptLen);
- dq.getHeader()->arcount = 0;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [](dnsheader& header) {
+ header.arcount = 0;
+ return true;
+ });
if (g_addEDNSToSelfGeneratedResponses) {
/* now we need to add a new OPT record */
auto& data = dq.getMutableData();
if (generateOptRR(optRData, data, dq.getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
- dq.getHeader()->arcount = htons(1);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.arcount = htons(1);
+ return true;
+ });
// make sure that any EDNS sent by the backend is removed before forwarding the response to the client
dq.ids.ednsAdded = true;
}
hadEDNS = getEDNS0Record(buffer, edns0);
}
- auto dh = reinterpret_cast<dnsheader*>(buffer.data());
- dh->rcode = rcode;
- dh->ad = false;
- dh->aa = false;
- dh->ra = dh->rd;
- dh->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(buffer, [rcode,clearAnswers](dnsheader& header) {
+ header.rcode = rcode;
+ header.ad = false;
+ header.aa = false;
+ header.ra = header.rd;
+ header.qr = true;
+
+ if (clearAnswers) {
+ header.ancount = 0;
+ header.nscount = 0;
+ header.arcount = 0;
+ }
+ return true;
+ });
if (clearAnswers) {
- dh->ancount = 0;
- dh->nscount = 0;
- dh->arcount = 0;
buffer.resize(sizeof(dnsheader) + qnameLength + sizeof(uint16_t) + sizeof(uint16_t));
if (hadEDNS) {
DNSQuestion dq(state, buffer);
*/
#pragma once
+#include <unordered_map>
+
#include "config.h"
#include "dnscrypt.hh"
#include "dnsname.hh"
#include "dnsdist-protocols.hh"
+#include "ednsextendederror.hh"
#include "gettime.hh"
#include "iputils.hh"
#include "noinitvector.hh"
std::unique_ptr<QTag> qTag{nullptr}; // 8
std::unique_ptr<PacketBuffer> d_packet{nullptr}; // Initial packet, so we can restart the query from the response path if needed // 8
std::unique_ptr<ProtoBufData> d_protoBufData{nullptr};
+ std::unique_ptr<EDNSExtendedError> d_extendedError{nullptr};
boost::optional<uint32_t> tempFailureTTL{boost::none}; // 8
ClientState* cs{nullptr}; // 8
std::unique_ptr<DOHUnitInterface> du; // 8
#include "threadname.hh"
#include "dnsdist.hh"
#include "dnsdist-async.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-edns.hh"
#include "dnsdist-lua.hh"
void TeeAction::worker()
{
setThreadName("dnsdist/TeeWork");
- char packet[1500];
- int res=0;
- struct dnsheader* dh=(struct dnsheader*)packet;
- for(;;) {
- res=waitForData(d_fd, 0, 250000);
- if(d_pleaseQuit)
+ std::array<char, s_udpIncomingBufferSize> packet{};
+ ssize_t res = 0;
+ const dnsheader_aligned dh(packet.data());
+ for (;;) {
+ res = waitForData(d_fd, 0, 250000);
+ if (d_pleaseQuit) {
break;
- if(res < 0) {
+ }
+
+ if (res < 0) {
usleep(250000);
continue;
}
- if(res==0)
+ if (res == 0) {
continue;
- res=recv(d_fd, packet, sizeof(packet), 0);
- if(res <= (int)sizeof(struct dnsheader))
+ }
+ res = recv(d_fd, packet.data(), packet.size(), 0);
+ if (static_cast<size_t>(res) <= sizeof(struct dnsheader)) {
d_recverrors++;
- else
+ }
+ else {
d_responses++;
+ }
- if(dh->rcode == RCode::NoError)
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ if (dh->rcode == RCode::NoError) {
d_noerrors++;
- else if(dh->rcode == RCode::ServFail)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dh->rcode == RCode::ServFail) {
d_servfails++;
- else if(dh->rcode == RCode::NXDomain)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dh->rcode == RCode::NXDomain) {
d_nxdomains++;
- else if(dh->rcode == RCode::Refused)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dh->rcode == RCode::Refused) {
d_refuseds++;
- else if(dh->rcode == RCode::FormErr)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dh->rcode == RCode::FormErr) {
d_formerrs++;
- else if(dh->rcode == RCode::NotImp)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dh->rcode == RCode::NotImp) {
d_notimps++;
+ }
}
}
RCodeAction(uint8_t rcode) : d_rcode(rcode) {}
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- dq->getHeader()->rcode = d_rcode;
- dq->getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) {
+ header.rcode = d_rcode;
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ return true;
+ });
return Action::HeaderModify;
}
std::string toString() const override
ERCodeAction(uint8_t rcode) : d_rcode(rcode) {}
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- dq->getHeader()->rcode = (d_rcode & 0xF);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) {
+ header.rcode = (d_rcode & 0xF);
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ return true;
+ });
dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4);
- dq->getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
return Action::HeaderModify;
}
std::string toString() const override
if (d_raw.size() >= sizeof(dnsheader)) {
auto id = dq->getHeader()->id;
dq->getMutableData() = d_raw;
- dq->getHeader()->id = id;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [id](dnsheader& header) {
+ header.id = id;
+ return true;
+ });
return Action::HeaderModify;
}
vector<ComboAddress> addrs;
data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen); // there goes your EDNS
uint8_t* dest = &(data.at(sizeof(dnsheader) + qnameWireLength + 4));
- dq->getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
- dq->getHeader()->ancount = 0;
- dq->getHeader()->arcount = 0; // for now, forget about your EDNS, we're marching over it
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) {
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ header.ancount = 0;
+ header.arcount = 0; // for now, forget about your EDNS, we're marching over it
+ return true;
+ });
uint32_t ttl = htonl(d_responseConfig.ttl);
uint16_t qclass = htons(dq->ids.qclass);
memcpy(dest, recordstart, sizeof(recordstart));
dest += sizeof(recordstart);
memcpy(dest, wireData.c_str(), wireData.length());
- dq->getHeader()->ancount++;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) {
+ header.ancount++;
+ return true;
+ });
}
else if (!rawResponses.empty()) {
qtype = htons(qtype);
memcpy(dest, rawResponse.c_str(), rawResponse.size());
dest += rawResponse.size();
- dq->getHeader()->ancount++;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) {
+ header.ancount++;
+ return true;
+ });
}
raw = true;
}
addr.sin4.sin_family == AF_INET ? reinterpret_cast<const void*>(&addr.sin4.sin_addr.s_addr) : reinterpret_cast<const void*>(&addr.sin6.sin6_addr.s6_addr),
addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
dest += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
- dq->getHeader()->ancount++;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) {
+ header.ancount++;
+ return true;
+ });
}
}
- dq->getHeader()->ancount = htons(dq->getHeader()->ancount);
+ auto finalANCount = dq->getHeader()->ancount;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [finalANCount](dnsheader& header) {
+ header.ancount = htons(finalANCount);
+ return true;
+ });
if (hadEDNS && raw == false) {
addEDNS(dq->getMutableData(), dq->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
auto& data = dq->getMutableData();
if (generateOptRR(optRData, data, dq->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
- dq->getHeader()->arcount = htons(1);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) {
+ header.arcount = htons(1);
+ return true;
+ });
// make sure that any EDNS sent by the backend is removed before forwarding the response to the client
dq->ids.ednsAdded = true;
}
// this action does not stop the processing
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- dq->getHeader()->rd = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) {
+ header.rd = false;
+ return true;
+ });
return Action::None;
}
std::string toString() const override
// this action does not stop the processing
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- dq->getHeader()->cd = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) {
+ header.cd = true;
+ return true;
+ });
return Action::None;
}
std::string toString() const override
}
dq->ids.du->setHTTPResponse(d_code, PacketBuffer(d_body), d_contentType);
- dq->getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) {
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ return true;
+ });
return Action::HeaderModify;
}
return Action::None;
}
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) {
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ return true;
+ });
return Action::Allow;
}
double d_ratio{1.0};
};
+class SetExtendedDNSErrorAction : public DNSAction
+{
+public:
+ // this action does not stop the processing
+ SetExtendedDNSErrorAction(uint16_t infoCode, const std::string& extraText)
+ {
+ d_ede.infoCode = infoCode;
+ d_ede.extraText = extraText;
+ }
+
+ DNSAction::Action operator()(DNSQuestion* dnsQuestion, std::string* ruleresult) const override
+ {
+ dnsQuestion->ids.d_extendedError = std::make_unique<EDNSExtendedError>(d_ede);
+
+ return DNSAction::Action::None;
+ }
+
+ [[nodiscard]] std::string toString() const override
+ {
+ return "set EDNS Extended DNS Error to " + std::to_string(d_ede.infoCode) + (d_ede.extraText.empty() ? std::string() : std::string(": \"") + d_ede.extraText + std::string("\""));
+ }
+
+private:
+ EDNSExtendedError d_ede;
+};
+
+class SetExtendedDNSErrorResponseAction : public DNSResponseAction
+{
+public:
+ // this action does not stop the processing
+ SetExtendedDNSErrorResponseAction(uint16_t infoCode, const std::string& extraText)
+ {
+ d_ede.infoCode = infoCode;
+ d_ede.extraText = extraText;
+ }
+
+ DNSResponseAction::Action operator()(DNSResponse* dnsResponse, std::string* ruleresult) const override
+ {
+ dnsResponse->ids.d_extendedError = std::make_unique<EDNSExtendedError>(d_ede);
+
+ return DNSResponseAction::Action::None;
+ }
+
+ [[nodiscard]] std::string toString() const override
+ {
+ return "set EDNS Extended DNS Error to " + std::to_string(d_ede.infoCode) + (d_ede.extraText.empty() ? std::string() : std::string(": \"") + d_ede.extraText + std::string("\""));
+ }
+
+private:
+ 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) {
setLuaSideEffect();
}
}
+// 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)
{
luaCtx.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
luaCtx.writeFunction("SetAdditionalProxyProtocolValueAction", [](uint8_t type, const std::string& value) {
return std::shared_ptr<DNSAction>(new SetAdditionalProxyProtocolValueAction(type, value));
});
+
+ luaCtx.writeFunction("SetExtendedDNSErrorAction", [](uint16_t infoCode, boost::optional<std::string> extraText) {
+ return std::shared_ptr<DNSAction>(new SetExtendedDNSErrorAction(infoCode, extraText ? *extraText : ""));
+ });
+
+ luaCtx.writeFunction("SetExtendedDNSErrorResponseAction", [](uint16_t infoCode, boost::optional<std::string> extraText) {
+ return std::shared_ptr<DNSResponseAction>(new SetExtendedDNSErrorResponseAction(infoCode, extraText ? *extraText : ""));
+ });
}
#include "dnsdist-lua.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
void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
{
#ifndef DISABLE_NON_FFI_DQ_BINDINGS
luaCtx.registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName { return dq.ids.qname; }, [](DNSQuestion& dq, const DNSName& newName) { (void) newName; });
luaCtx.registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.ids.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
luaCtx.registerMember<uint16_t (DNSQuestion::*)>("qclass", [](const DNSQuestion& dq) -> uint16_t { return dq.ids.qclass; }, [](DNSQuestion& dq, uint16_t newClass) { (void) newClass; });
- luaCtx.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return dq.getHeader()->rcode; }, [](DNSQuestion& dq, int newRCode) { dq.getHeader()->rcode = newRCode; });
+ luaCtx.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return static_cast<int>(dq.getHeader()->rcode); }, [](DNSQuestion& dq, int newRCode) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [newRCode](dnsheader& header) {
+ header.rcode = static_cast<decltype(header.rcode)>(newRCode);
+ return true;
+ });
+ });
luaCtx.registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress { return dq.ids.origRemote; }, [](DNSQuestion& dq, const ComboAddress newRemote) { (void) newRemote; });
/* DNSDist DNSQuestion */
- luaCtx.registerMember<dnsheader* (DNSQuestion::*)>("dh", [](const DNSQuestion& dq) -> dnsheader* { return const_cast<DNSQuestion&>(dq).getHeader(); }, [](DNSQuestion& dq, const dnsheader* dh) { *(dq.getHeader()) = *dh; });
+ luaCtx.registerMember<dnsheader* (DNSQuestion::*)>("dh", [](const DNSQuestion& dq) -> dnsheader* { return dq.getMutableHeader(); }, [](DNSQuestion& dq, const dnsheader* dh) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [&dh](dnsheader& header) {
+ header = *dh;
+ return true;
+ });
+ });
luaCtx.registerMember<uint16_t (DNSQuestion::*)>("len", [](const DNSQuestion& dq) -> uint16_t { return dq.getData().size(); }, [](DNSQuestion& dq, uint16_t newlen) { dq.getMutableData().resize(newlen); });
luaCtx.registerMember<uint8_t (DNSQuestion::*)>("opcode", [](const DNSQuestion& dq) -> uint8_t { return dq.getHeader()->opcode; }, [](DNSQuestion& dq, uint8_t newOpcode) { (void) newOpcode; });
luaCtx.registerMember<bool (DNSQuestion::*)>("tcp", [](const DNSQuestion& dq) -> bool { return dq.overTCP(); }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
dq.ids.d_protoBufData->d_requestorID = newValue;
});
luaCtx.registerFunction<bool(DNSQuestion::*)()const>("getDO", [](const DNSQuestion& dq) {
- return getEDNSZ(dq) & EDNS_HEADER_FLAG_DO;
+ return getEDNSZ(dq) & EDNS_HEADER_FLAG_DO;
});
luaCtx.registerFunction<std::string(DNSQuestion::*)()const>("getContent", [](const DNSQuestion& dq) {
return std::string(reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size());
auto& buffer = dq.getMutableData();
buffer.clear();
buffer.insert(buffer.begin(), raw.begin(), raw.end());
- reinterpret_cast<dnsheader*>(buffer.data())->id = oldID;
+
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(buffer, [oldID](dnsheader& header) {
+ header.id = oldID;
+ return true;
+ });
});
luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView>(DNSQuestion::*)()const>("getEDNSOptions", [](const DNSQuestion& dq) {
if (dq.ednsOptions == nullptr) {
setEDNSOption(dq, code, data);
});
+ luaCtx.registerFunction<void(DNSQuestion::*)(uint16_t infoCode, const boost::optional<std::string>& extraText)>("setExtendedDNSError", [](DNSQuestion& dnsQuestion, uint16_t infoCode, const boost::optional<std::string>& extraText) {
+ EDNSExtendedError ede;
+ ede.infoCode = infoCode;
+ if (extraText) {
+ ede.extraText = *extraText;
+ }
+ dnsQuestion.ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+ });
+
luaCtx.registerFunction<bool(DNSQuestion::*)(uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)>("suspend", [](DNSQuestion& dq, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs) {
dq.asynchronous = true;
return dnsdist::suspendQuery(dq, asyncID, queryID, timeoutMs);
luaCtx.registerMember<const DNSName (DNSResponse::*)>("qname", [](const DNSResponse& dq) -> const DNSName { return dq.ids.qname; }, [](DNSResponse& dq, const DNSName& newName) { (void) newName; });
luaCtx.registerMember<uint16_t (DNSResponse::*)>("qtype", [](const DNSResponse& dq) -> uint16_t { return dq.ids.qtype; }, [](DNSResponse& dq, uint16_t newType) { (void) newType; });
luaCtx.registerMember<uint16_t (DNSResponse::*)>("qclass", [](const DNSResponse& dq) -> uint16_t { return dq.ids.qclass; }, [](DNSResponse& dq, uint16_t newClass) { (void) newClass; });
- luaCtx.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return dq.getHeader()->rcode; }, [](DNSResponse& dq, int newRCode) { dq.getHeader()->rcode = newRCode; });
+ luaCtx.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return static_cast<int>(dq.getHeader()->rcode); }, [](DNSResponse& dq, int newRCode) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [newRCode](dnsheader& header) {
+ header.rcode = static_cast<decltype(header.rcode)>(newRCode);
+ return true;
+ });
+ });
luaCtx.registerMember<const ComboAddress (DNSResponse::*)>("remoteaddr", [](const DNSResponse& dq) -> const ComboAddress { return dq.ids.origRemote; }, [](DNSResponse& dq, const ComboAddress newRemote) { (void) newRemote; });
- luaCtx.registerMember<dnsheader* (DNSResponse::*)>("dh", [](const DNSResponse& dr) -> dnsheader* { return const_cast<DNSResponse&>(dr).getHeader(); }, [](DNSResponse& dr, const dnsheader* dh) { *(dr.getHeader()) = *dh; });
+ luaCtx.registerMember<dnsheader* (DNSResponse::*)>("dh", [](const DNSResponse& dr) -> dnsheader* { return dr.getMutableHeader(); }, [](DNSResponse& dr, const dnsheader* dh) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dr.getMutableData(), [&dh](dnsheader& header) {
+ header = *dh;
+ return true;
+ });
+ });
luaCtx.registerMember<uint16_t (DNSResponse::*)>("len", [](const DNSResponse& dq) -> uint16_t { return dq.getData().size(); }, [](DNSResponse& dq, uint16_t newlen) { dq.getMutableData().resize(newlen); });
luaCtx.registerMember<uint8_t (DNSResponse::*)>("opcode", [](const DNSResponse& dq) -> uint8_t { return dq.getHeader()->opcode; }, [](DNSResponse& dq, uint8_t newOpcode) { (void) newOpcode; });
luaCtx.registerMember<bool (DNSResponse::*)>("tcp", [](const DNSResponse& dq) -> bool { return dq.overTCP(); }, [](DNSResponse& dq, bool newTcp) { (void) newTcp; });
auto& buffer = dr.getMutableData();
buffer.clear();
buffer.insert(buffer.begin(), raw.begin(), raw.end());
- reinterpret_cast<dnsheader*>(buffer.data())->id = oldID;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(buffer, [oldID](dnsheader& header) {
+ header.id = oldID;
+ return true;
+ });
});
luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView>(DNSResponse::*)()const>("getEDNSOptions", [](const DNSResponse& dq) {
return setNegativeAndAdditionalSOA(dq, nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum, false);
});
+ luaCtx.registerFunction<void(DNSResponse::*)(uint16_t infoCode, const boost::optional<std::string>& extraText)>("setExtendedDNSError", [](DNSResponse& dnsResponse, uint16_t infoCode, const boost::optional<std::string>& extraText) {
+ EDNSExtendedError ede;
+ ede.infoCode = infoCode;
+ if (extraText) {
+ ede.extraText = *extraText;
+ }
+ dnsResponse.ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+ });
+
luaCtx.registerFunction<bool(DNSResponse::*)(uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)>("suspend", [](DNSResponse& dr, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs) {
dr.asynchronous = true;
return dnsdist::suspendResponse(dr, asyncID, queryID, timeoutMs);
#endif /* DISABLE_DEPRECATED_DYNBLOCK */
#endif /* DISABLE_DYNBLOCKS */
-
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
void setupLuaInspection(LuaContext& luaCtx)
{
#ifndef DISABLE_TOP_N_BINDINGS
luaCtx.writeFunction("requestDoHStatesDump", [] {
setLuaNoSideEffect();
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
g_dohStatesDumpRequested += g_dohClientThreads->getThreadsCount();
+#endif
});
luaCtx.writeFunction("dumpStats", [] {
group->includeRange(Netmask(*boost::get<std::string>(&ranges)));
}
});
+ luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, LuaArray<std::string>, NetmaskGroup>)>("removeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, LuaArray<std::string>, NetmaskGroup> ranges) {
+ if (ranges.type() == typeid(LuaArray<std::string>)) {
+ for (const auto& range : *boost::get<LuaArray<std::string>>(&ranges)) {
+ group->removeRange(Netmask(range.second));
+ }
+ }
+ else if (ranges.type() == typeid(NetmaskGroup)) {
+ group->removeRange(*boost::get<NetmaskGroup>(&ranges));
+ }
+ else {
+ group->removeRange(Netmask(*boost::get<std::string>(&ranges)));
+ }
+ });
luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(LuaTypeOrArrayOf<std::string>)>("excludeDomains", [](std::shared_ptr<DynBlockRulesGroup>& group, LuaTypeOrArrayOf<std::string> domains) {
if (domains.type() == typeid(LuaArray<std::string>)) {
for (const auto& range : *boost::get<LuaArray<std::string>>(&domains)) {
if (auto str = boost::get<std::string>(&id)) {
try {
const auto uuid = getUniqueID(*str);
- if (rules.erase(std::remove_if(rules.begin(),
+ auto removeIt = std::remove_if(rules.begin(),
rules.end(),
- [uuid](const T& a) { return a.d_id == uuid; }),
- rules.end()) == 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());
}
catch (const std::runtime_error& e) {
/* it was not an UUID, let's see if it was a name instead */
- if (rules.erase(std::remove_if(rules.begin(),
+ auto removeIt = std::remove_if(rules.begin(),
rules.end(),
- [&str](const T& a) { return a.d_name == *str; }),
- rules.end()) == 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());
}
}
else if (auto pos = boost::get<unsigned int>(&id)) {
tlsCtx = getTLSContext(config.d_tlsParams);
if (getOptionalValue<std::string>(vars, "dohPath", valueStr) > 0) {
-#ifndef HAVE_NGHTTP2
- throw std::runtime_error("Outgoing DNS over HTTPS support requested (via 'dohPath' on newServer()) but nghttp2 support is not available");
+#if !defined(HAVE_DNS_OVER_HTTPS) || !defined(HAVE_NGHTTP2)
+ throw std::runtime_error("Outgoing DNS over HTTPS support requested (via 'dohPath' on newServer()) but it is not available");
#endif
serverPort = 443;
setTCPDownstreamMaxIdleConnectionsPerBackend(max);
});
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
luaCtx.writeFunction("setMaxIdleDoHConnectionsPerDownstream", [](uint64_t max) {
setDoHDownstreamMaxIdleConnectionsPerBackend(max);
});
}
g_outgoingDoHWorkerThreads = workers;
});
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](uint64_t max) {
if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketsPerBackend")) {
return;
}
- DIR* dirp;
- struct dirent* ent;
std::vector<std::string> files;
- if (!(dirp = opendir(dirname.c_str()))) {
- errlog("Error opening the included directory %s!", dirname.c_str());
- g_outputBuffer = "Error opening the included directory " + dirname + "!";
- return;
- }
-
- while ((ent = readdir(dirp)) != NULL) {
- if (ent->d_name[0] == '.') {
- continue;
+ {
+ auto dirHandle = std::unique_ptr<DIR, decltype(&closedir)>(opendir(dirname.c_str()), closedir);
+ if (!dirHandle) {
+ errlog("Error opening the included directory %s!", dirname.c_str());
+ g_outputBuffer = "Error opening the included directory " + dirname + "!";
+ return;
}
- if (boost::ends_with(ent->d_name, ".conf")) {
- std::ostringstream namebuf;
- namebuf << dirname << "/" << ent->d_name;
-
- if (stat(namebuf.str().c_str(), &st) || !S_ISREG(st.st_mode)) {
+ struct dirent* ent = nullptr;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
+ while ((ent = readdir(dirHandle.get())) != nullptr) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
+ if (ent->d_name[0] == '.') {
continue;
}
- files.push_back(namebuf.str());
+ if (boost::ends_with(ent->d_name, ".conf")) {
+ std::ostringstream namebuf;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
+ namebuf << dirname << "/" << ent->d_name;
+
+ if (stat(namebuf.str().c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
+ continue;
+ }
+
+ files.push_back(namebuf.str());
+ }
}
}
- closedir(dirp);
std::sort(files.begin(), files.end());
g_included = true;
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();
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;
#include "dnsdist.hh"
#include "dnsdist-concurrent-connections.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-nghttp2-in.hh"
#include "dnsdist-proxy-protocol.hh"
DNSResponse dr(ids, response.d_buffer, ds);
dr.d_incomingTCPState = state;
- memcpy(&response.d_cleartextDH, dr.getHeader(), sizeof(response.d_cleartextDH));
+ memcpy(&response.d_cleartextDH, dr.getHeader().get(), sizeof(response.d_cleartextDH));
if (!processResponse(response.d_buffer, *state->d_threadData.localRespRuleActions, *state->d_threadData.localCacheInsertedRespRuleActions, dr, false)) {
state->terminateClientConnection();
{
/* this pointer will be invalidated the second the buffer is resized, don't hold onto it! */
- auto* dh = reinterpret_cast<dnsheader*>(query.data());
- if (!checkQueryHeaders(dh, *d_ci.cs)) {
+ const dnsheader_aligned dh(query.data());
+ if (!checkQueryHeaders(dh.get(), *d_ci.cs)) {
return QueryProcessingResult::InvalidHeaders;
}
if (dh->qdcount == 0) {
TCPResponse response;
- dh->rcode = RCode::NotImp;
- dh->qr = true;
auto queryID = dh->id;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
response.d_idstate = std::move(ids);
response.d_idstate.origID = queryID;
response.d_idstate.selfGenerated = true;
}
DNSQuestion dq(ids, query);
- const uint16_t* flags = getFlagsFromDNSHeader(dq.getHeader());
- ids.origFlags = *flags;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [&ids](dnsheader& header) {
+ const uint16_t* flags = getFlagsFromDNSHeader(&header);
+ ids.origFlags = *flags;
+ return true;
+ });
dq.d_incomingTCPState = state;
dq.sni = d_handler.getServerNameIndication();
if (forwardViaUDPFirst()) {
// if there was no EDNS, we add it with a large buffer size
// so we can use UDP to talk to the backend.
- auto dh = const_cast<struct dnsheader*>(reinterpret_cast<const struct dnsheader*>(query.data()));
+ const dnsheader_aligned dh(query.data());
if (!dh->arcount) {
if (addEDNS(query, 4096, false, 4096, 0)) {
dq.ids.ednsAdded = true;
// the buffer might have been invalidated by now
uint16_t queryID;
{
- const dnsheader* dh = dq.getHeader();
+ const auto dh = dq.getHeader();
queryID = dh->id;
}
if (result == ProcessQueryResult::SendAnswer) {
TCPResponse response;
{
- const dnsheader* dh = dq.getHeader();
- memcpy(&response.d_cleartextDH, dh, sizeof(response.d_cleartextDH));
+ const auto dh = dq.getHeader();
+ memcpy(&response.d_cleartextDH, dh.get(), sizeof(response.d_cleartextDH));
}
response.d_idstate = std::move(ids);
response.d_idstate.origID = queryID;
gettimeofday(&now, nullptr);
if (citmp->cs->dohFrontend) {
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
auto state = std::make_shared<IncomingHTTP2Connection>(std::move(*citmp), *threadData, now);
state->handleIO();
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
else {
auto state = std::make_shared<IncomingTCPConnectionState>(std::move(*citmp), *threadData, now);
state->handleTimeout(state, false);
}
}
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
else if (cbData.second.type() == typeid(std::shared_ptr<IncomingHTTP2Connection>)) {
auto state = boost::any_cast<std::shared_ptr<IncomingHTTP2Connection>>(cbData.second);
if (cbData.first == state->d_handler.getDescriptor()) {
state->handleTimeout(parentState, false);
}
}
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
else if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
vinfolog("Timeout (read) from remote backend %s", conn->getBackendName());
state->handleTimeout(state, true);
}
}
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
else if (cbData.second.type() == typeid(std::shared_ptr<IncomingHTTP2Connection>)) {
auto state = boost::any_cast<std::shared_ptr<IncomingHTTP2Connection>>(cbData.second);
if (cbData.first == state->d_handler.getDescriptor()) {
state->handleTimeout(parentState, true);
}
}
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
else if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
vinfolog("Timeout (write) from remote backend %s", conn->getBackendName());
auto state = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(param);
infolog(" - %s", state->toString());
}
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
else if (param.type() == typeid(std::shared_ptr<IncomingHTTP2Connection>)) {
auto state = boost::any_cast<std::shared_ptr<IncomingHTTP2Connection>>(param);
infolog(" - %s", state->toString());
}
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
else if (param.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(param);
infolog(" - %s", conn->toString());
gettimeofday(&now, nullptr);
if (ci.cs->dohFrontend) {
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
auto state = std::make_shared<IncomingHTTP2Connection>(std::move(ci), *threadData, now);
state->handleIO();
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
else {
auto state = std::make_shared<IncomingTCPConnectionState>(std::move(ci), *threadData, now);
#include "dnsdist-healthchecks.hh"
#include "dnsdist-metrics.hh"
#include "dnsdist-prometheus.hh"
+#include "dnsdist-rings.hh"
#include "dnsdist-web.hh"
#include "dolog.hh"
#include "gettime.hh"
{ "latency-doh-avg1000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000 packets received over DoH")},
{ "latency-doh-avg10000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 10000 packets received over DoH")},
{ "latency-doh-avg1000000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000000 packets received over DoH")},
+ { "latency-doq-avg100", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 100 packets received over DoQ")},
+ { "latency-doq-avg1000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000 packets received over DoQ")},
+ { "latency-doq-avg10000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 10000 packets received over DoQ")},
+ { "latency-doq-avg1000000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000000 packets received over DoQ")},
{ "uptime", MetricDefinition(PrometheusMetricType::gauge, "Uptime of the dnsdist process in seconds")},
{ "real-memory-usage", MetricDefinition(PrometheusMetricType::gauge, "Current memory usage in bytes")},
{ "noncompliant-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped as non-compliant")},
}
#endif /* DISABLE_WEB_CACHE_MANAGEMENT */
+template<typename T> static void addRingEntryToList(const struct timespec& now, Json::array& list, const T& entry)
+{
+ constexpr bool response = std::is_same_v<T, Rings::Response>;
+ Json::object tmp{
+ { "age", static_cast<double>(DiffTime(entry.when, now)) },
+ { "id", ntohs(entry.dh.id) },
+ { "name", entry.name.toString() },
+ { "requestor", entry.requestor.toStringWithPort() },
+ { "size", static_cast<int>(entry.size) },
+ { "qtype", entry.qtype },
+ { "protocol", entry.protocol.toString() },
+ { "rd", static_cast<bool>(entry.dh.rd) },
+ };
+ if constexpr (!response) {
+#if defined(DNSDIST_RINGS_WITH_MACADDRESS)
+ tmp.emplace("mac", entry.hasmac ? std::string(reinterpret_cast<const char*>(entry.macaddress.data()), entry.macaddress.size()) : std::string());
+#endif
+ }
+ else {
+ tmp.emplace("latency", static_cast<double>(entry.usec));
+ tmp.emplace("rcode", static_cast<uint8_t>(entry.dh.rcode));
+ tmp.emplace("tc", static_cast<bool>(entry.dh.tc));
+ tmp.emplace("aa", static_cast<bool>(entry.dh.aa));
+ tmp.emplace("answers", ntohs(entry.dh.ancount));
+ auto server = entry.ds.toStringWithPort();
+ tmp.emplace("backend", server != "0.0.0.0:0" ? std::move(server) : "Cache");
+ }
+ list.push_back(std::move(tmp));
+}
+
+static void handleRings(const YaHTTP::Request& req, YaHTTP::Response& resp)
+{
+ handleCORS(req, resp);
+
+ std::optional<size_t> maxNumberOfQueries{std::nullopt};
+ std::optional<size_t> maxNumberOfResponses{std::nullopt};
+
+ const auto maxQueries = req.getvars.find("maxQueries");
+ if (maxQueries != req.getvars.end()) {
+ try {
+ maxNumberOfQueries = pdns::checked_stoi<size_t>(maxQueries->second);
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Error parsing the 'maxQueries' value from rings HTTP GET query: %s", exp.what());
+ }
+ }
+
+ const auto maxResponses = req.getvars.find("maxResponses");
+ if (maxResponses != req.getvars.end()) {
+ try {
+ maxNumberOfResponses = pdns::checked_stoi<size_t>(maxResponses->second);
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Error parsing the 'maxResponses' value from rings HTTP GET query: %s", exp.what());
+ }
+ }
+
+ resp.status = 200;
+
+ Json::object doc;
+ size_t numberOfQueries = 0;
+ size_t numberOfResponses = 0;
+ Json::array queries;
+ Json::array responses;
+ struct timespec now
+ {
+ };
+ gettime(&now);
+
+ for (const auto& shard : g_rings.d_shards) {
+ if (!maxNumberOfQueries || numberOfQueries < *maxNumberOfQueries) {
+ auto queryRing = shard->queryRing.lock();
+ for (const auto& entry : *queryRing) {
+ addRingEntryToList(now, queries, entry);
+ numberOfQueries++;
+ if (maxNumberOfQueries && numberOfQueries >= *maxNumberOfQueries) {
+ break;
+ }
+ }
+ }
+ if (!maxNumberOfResponses || numberOfResponses < *maxNumberOfResponses) {
+ auto responseRing = shard->respRing.lock();
+ for (const auto& entry : *responseRing) {
+ addRingEntryToList(now, responses, entry);
+ numberOfResponses++;
+ if (maxNumberOfResponses && numberOfResponses >= *maxNumberOfResponses) {
+ break;
+ }
+ }
+ }
+ }
+ doc.emplace("queries", std::move(queries));
+ doc.emplace("responses", std::move(responses));
+ Json my_json = doc;
+ resp.body = my_json.dump();
+ resp.headers["Content-Type"] = "application/json";
+}
+
static std::unordered_map<std::string, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)>> s_webHandlers;
void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler);
registerWebHandler("/api/v1/servers/localhost", handleStats);
registerWebHandler("/api/v1/servers/localhost/pool", handlePoolStats);
registerWebHandler("/api/v1/servers/localhost/statistics", handleStatsOnly);
+ registerWebHandler("/api/v1/servers/localhost/rings", handleRings);
#ifndef DISABLE_WEB_CONFIG
registerWebHandler("/api/v1/servers/localhost/config", handleConfigDump);
registerWebHandler("/api/v1/servers/localhost/config/allow-from", handleAllowFrom);
#include "dnsdist-xpf.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsparser.hh"
#include "xpf.hh"
pos += payload.size();
(void) pos;
- dq.getHeader()->arcount = htons(ntohs(dq.getHeader()->arcount) + 1);
-
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.arcount = htons(ntohs(header.arcount) + 1);
+ return true;
+ });
return true;
}
#include "dnsdist-carbon.hh"
#include "dnsdist-console.hh"
#include "dnsdist-discovery.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-ecs.hh"
+#include "dnsdist-edns.hh"
#include "dnsdist-healthchecks.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-nghttp2.hh"
}
packet.resize(static_cast<uint16_t>(sizeof(dnsheader)+qnameWireLength+DNS_TYPE_SIZE+DNS_CLASS_SIZE));
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet.data());
- dh->ancount = dh->arcount = dh->nscount = 0;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [](dnsheader& header) {
+ header.ancount = 0;
+ header.arcount = 0;
+ header.nscount = 0;
+ return true;
+ });
if (hadEDNS) {
addEDNS(packet, maximumSize, z & EDNS_HEADER_FLAG_DO, payloadSize, 0);
std::string DNSQuestion::getTrailingData() const
{
- const char* message = reinterpret_cast<const char*>(this->getHeader());
- const uint16_t messageLen = getDNSPacketLength(message, this->data.size());
+ // 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());
return std::string(message + messageLen, this->getData().size() - messageLen);
}
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) {
doAvg(dnsdist::metrics::g_stats.latencyDoHAvg10000, udiff, 10000);
doAvg(dnsdist::metrics::g_stats.latencyDoHAvg1000000, udiff, 1000000);
}
+ else if (protocol == dnsdist::Protocol::DoQ) {
+ doAvg(dnsdist::metrics::g_stats.latencyDoQAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyDoQAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoQAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoQAvg1000000, udiff, 1000000);
+ }
}
bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, unsigned int& qnameWireLength)
return false;
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(response.data());
+ const dnsheader_aligned dh(response.data());
if (dh->qr == 0) {
++dnsdist::metrics::g_stats.nonCompliantResponses;
if (remote) {
*flags |= origFlags;
}
-static bool fixUpQueryTurnedResponse(DNSQuestion& dq, const uint16_t origFlags)
+static bool fixUpQueryTurnedResponse(DNSQuestion& dnsQuestion, const uint16_t origFlags)
{
- restoreFlags(dq.getHeader(), origFlags);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [origFlags](dnsheader& header) {
+ restoreFlags(&header, origFlags);
+ return true;
+ });
- return addEDNSToQueryTurnedResponse(dq);
+ return addEDNSToQueryTurnedResponse(dnsQuestion);
}
static bool fixUpResponse(PacketBuffer& response, const DNSName& qname, uint16_t origFlags, bool ednsAdded, bool ecsAdded, bool* zeroScope)
return false;
}
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
- restoreFlags(dh, origFlags);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(response, [origFlags](dnsheader& header) {
+ restoreFlags(&header, origFlags);
+ return true;
+ });
if (response.size() == sizeof(dnsheader)) {
return true;
if (last) {
/* simply remove the last AR */
response.resize(response.size() - optLen);
- dh = reinterpret_cast<struct dnsheader*>(response.data());
- uint16_t arcount = ntohs(dh->arcount);
- arcount--;
- dh->arcount = htons(arcount);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(response, [](dnsheader& header) {
+ uint16_t arcount = ntohs(header.arcount);
+ arcount--;
+ header.arcount = htons(arcount);
+ return true;
+ });
}
else {
/* Removing an intermediary RR could lead to compression error */
return true;
break;
case DNSResponseAction::Action::ServFail:
- dr.getHeader()->rcode = RCode::ServFail;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dr.getMutableData(), [](dnsheader& header) {
+ header.rcode = RCode::ServFail;
+ return true;
+ });
return true;
break;
/* non-terminal actions follow */
ac(&dr, &result);
}
+ if (dr.ids.d_extendedError) {
+ dnsdist::edns::addExtendedDNSError(dr.getMutableData(), dr.getMaximumSize(), dr.ids.d_extendedError->infoCode, dr.ids.d_extendedError->extraText);
+ }
+
#ifdef HAVE_DNSCRYPT
if (!muted) {
if (!encryptResponse(response, dr.getMaximumSize(), dr.overTCP(), dr.ids.dnsCryptQuery)) {
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(dr.getMutableData(), dr.getMaximumSize(), dr.ids.qname.wirelength());
- dr.getHeader()->tc = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dr.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ return true;
+ });
}
else if (dr.getHeader()->tc && g_truncateTC) {
truncateTC(response, dr.getMaximumSize(), dr.ids.qname.wirelength());
/* when the answer is encrypted in place, we need to get a copy
of the original header before encryption to fill the ring buffer */
dnsheader cleartextDH;
- memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH));
+ memcpy(&cleartextDH, dr.getHeader().get(), sizeof(cleartextDH));
if (!isAsync) {
if (!processResponse(response, respRuleActions, cacheInsertedRespRuleActions, dr, ids.cs && ids.cs->muted)) {
}
response.resize(static_cast<size_t>(got));
- dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
+ const dnsheader_aligned dh(response.data());
queryId = dh->id;
auto ids = dss->getState(queryId);
auto du = std::move(ids->du);
- dh->id = ids->origID;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(response, [&ids](dnsheader& header) {
+ header.id = ids->origID;
+ return true;
+ });
++dss->responses;
double udiff = ids->queryRealTime.udiff();
return false;
}
- switch(action) {
+ auto setRCode = [&dq](uint8_t rcode) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [rcode](dnsheader& header) {
+ header.rcode = rcode;
+ header.qr = true;
+ return true;
+ });
+ };
+
+ switch (action) {
case DNSAction::Action::Allow:
return true;
break;
return true;
break;
case DNSAction::Action::Nxdomain:
- dq.getHeader()->rcode = RCode::NXDomain;
- dq.getHeader()->qr = true;
+ setRCode(RCode::NXDomain);
return true;
break;
case DNSAction::Action::Refused:
- dq.getHeader()->rcode = RCode::Refused;
- dq.getHeader()->qr = true;
+ setRCode(RCode::Refused);
return true;
break;
case DNSAction::Action::ServFail:
- dq.getHeader()->rcode = RCode::ServFail;
- dq.getHeader()->qr = true;
+ setRCode(RCode::ServFail);
return true;
break;
case DNSAction::Action::Spoof:
break;
case DNSAction::Action::Truncate:
if (!dq.overTCP()) {
- dq.getHeader()->tc = true;
- dq.getHeader()->qr = true;
- dq.getHeader()->ra = dq.getHeader()->rd;
- dq.getHeader()->aa = false;
- dq.getHeader()->ad = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ header.qr = true;
+ header.ra = header.rd;
+ header.aa = false;
+ header.ad = false;
+ return true;
+ });
++dnsdist::metrics::g_stats.ruleTruncated;
return true;
}
return true;
break;
case DNSAction::Action::NoRecurse:
- dq.getHeader()->rd = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.rd = false;
+ return true;
+ });
return true;
break;
/* non-terminal actions follow */
}
#ifndef DISABLE_DYNBLOCKS
+ auto setRCode = [&dq](uint8_t rcode) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [rcode](dnsheader& header) {
+ header.rcode = rcode;
+ header.qr = true;
+ return true;
+ });
+ };
+
/* 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(dq.ids.origRemote, dq.ids.origRemote.isIPv4() ? 32 : 128, 16))) {
auto updateBlockStats = [&got]() {
if (action == DNSAction::Action::None) {
action = g_dynBlockAction;
}
+
switch (action) {
case DNSAction::Action::NoOp:
/* do nothing */
vinfolog("Query from %s turned into NXDomain because of dynamic block", dq.ids.origRemote.toStringWithPort());
updateBlockStats();
- dq.getHeader()->rcode = RCode::NXDomain;
- dq.getHeader()->qr=true;
+ setRCode(RCode::NXDomain);
return true;
case DNSAction::Action::Refused:
vinfolog("Query from %s refused because of dynamic block", dq.ids.origRemote.toStringWithPort());
updateBlockStats();
- dq.getHeader()->rcode = RCode::Refused;
- dq.getHeader()->qr = true;
+ setRCode(RCode::Refused);
return true;
case DNSAction::Action::Truncate:
if (!dq.overTCP()) {
updateBlockStats();
vinfolog("Query from %s truncated because of dynamic block", dq.ids.origRemote.toStringWithPort());
- dq.getHeader()->tc = true;
- dq.getHeader()->qr = true;
- dq.getHeader()->ra = dq.getHeader()->rd;
- dq.getHeader()->aa = false;
- dq.getHeader()->ad = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ header.qr = true;
+ header.ra = header.rd;
+ header.aa = false;
+ header.ad = false;
+ return true;
+ });
return true;
}
else {
case DNSAction::Action::NoRecurse:
updateBlockStats();
vinfolog("Query from %s setting rd=0 because of dynamic block", dq.ids.origRemote.toStringWithPort());
- dq.getHeader()->rd = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.rd = false;
+ return true;
+ });
return true;
default:
updateBlockStats();
vinfolog("Query from %s for %s turned into NXDomain because of dynamic block", dq.ids.origRemote.toStringWithPort(), dq.ids.qname.toLogString());
updateBlockStats();
- dq.getHeader()->rcode = RCode::NXDomain;
- dq.getHeader()->qr = true;
+ setRCode(RCode::NXDomain);
return true;
case DNSAction::Action::Refused:
vinfolog("Query from %s for %s refused because of dynamic block", dq.ids.origRemote.toStringWithPort(), dq.ids.qname.toLogString());
updateBlockStats();
- dq.getHeader()->rcode = RCode::Refused;
- dq.getHeader()->qr = true;
+ setRCode(RCode::Refused);
return true;
case DNSAction::Action::Truncate:
if (!dq.overTCP()) {
updateBlockStats();
vinfolog("Query from %s for %s truncated because of dynamic block", dq.ids.origRemote.toStringWithPort(), dq.ids.qname.toLogString());
- dq.getHeader()->tc = true;
- dq.getHeader()->qr = true;
- dq.getHeader()->ra = dq.getHeader()->rd;
- dq.getHeader()->aa = false;
- dq.getHeader()->ad = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ header.qr = true;
+ header.ra = header.rd;
+ header.aa = false;
+ header.ad = false;
+ return true;
+ });
return true;
}
else {
case DNSAction::Action::NoRecurse:
updateBlockStats();
vinfolog("Query from %s setting rd=0 because of dynamic block", dq.ids.origRemote.toStringWithPort());
- dq.getHeader()->rd = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.rd = false;
+ return true;
+ });
return true;
default:
updateBlockStats();
ac(&dr, &result);
}
+ if (dr.ids.d_extendedError) {
+ dnsdist::edns::addExtendedDNSError(dr.getMutableData(), dr.getMaximumSize(), dr.ids.d_extendedError->infoCode, dr.ids.d_extendedError->extraText);
+ }
+
if (cacheHit) {
++dnsdist::metrics::g_stats.cacheHits;
}
yet, as we will do a second-lookup */
if (dq.ids.packetCache->get(dq, dq.getHeader()->id, &dq.ids.cacheKey, dq.ids.subnet, dq.ids.dnssecOK, forwardedOverUDP, allowExpired, false, true, dq.ids.protocol != dnsdist::Protocol::DoH || forwardedOverUDP)) {
- restoreFlags(dq.getHeader(), dq.ids.origFlags);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [flags=dq.ids.origFlags](dnsheader& header) {
+ restoreFlags(&header, flags);
+ return true;
+ });
vinfolog("Packet cache hit for query for %s|%s from %s (%s, %d bytes)", dq.ids.qname.toLogString(), QType(dq.ids.qtype).toString(), dq.ids.origRemote.toStringWithPort(), dq.ids.protocol.toString(), dq.getData().size());
vinfolog("%s query for %s|%s from %s, no downstream server available", g_servFailOnNoPolicy ? "ServFailed" : "Dropped", dq.ids.qname.toLogString(), QType(dq.ids.qtype).toString(), dq.ids.origRemote.toStringWithPort());
if (g_servFailOnNoPolicy) {
- dq.getHeader()->rcode = RCode::ServFail;
- dq.getHeader()->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.rcode = RCode::ServFail;
+ header.qr = true;
+ return true;
+ });
fixUpQueryTurnedResponse(dq, dq.ids.origFlags);
}
/* save the DNS flags as sent to the backend so we can cache the answer with the right flags later */
- dq.ids.cacheFlags = *getFlagsFromDNSHeader(dq.getHeader());
+ dq.ids.cacheFlags = *getFlagsFromDNSHeader(dq.getHeader().get());
if (dq.addXPF && selectedBackend->d_config.xpfRRCode != 0) {
addXPF(dq, selectedBackend->d_config.xpfRRCode);
{
/* this pointer will be invalidated the second the buffer is resized, don't hold onto it! */
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(query.data());
+ const dnsheader_aligned dh(query.data());
queryId = ntohs(dh->id);
- if (!checkQueryHeaders(dh, cs)) {
+ if (!checkQueryHeaders(dh.get(), cs)) {
return;
}
if (dh->qdcount == 0) {
- dh->rcode = RCode::NotImp;
- dh->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
+
sendUDPResponse(cs.udpFD, query, 0, dest, remote);
return;
}
ids.protocol = dnsdist::Protocol::DNSCryptUDP;
}
DNSQuestion dq(ids, query);
- const uint16_t* flags = getFlagsFromDNSHeader(dq.getHeader());
+ const uint16_t* flags = getFlagsFromDNSHeader(dq.getHeader().get());
ids.origFlags = *flags;
if (!proxyProtocolValues.empty()) {
}
// the buffer might have been invalidated by now (resized)
- struct dnsheader* dh = dq.getHeader();
+ const auto dh = dq.getHeader();
if (result == ProcessQueryResult::SendAnswer) {
#ifndef DISABLE_RECVMMSG
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
g_tcpclientthreads = std::make_unique<TCPClientCollection>(*g_maxTCPClientThreads, std::vector<ClientState*>());
#endif
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
initDoHWorkers();
+#endif
for (auto& todoItem : todo) {
todoItem();
return data;
}
- dnsheader* getHeader()
+ bool editHeader(const std::function<bool(dnsheader&)>& editFunction);
+
+ const dnsheader_aligned getHeader() const
{
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 reinterpret_cast<dnsheader*>(&data.at(0));
+ dnsheader_aligned dh(data.data());
+ return dh;
}
- const dnsheader* getHeader() const
+ /* this function is not safe against unaligned access, you should
+ use editHeader() instead, but we need it for the Lua bindings */
+ dnsheader* getMutableHeader() const
{
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 reinterpret_cast<const dnsheader*>(&data.at(0));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ return reinterpret_cast<dnsheader*>(data.data());
}
bool hasRoomFor(size_t more) const
/missing
/testrunner
/dnsdist
+/fuzz_target_dnsdistcache
/*.pb.cc
/*.pb.h
/dnsdist.service
dnsdist-lua.cc dnsdist-lua.hh \
dnsdist-mac-address.cc dnsdist-mac-address.hh \
dnsdist-metrics.cc dnsdist-metrics.hh \
- dnsdist-nghttp2-in.cc dnsdist-nghttp2-in.hh \
- dnsdist-nghttp2.cc dnsdist-nghttp2.hh \
+ dnsdist-nghttp2-in.hh \
+ dnsdist-nghttp2.hh \
dnsdist-prometheus.hh \
dnsdist-protobuf.cc dnsdist-protobuf.hh \
dnsdist-protocols.cc dnsdist-protocols.hh \
dolog.hh \
doq.hh \
ednscookies.cc ednscookies.hh \
+ ednsextendederror.cc ednsextendederror.hh \
ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
ext/json11/json11.cpp \
dnsdist-lua-vars.cc \
dnsdist-mac-address.cc dnsdist-mac-address.hh \
dnsdist-metrics.cc dnsdist-metrics.hh \
- dnsdist-nghttp2-in.cc dnsdist-nghttp2-in.hh \
- dnsdist-nghttp2.cc dnsdist-nghttp2.hh \
+ dnsdist-nghttp2-in.hh \
+ dnsdist-nghttp2.hh \
dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
dnsdist-random.cc dnsdist-random.hh \
test-dnsdistkvs_cc.cc \
test-dnsdistlbpolicies_cc.cc \
test-dnsdistluanetwork.cc \
- test-dnsdistnghttp2-in_cc.cc \
- test-dnsdistnghttp2_cc.cc \
test-dnsdistnghttp2_common.hh \
test-dnsdistpacketcache_cc.cc \
test-dnsdistrings_cc.cc \
dnsdist_LDADD += $(LIBH2OEVLOOP_LIBS)
endif
+if HAVE_NGHTTP2
+dnsdist_SOURCES += dnsdist-nghttp2-in.cc
+dnsdist_SOURCES += dnsdist-nghttp2.cc
+testrunner_SOURCES += dnsdist-nghttp2-in.cc
+testrunner_SOURCES += dnsdist-nghttp2.cc
+testrunner_SOURCES += test-dnsdistnghttp2-in_cc.cc \
+ test-dnsdistnghttp2_cc.cc
+dnsdist_LDADD += $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
+testrunner_LDADD += $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
+endif
+
endif
if HAVE_DNS_OVER_QUIC
endif
endif
-if HAVE_NGHTTP2
-dnsdist_LDADD += $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
-testrunner_LDADD += $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
-endif
-
if !HAVE_LUA_HPP
BUILT_SOURCES += lua.hpp
nodist_dnsdist_SOURCES = lua.hpp
channel.hh channel.cc \
dns.cc dns.hh \
dnsdist-cache.cc dnsdist-cache.hh \
+ dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
dnsdist-ecs.cc dnsdist-ecs.hh \
dnsdist-idstate.hh \
dnsdist-protocols.cc dnsdist-protocols.hh \
])
])
-PDNS_WITH_NGHTTP2
DNSDIST_WITH_CDB
PDNS_CHECK_LMDB
PDNS_ENABLE_IPCIPHER
bool DownstreamState::passCrossProtocolQuery(std::unique_ptr<CrossProtocolQuery>&& cpq)
{
- if (d_config.d_dohPath.empty()) {
- return g_tcpclientthreads && g_tcpclientthreads->passCrossProtocolQueryToThread(std::move(cpq));
- }
- else {
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ if (!d_config.d_dohPath.empty()) {
return g_dohClientThreads && g_dohClientThreads->passCrossProtocolQueryToThread(std::move(cpq));
}
+#endif
+ return g_tcpclientthreads && g_tcpclientthreads->passCrossProtocolQueryToThread(std::move(cpq));
}
bool DownstreamState::reconnect(bool initialAttempt)
static bool parseSVCParams(const PacketBuffer& answer, std::map<uint16_t, DesignatedResolvers>& resolvers)
{
std::map<DNSName, std::vector<ComboAddress>> hints;
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(answer.data());
+ const dnsheader_aligned dh(answer.data());
PacketReader pr(std::string_view(reinterpret_cast<const char*>(answer.data()), answer.size()));
uint16_t qdcount = ntohs(dh->qdcount);
uint16_t ancount = ntohs(dh->ancount);
#include "dnsdist-ecs.hh"
#include "dnsdist-edns.hh"
#include "ednsoptions.hh"
+#include "ednsextendederror.hh"
namespace dnsdist::edns
{
}
return {infoCode, std::move(extraText)};
}
+
+bool addExtendedDNSError(PacketBuffer& packet, size_t maximumPacketSize, uint16_t code, const std::string& extraStatus)
+{
+ uint16_t optStart = 0;
+ size_t optLen = 0;
+ bool last = false;
+
+ int res = locateEDNSOptRR(packet, &optStart, &optLen, &last);
+
+ if (res != 0) {
+ /* no EDNS OPT record in the response, something is not right */
+ return false;
+ }
+
+ EDNSExtendedError ede{.infoCode = code, .extraText = extraStatus};
+ auto edeOptionPayload = makeEDNSExtendedErrorOptString(ede);
+ std::string edeOption;
+ generateEDNSOption(EDNSOptionCode::EXTENDEDERROR, edeOptionPayload, edeOption);
+
+ /* we might have one record after the OPT one, we need to rewrite
+ the whole packet because of compression */
+ PacketBuffer newContent;
+ bool ednsAdded = false;
+ bool edeAdded = false;
+ if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::EXTENDEDERROR, edeAdded, true, edeOption)) {
+ return false;
+ }
+
+ if (newContent.size() > maximumPacketSize) {
+ return false;
+ }
+
+ packet = std::move(newContent);
+ return true;
+}
}
namespace dnsdist::edns
{
std::pair<std::optional<uint16_t>, std::optional<std::string>> getExtendedDNSError(const PacketBuffer& packet);
+bool addExtendedDNSError(PacketBuffer& packet, size_t maximumPacketSize, uint16_t code, const std::string& extraStatus);
}
mplexer->addReadFD(data->d_udpSocket.getHandle(), &healthCheckUDPCallback, data, &data->d_ttd);
}
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
else if (downstream->isDoH()) {
InternalQuery query(std::move(packet), InternalQueryState());
query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
data->d_ds->submitHealthCheckResult(data->d_initial, false);
}
}
+#endif
else {
data->d_tcpHandler = std::make_unique<TCPIOHandler>(downstream->d_config.d_tlsSubjectName, downstream->d_config.d_tlsSubjectIsAddr, sock.releaseHandle(), timeval{downstream->d_config.checkTimeout, 0}, downstream->d_tlsCtx);
data->d_ioState = std::make_unique<IOStateHandler>(*mplexer, data->d_tcpHandler->getDescriptor());
continue;
}
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
handleH2Timeouts(mplexer, now);
+#endif
auto timeouts = mplexer.getTimeouts(now);
for (const auto& timeout : timeouts) {
void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, size_t bodyLen, const char* contentType) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dnsquestion_set_extended_dns_error(dnsdist_ffi_dnsquestion_t* dnsQuestion, uint16_t infoCode, const char* extraText, size_t extraTextSize) __attribute__ ((visibility ("default")));
+
size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char** out) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char* data, size_t dataLen) __attribute__ ((visibility ("default")));
void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq)
{
- return dq->dq->getHeader();
+ return dq->dq->getMutableHeader();
}
uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq)
#ifdef HAVE_DNS_OVER_HTTPS
PacketBuffer bodyVect(body, body + bodyLen);
dq->dq->ids.du->setHTTPResponse(statusCode, std::move(bodyVect), contentType);
- dq->dq->getHeader()->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->dq->getMutableData(), [](dnsheader& header) {
+ header.qr = true;
+ return true;
+ });
#endif
}
+void dnsdist_ffi_dnsquestion_set_extended_dns_error(dnsdist_ffi_dnsquestion_t* dnsQuestion, uint16_t infoCode, const char* extraText, size_t extraTextSize)
+{
+ EDNSExtendedError ede;
+ ede.infoCode = infoCode;
+ if (extraText != nullptr && extraTextSize > 0) {
+ ede.extraText = std::string(extraText, extraTextSize);
+ }
+ dnsQuestion->dq->ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+}
+
void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode)
{
- dq->dq->getHeader()->rcode = rcode;
- dq->dq->getHeader()->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->dq->getMutableData(), [rcode](dnsheader& header) {
+ header.rcode = rcode;
+ header.qr = true;
+ return true;
+ });
}
void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t* dq, uint16_t len)
return false;
}
- auto oldId = reinterpret_cast<const dnsheader*>(query->query.d_buffer.data())->id;
+ dnsheader_aligned alignedHeader(query->query.d_buffer.data());
+ auto oldID = alignedHeader->id;
query->query.d_buffer.clear();
query->query.d_buffer.insert(query->query.d_buffer.begin(), raw, raw + rawSize);
- reinterpret_cast<dnsheader*>(query->query.d_buffer.data())->id = oldId;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(query->query.d_buffer, [oldID](dnsheader& header) {
+ header.id = oldID;
+ return true;
+ });
query->query.d_idstate.skipCache = true;
return dnsdist::queueQueryResumptionEvent(std::move(query));
constexpr bool response = std::is_same_v<T, Rings::Response>;
#if defined(DNSDIST_RINGS_WITH_MACADDRESS)
if constexpr (!response) {
- dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toString(), entry.hasmac ? std::string(reinterpret_cast<const char*>(entry.macaddress.data()), entry.macaddress.size()) : std::string(), entry.size, entry.qtype, entry.protocol, response};
+ dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), entry.hasmac ? std::string(reinterpret_cast<const char*>(entry.macaddress.data()), entry.macaddress.size()) : std::string(), entry.size, entry.qtype, entry.protocol, response};
list->d_entries.push_back(std::move(tmp));
}
else {
- dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toString(), std::string(), entry.size, entry.qtype, entry.protocol, response};
+ dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), std::string(), entry.size, entry.qtype, entry.protocol, response};
list->d_entries.push_back(std::move(tmp));
}
#else
- dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toString(), std::string(), entry.size, entry.qtype, entry.protocol, response};
+ dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), std::string(), entry.size, entry.qtype, entry.protocol, response};
list->d_entries.push_back(std::move(tmp));
#endif
}
{"latency-doh-avg1000", &latencyDoHAvg1000},
{"latency-doh-avg10000", &latencyDoHAvg10000},
{"latency-doh-avg1000000", &latencyDoHAvg1000000},
+ {"latency-doq-avg100", &latencyDoQAvg100},
+ {"latency-doq-avg1000", &latencyDoQAvg1000},
+ {"latency-doq-avg10000", &latencyDoQAvg10000},
+ {"latency-doq-avg1000000", &latencyDoQAvg1000000},
{"uptime", uptimeOfProcess},
{"real-memory-usage", getRealMemoryUsage},
{"special-memory-usage", getSpecialMemoryUsage},
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};
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>;
struct EntryPair
*/
#include "base64.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-nghttp2-in.hh"
#include "dnsdist-proxy-protocol.hh"
#include "dnsparser.hh"
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
#if 0
class IncomingDoHCrossProtocolContext : public CrossProtocolContext
if (responseDH.get()->tc && state.d_packet && state.d_packet->size() > state.d_proxyProtocolPayloadSize && state.d_packet->size() - state.d_proxyProtocolPayloadSize > sizeof(dnsheader)) {
vinfolog("Response received from backend %s via UDP, for query %d received from %s via DoH, is truncated, retrying over TCP", response.d_ds->getNameWithAddr(), state.d_streamID, state.origRemote.toStringWithPort());
auto& query = *state.d_packet;
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- auto* queryDH = reinterpret_cast<struct dnsheader*>(&query.at(state.d_proxyProtocolPayloadSize));
- /* restoring the original ID */
- queryDH->id = state.origID;
+ dnsdist::PacketMangling::editDNSHeaderFromRawPacket(&query.at(state.d_proxyProtocolPayloadSize), [origID = state.origID](dnsheader& header) {
+ /* restoring the original ID */
+ header.id = origID;
+ return true;
+ });
state.forwardedOverUDP = false;
bool proxyProtocolPayloadAdded = state.d_proxyProtocolPayloadSize > 0;
return !d_connectionDied && d_ioState != nullptr;
}
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
#pragma once
#include "config.h"
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
#include <nghttp2/nghttp2.h>
#include "dnsdist-tcp-upstream.hh"
static void addCustomDynamicHeader(std::vector<nghttp2_nv>& headers, const std::string& name, const std::string_view& value);
};
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
#include "config.h"
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
#include <nghttp2/nghttp2.h>
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
#include "dnsdist-nghttp2.hh"
#include "dnsdist-nghttp2-in.hh"
std::unique_ptr<DoHClientCollection> g_dohClientThreads{nullptr};
std::optional<uint16_t> g_outgoingDoHWorkerThreads{std::nullopt};
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
class DoHConnectionToBackend : public ConnectionToBackend
{
public:
return true;
}
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
struct DoHClientCollection::DoHWorkerThread
{
void DoHClientCollection::addThread()
{
-#ifdef HAVE_NGHTTP2
+#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);
errlog("Error creating the DoH channel: %s", e.what());
return;
}
-#else /* HAVE_NGHTTP2 */
+#else /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
throw std::runtime_error("DoHClientCollection::addThread() called but nghttp2 support is not available");
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
bool initDoHWorkers()
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
if (!g_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. */
return true;
#else
return false;
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
bool setupDoHClientProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
if (ctx == nullptr) {
return false;
}
-#ifdef HAVE_NGHTTP2
+#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_NGHTTP2 */
+#else /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
return false;
-#endif /* HAVE_NGHTTP2 */
+#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)
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
struct timeval now
{
.tv_sec = 0, .tv_usec = 0
}
return true;
-#else /* HAVE_NGHTTP2 */
+#else /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
return false;
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
size_t clearH2Connections()
{
size_t cleared = 0;
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
cleared = t_downstreamDoHConnectionsManager.clear();
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
return cleared;
}
size_t handleH2Timeouts(FDMultiplexer& mplexer, const struct timeval& now)
{
size_t got = 0;
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
auto expiredReadConns = mplexer.getTimeouts(now, false);
for (const auto& cbData : expiredReadConns) {
if (cbData.second.type() == typeid(std::shared_ptr<DoHConnectionToBackend>)) {
++got;
}
}
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
return got;
}
void setDoHDownstreamCleanupInterval(uint16_t max)
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
DownstreamDoHConnectionsManager::setCleanupInterval(max);
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
void setDoHDownstreamMaxIdleTime(uint16_t max)
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
DownstreamDoHConnectionsManager::setMaxIdleTime(max);
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
void setDoHDownstreamMaxIdleConnectionsPerBackend(size_t max)
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
DownstreamDoHConnectionsManager::setMaxIdleConnectionsPerDownstream(max);
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
throw std::runtime_error("Looking for a TXT record in an answer smaller than the DNS header");
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(answer.data());
+ const dnsheader_aligned dh(answer.data());
PacketReader pr(answer);
uint16_t qdcount = ntohs(dh->qdcount);
uint16_t ancount = ntohs(dh->ancount);
}
auto raw = unknownContent->getRawContent();
auto serial = getSerialFromRawSOAContent(raw);
- if (query.d_xfrMasterSerial == 0) {
+ if (query.d_xfrPrimarySerial == 0) {
// store the first SOA in our client's connection metadata
- query.d_xfrMasterSerial = serial;
- if (query.d_idstate.qtype == QType::IXFR && (query.d_xfrMasterSerial == query.d_ixfrQuerySerial || rfc1982LessThan(query.d_xfrMasterSerial, query.d_ixfrQuerySerial))) {
- /* This is the first message with a master SOA:
+ query.d_xfrPrimarySerial = serial;
+ if (query.d_idstate.qtype == QType::IXFR && (query.d_xfrPrimarySerial == query.d_ixfrQuerySerial || rfc1982LessThan(query.d_xfrPrimarySerial, query.d_ixfrQuerySerial))) {
+ /* This is the first message with a primary SOA:
RFC 1995 Section 2:
If an IXFR query with the same or newer version number
than that of the server is received, it is replied to
}
++query.d_xfrSerialCount;
- if (serial == query.d_xfrMasterSerial) {
- ++query.d_xfrMasterSerialCount;
- // figure out if it's end when receiving master's SOA again
+ if (serial == query.d_xfrPrimarySerial) {
+ ++query.d_xfrPrimarySerialCount;
+ // figure out if it's end when receiving primary's SOA again
if (query.d_xfrSerialCount == 2) {
// if there are only two SOA records marks a finished AXFR
done = true;
break;
}
- if (query.d_xfrMasterSerialCount == 3) {
- // receiving master's SOA 3 times marks a finished IXFR
+ if (query.d_xfrPrimarySerialCount == 3) {
+ // receiving primary's SOA 3 times marks a finished IXFR
done = true;
break;
}
std::string d_proxyProtocolPayload;
PacketBuffer d_buffer;
uint32_t d_ixfrQuerySerial{0};
- uint32_t d_xfrMasterSerial{0};
+ uint32_t d_xfrPrimarySerial{0};
uint32_t d_xfrSerialCount{0};
uint32_t d_downstreamFailures{0};
- uint8_t d_xfrMasterSerialCount{0};
+ uint8_t d_xfrPrimarySerialCount{0};
bool d_xfrStarted{false};
bool d_proxyProtocolPayloadAdded{false};
};
TCPQuery(std::move(buffer), std::move(state)), d_connection(std::move(conn)), d_ds(std::move(ds))
{
if (d_buffer.size() >= sizeof(dnsheader)) {
- memcpy(&d_cleartextDH, reinterpret_cast<const dnsheader*>(d_buffer.data()), sizeof(d_cleartextDH));
+ dnsheader_aligned header(d_buffer.data());
+ memcpy(&d_cleartextDH, header.get(), sizeof(d_cleartextDH));
}
else {
memset(&d_cleartextDH, 0, sizeof(d_cleartextDH));
TCPQuery(std::move(query))
{
if (d_buffer.size() >= sizeof(dnsheader)) {
- memcpy(&d_cleartextDH, reinterpret_cast<const dnsheader*>(d_buffer.data()), sizeof(d_cleartextDH));
+ dnsheader_aligned header(d_buffer.data());
+ memcpy(&d_cleartextDH, header.get(), sizeof(d_cleartextDH));
}
else {
memset(&d_cleartextDH, 0, sizeof(d_cleartextDH));
Since server-side sessions cannot be shared between several instances, and pretty much all clients support tickets anyway, we do recommend disabling the sessions by passing ``numberOfStoredSessions=0`` to the :func:`addDOHLocal` (for DNS over HTTPS) and :func:`addTLSLocal` (for DNS over TLS) functions.
-By default, dnsdist will generate a new, random STEK at startup and rotate it every 12 hours. It will keep 5 keys in memory, with only the last one marked as active and used to encrypt new tickets while the remaining ones can still be used to decrypt existing tickets after a rotation. The rotation time and the number of keys to keep in memory can be configured via the ``numberOfTicketsKeys`` and ``ticketsKeysRotationDelay`` parameters of the :func:`addDOHLocal` (for DNS over HTTPS) and :func:`addTLSLocal` (for DNS over TLS) functions.
+By default, dnsdist will generate a new, random STEK at startup for each :func:`addTLSLocal` and :func:`addDOHLocal` directive, and rotate these STEKs every 12 hours. For each frontend it will keep 5 keys in memory, with only the last one marked as active and used to encrypt new tickets while the remaining ones can still be used to decrypt existing tickets after a rotation. The rotation time and the number of keys to keep in memory can be configured via the ``numberOfTicketsKeys`` and ``ticketsKeysRotationDelay`` parameters of the :func:`addDOHLocal` (for DNS over HTTPS) and :func:`addTLSLocal` (for DNS over TLS) functions.
+When the automatic rotation mechanism kicks in a new, random key will be added to the list of keys. With the OpenSSL provider, the new key becomes active, so new tickets will be encrypted with this key, and the existing keys become passive and only be used to decrypt existing tickets. With the GnuTLS provider only one key is currently supported so the existing keys are immediately discarded.
+This automatic rotation can be disabled by setting ``ticketsKeysRotationDelay`` to 0.
It is also possible to manually request a STEK rotation using the :func:`getDOHFrontend` (DoH) and :func:`getTLSContext` (DoT) functions to retrieve the bind object, and calling its ``rotateTicketsKey`` method (:meth:`DOHFrontend:rotateTicketsKey`, :meth:`TLSContext:rotateTicketsKey`).
-The default settings should be fine for most deployments, but generating a random key for every dnsdist instance will not allow resuming the session from a different instance in a cluster. In that case it is possible to generate the STEK outside of dnsdist, write it to a file, distribute it to all instances using something like rsync over SSH, and load that file from dnsdist. Please remember that the STEK contains very sensitive data, and should be well-protected from access by unauthorized users. It means that special care should be taken to setting the right permissions on that file.
+The default settings should be fine for most deployments, but generating a random key for every dnsdist instance will not allow resuming the session from a different instance in a cluster. It is also not very useful to have a different key for every :func:`addTLSLocal` and :func:`addDOHLocal` directive if you are using the same certificate and key, and it would be much better to use the same STEK to improve the session resumption ratio.
+
+In that case it is possible to generate the STEK outside of dnsdist, write it to a file, distribute it to all instances using something like rsync over SSH, and load that file from dnsdist. Please remember that the STEK contains very sensitive data, and should be well-protected from access by unauthorized users. It means that special care should be taken to setting the right permissions on that file. Automatic rotation should then be disabled by setting ``ticketsKeysRotationDelay`` to 0.
For the OpenSSL provider (DoT, DoH), generating a random STEK in a file is a simple as getting 80 cryptographically secure random bytes and writing them to a file::
If the file contains several keys, so for example 240 random bytes, dnsdist will load several STEKs, using the last one for encrypting new tickets and all of them to decrypt existing tickets.
In order to rotate the keys at runtime, it is possible to instruct dnsdist to reload the content of the certificates, keys, and STEKs from the same file used at configuration time, for all DoH and DoH binds, by issuing the :func:`reloadAllCertificates` command.
-It can also be done one bind at a time using the :func:`getDOHFrontend` (DoH) and :func:`getTLSContext` (DoT) functions to retrieve the bind object, and calling its ``loadTicketsKeys`` method (:meth:`DOHFrontend.loadTicketsKeys`, :meth:`TLSContext:loadTicketsKeys`).
+It can also be done one bind at a time using the :func:`getDOHFrontend` (DoH) and :func:`getTLSContext` (DoT) functions to retrieve the bind object, and calling its ``loadTicketsKeys`` method (:meth:`DOHFrontend:loadTicketsKeys`, :meth:`TLSContext:loadTicketsKeys`).
+
+One possible way of handling manual rotation of the key would be to first:
+
+- generate ``N`` keys in ``N`` (``1..N``) separate files (for example executing ``dd if=/dev/urandom of=/secure-tmp-fs/N.key bs=80 count=1`` ``N`` times)
+- concatenate the ``N`` files into a single file (``/secure-tmp-fs/STEKs.key``) that you pass to dnsdist's ``ticketKeyFile`` parameter
+
+Then, when the STEK should be rotated:
+
+- generate one new key file (``N+1``)
+- delete the first key file (``1``)
+- concatenate the ``2..N+1`` files into one (``/secure-tmp-fs/STEKs.key``)
+- issue :func:`reloadAllCertificates` via the dnsdist console, or call ``loadTicketsKeys('/secure-tmp-fs/STEKs.key')`` for all frontends
+
+This way dnsdist can still decrypt incoming tickets that were encoded via the previous key (the active one is always the one at the end of the file, and we start by removing the one at the beginning of the file).
Content of the STEK file
------------------------
* supported ciphers depend on the exact kernel version used. ``TLS_AES_128_GCM_SHA256`` might be a good option for testing purpose since it was supported pretty early
* as of OpenSSL 3.0.7, kTLS can only be used for sending TLS 1.3 packets, not receiving them. Both sending and receiving packets should be working for TLS 1.2.
+TLS performance
+---------------
+
+For DNS over HTTPS and DNS over TLS, in addition to the advice above we suggest reading the :doc:`tls-sessions-management` page to learn how to improve TLS session resumption ratio, which has a huge impact on CPU usage and latency.
Rules and Lua
-------------
Changelog
=========
+.. changelog::
+ :version: 1.9.0-alpha3
+ :released: 20th of October 2023
+
+ Please review the :doc:`Upgrade Guide <../upgrade_guide>` before upgrading.
+
+ .. change::
+ :tags: New Features, Protobuf
+ :pullreq: 13185
+
+ Log Extended DNS Errors (EDE) to protobuf
+
+ .. change::
+ :tags: Bugs Fixes
+ :pullreq: 13274
+
+ Enable back h2o support in our packages
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13275
+ :tickets: 13201
+
+ Add Lua binding to downstream address (Denis Machard)
+
+ .. change::
+ :tags: New Features, DNS over QUIC
+ :pullreq: 13280
+
+ Add support for incoming DNS over QUIC
+
+ .. change::
+ :tags: Bugs Fixes, DNS over HTTPS
+ :pullreq: 13298
+
+ Fix timeouts on incoming DoH connections with nghttp2
+
+ .. change::
+ :tags: Bug Fixes, Metrics
+ :pullreq: 13302
+
+ Fix a typo in 'Client timeouts' (phonedph1)
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13305
+
+ Set proper levels when logging messages
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13310
+
+ Fix several cosmetic issues in eBPF dynamic blocks, update documentation
+
+ .. change::
+ :tags: Improvements, Webserver
+ :pullreq: 13335
+
+ Display the rule name, if any, in the web interface
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13340
+
+ Netmask: Normalize subnet masks coming from a string
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13372
+ :tickets: 13280
+
+ Prevent DNS header alignment issues
+
+.. changelog::
+ :version: 1.9.0-alpha2
+ :released: Never
+
+ This version was never released due to a last-minute issue in RPM packaging.
+
.. changelog::
:version: 1.8.2
:released: 11th of October 2023
changelog_render_changeset = "https://github.com/PowerDNS/pdns/commit/%s"
changelog_sections = ['New Features', 'Improvements', 'Bug Fixes', 'Removals']
-changelog_inner_tag_sort = ['Security', 'DNS over HTTPS', 'DNS over TLS', 'DNSCrypt', 'DNSTAP', 'Protobuf', 'Performance', 'Webserver', 'Metrics']
+changelog_inner_tag_sort = ['Security', 'DNS over QUIC', 'DNS over HTTPS', 'DNS over TLS', 'DNSCrypt', 'DNSTAP', 'Protobuf', 'Performance', 'Webserver', 'Metrics']
changelog_hide_tags_in_entry = True
:>json list: A list of metrics related to that pool
:>json list servers: A list of :json:object:`Server` objects present in that pool
+.. http:get:: /api/v1/servers/localhost/rings?maxQueries=NUM&maxResponses=NUM
+
+ .. versionadded:: 1.9.0
+
+ Get the most recent queries and responses from the in-memory ring buffers. Returns up to ``maxQueries``
+ query entries if set, up to ``maxResponses`` responses if set, and the whole content of the ring buffers otherwise.
+
+ :>json list queries: The list of the most recent queries, as :json:object:`RingEntry` objects
+ :>json list responses: The list of the most recent responses, as :json:object:`RingEntry` objects
+
JSON Objects
~~~~~~~~~~~~
:property string name: The name of this statistic. See :doc:`../statistics`
:property string type: "StatisticItem"
:property integer value: The value for this item
+
+.. json:object:: RingEntry
+
+ This represents an entry in the in-memory ring buffers.
+
+ :property float age: How long ago was the query or response received, in seconds
+ :property integer id: The DNS ID
+ :property string name: The requested domain name
+ :property string requestor: The client IP and port
+ :property integer size: The size of the query or response
+ :property integer qtype: The requested DNS type
+ :property string protocol: The DNS protocol the query or response was received over
+ :property boolean rd: The RD flag
+ :property string mac: The MAC address of the device sending the query
+ :property float latency: The time it took for the response to be sent back to the client, in microseconds
+ :property int rcode: The response code
+ :property boolean tc: The TC flag
+ :property boolean aa: The AA flag
+ :property integer answers: The number of records in the answer section of the response
+ :property string backend: The IP and port of the backend that returned the response, or "Cache" if it was a cache-hit
* `protobuf <https://developers.google.com/protocol-buffers/>`_ (optional, not needed as of 1.6.0)
* `quiche <https://github.com/cloudflare/quiche>`_ (optional, incoming DoQ support)
* `re2 <https://github.com/google/re2>`_ (optional)
-* `TinyCDB <https://www.corpit.ru/mjt/tinycdb.html>` (optional, CDB support)
+* `TinyCDB <https://www.corpit.ru/mjt/tinycdb.html>`_ (optional, CDB support)
Should :program:`dnsdist` be run on a system with systemd, it is highly recommended to have
the systemd header files (``libsystemd-dev`` on Debian and ``systemd-devel`` on CentOS)
* ``minTLSVersion``: str - Minimum version of the TLS protocol to support. Possible values are 'tls1.0', 'tls1.1', 'tls1.2' and 'tls1.3'. Default is to require at least TLS 1.0.
* ``numberOfTicketsKeys``: int - The maximum number of tickets keys to keep in memory at the same time. Only one key is marked as active and used to encrypt new tickets while the remaining ones can still be used to decrypt existing tickets after a rotation. Default to 5.
* ``ticketKeyFile``: str - The path to a file from where TLS tickets keys should be loaded, to support :rfc:`5077`. These keys should be rotated often and never written to persistent storage to preserve forward secrecy. The default is to generate a random key. dnsdist supports several tickets keys to be able to decrypt existing sessions after the rotation. See :doc:`../advanced/tls-sessions-management` for more information.
- * ``ticketsKeysRotationDelay``: int - Set the delay before the TLS tickets key is rotated, in seconds. Default is 43200 (12h).
+ * ``ticketsKeysRotationDelay``: int - Set the delay before the TLS tickets key is rotated, in seconds. Default is 43200 (12h). A value of 0 disables the automatic rotation, which might be useful when ``ticketKeyFile`` is used.
* ``sessionTimeout``: int - Set the TLS session lifetime in seconds, this is used both for TLS ticket lifetime and for sessions kept in memory.
* ``sessionTickets``: bool - Whether session resumption via session tickets is enabled. Default is true, meaning tickets are enabled.
* ``numberOfStoredSessions``: int - The maximum number of sessions kept in memory at the same time. Default is 20480. Setting this value to 0 disables stored session entirely.
* ``ciphersTLS13``: str - The ciphers to use for TLS 1.3, when the OpenSSL provider is used. When the GnuTLS provider is used, ``ciphers`` applies regardless of the TLS protocol and this setting is not used.
* ``numberOfTicketsKeys``: int - The maximum number of tickets keys to keep in memory at the same time, if the provider supports it (GnuTLS doesn't, OpenSSL does). Only one key is marked as active and used to encrypt new tickets while the remaining ones can still be used to decrypt existing tickets after a rotation. Default to 5.
* ``ticketKeyFile``: str - The path to a file from where TLS tickets keys should be loaded, to support :rfc:`5077`. These keys should be rotated often and never written to persistent storage to preserve forward secrecy. The default is to generate a random key. The OpenSSL provider supports several tickets keys to be able to decrypt existing sessions after the rotation, while the GnuTLS provider only supports one key. See :doc:`../advanced/tls-sessions-management` for more information.
- * ``ticketsKeysRotationDelay``: int - Set the delay before the TLS tickets key is rotated, in seconds. Default is 43200 (12h).
+ * ``ticketsKeysRotationDelay``: int - Set the delay before the TLS tickets key is rotated, in seconds. Default is 43200 (12h). A value of 0 disables the automatic rotation, which might be useful when ``ticketKeyFile`` is used.
* ``sessionTimeout``: int - Set the TLS session lifetime in seconds, this is used both for TLS ticket lifetime and for sessions kept in memory.
* ``sessionTickets``: bool - Whether session resumption via session tickets is enabled. Default is true, meaning tickets are enabled.
* ``numberOfStoredSessions``: int - The maximum number of sessions kept in memory at the same time. At this time this is only supported by the OpenSSL provider, as stored sessions are not supported with the GnuTLS one. Default is 20480. Setting this value to 0 disables stored session entirely.
:param list netmasks: A :class:`NetmaskGroup` object, or a netmask or list of netmasks as strings, like for example "192.0.2.1/24"
+ .. method:: DynBlockRulesGroup:removeRange(netmasks)
+
+ .. versionadded:: 1.9.0
+
+ Remove a previously included or excluded range. The range should be an exact match of the existing entry to remove.
+
+ :param list netmasks: A :class:`NetmaskGroup` object, or a netmask or list of netmasks as strings, like for example "192.0.2.1/24"
+
.. method:: DynBlockRulesGroup:toString()
Return a string describing the rules and range exclusions of this DynBlockRulesGroup.
:param str path: The path to the file, usually /etc/resolv.conf
+.. function:: getStatisticsCounters()
+
+ This function returns a Lua associative array of metrics, with the metric name as key and the current value
+ of the counter as value.
+
.. function:: maintenance()
If this function exists, it is called every second to do regular tasks.
:param int code: The EDNS option code
:param string data: The EDNS option raw data
+ .. method:: DNSQuestion:setExtendedDNSError(infoCode [, extraText])
+
+ .. versionadded:: 1.9.0
+
+ Set an Extended DNS Error status that will be added to the response corresponding to the current query.
+
+ :param int infoCode: The EDNS Extended DNS Error code
+ :param string extraText: The optional EDNS Extended DNS Error extra text
+
.. method:: DNSQuestion:setHTTPResponse(status, body, contentType="")
.. versionadded:: 1.4.0
- :func:`NoneAction`
- :func:`RemoteLogAction`
- :func:`RemoteLogResponseAction`
-- :func:`SetMaxReturnedTTLResponseAction`
-- :func:`SetMaxReturnedTTLAction`
-- :func:`SetMinTTLResponseAction`
-- :func:`SetMaxTTLResponseAction`
- :func:`SNMPTrapAction`
- :func:`SNMPTrapResponseAction`
- :func:`TeeAction`
:param int option: The EDNS option number
:param string data: The EDNS0 option raw content
+.. function:: SetExtendedDNSErrorAction(infoCode [, extraText])
+
+ .. versionadded:: 1.9.0
+
+ Set an Extended DNS Error status that will be added to the response corresponding to the current query.
+ Subsequent rules are processed after this action.
+
+ :param int infoCode: The EDNS Extended DNS Error code
+ :param string extraText: The optional EDNS Extended DNS Error extra text
+
+.. function:: SetExtendedDNSErrorResponseAction(infoCode [, extraText])
+
+ .. versionadded:: 1.9.0
+
+ Set an Extended DNS Error status that will be added to this response.
+ Subsequent rules are processed after this action.
+
+ :param int infoCode: The EDNS Extended DNS Error code
+ :param string extraText: The optional EDNS Extended DNS Error extra text
+
.. function:: SetMacAddrAction(option)
.. versionadded:: 1.6.0
----------------------
Number of responses dropped because the internal DoH pipe was full.
+doq-response-pipe-full
+----------------------
+Number of responses dropped because the internal DoQ pipe was full.
+
downstream-send-errors
----------------------
Number of errors when sending a query to a backend.
----------------------
Average response latency, in microseconds, of the last 1000000 packets received over DoH.
+latency-doq-avg100
+------------------
+Average response latency, in microseconds, of the last 100 packets received over DoQ.
+
+latency-doq-avg1000
+-------------------
+Average response latency, in microseconds, of the last 1000 packets received over DoQ.
+
+latency-doq-avg10000
+--------------------
+Average response latency, in microseconds, of the last 10000 packets received over DoQ.
+
+latency-doq-avg1000000
+----------------------
+Average response latency, in microseconds, of the last 1000000 packets received over DoQ.
+
latency-dot-avg100
------------------
Average response latency, in microseconds, of the last 100 packets received over DoT.
#include "dns.hh"
#include "dolog.hh"
#include "dnsdist-concurrent-connections.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-metrics.hh"
#include "dnsdist-proxy-protocol.hh"
DNSResponse dr(dohUnit->ids, dohUnit->response, dohUnit->downstream);
dnsheader cleartextDH{};
- memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH));
+ memcpy(&cleartextDH, dr.getHeader().get(), sizeof(cleartextDH));
if (!response.isAsync()) {
static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localRespRuleActions = g_respruleactions.getLocal();
{
/* don't keep that pointer around, it will be invalidated if the buffer is ever resized */
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- auto* dnsHeader = reinterpret_cast<struct dnsheader*>(unit->query.data());
+ const dnsheader_aligned dnsHeader(unit->query.data());
- if (!checkQueryHeaders(dnsHeader, clientState)) {
+ if (!checkQueryHeaders(dnsHeader.get(), clientState)) {
unit->status_code = 400;
handleImmediateResponse(std::move(unit), "DoH invalid headers");
return;
}
if (dnsHeader->qdcount == 0U) {
- dnsHeader->rcode = RCode::NotImp;
- dnsHeader->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(unit->query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
unit->response = std::move(unit->query);
handleImmediateResponse(std::move(unit), "DoH empty query");
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
ids.qname = DNSName(reinterpret_cast<const char*>(unit->query.data()), static_cast<int>(unit->query.size()), static_cast<int>(sizeof(dnsheader)), false, &ids.qtype, &ids.qclass);
DNSQuestion dnsQuestion(ids, unit->query);
- const uint16_t* flags = getFlagsFromDNSHeader(dnsQuestion.getHeader());
+ const uint16_t* flags = getFlagsFromDNSHeader(dnsQuestion.getHeader().get());
ids.origFlags = *flags;
ids.cs = &clientState;
dnsQuestion.sni = std::move(unit->sni);
/* this moves du->ids, careful! */
auto cpq = std::make_unique<DoHCrossProtocolQuery>(std::move(unit), false);
+ if (!cpq) {
+ // make linters happy
+ return;
+ }
cpq->query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
if (downstream->passCrossProtocolQuery(std::move(cpq))) {
dohUnit->query.size() > dohUnit->ids.d_proxyProtocolPayloadSize &&
(dohUnit->query.size() - dohUnit->ids.d_proxyProtocolPayloadSize) > sizeof(dnsheader)) {
/* restoring the original ID */
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- auto* queryDH = reinterpret_cast<struct dnsheader*>(&dohUnit->query.at(dohUnit->ids.d_proxyProtocolPayloadSize));
- queryDH->id = dohUnit->ids.origID;
+ dnsdist::PacketMangling::editDNSHeaderFromRawPacket(&dohUnit->query.at(dohUnit->ids.d_proxyProtocolPayloadSize), [oldID=dohUnit->ids.origID](dnsheader& header) {
+ header.id = oldID;
+ return true;
+ });
dohUnit->ids.forwardedOverUDP = false;
dohUnit->tcp = true;
dohUnit->truncated = false;
DNSResponse dnsResponse(dohUnit->ids, udpResponse, dohUnit->downstream);
dnsheader cleartextDH{};
- memcpy(&cleartextDH, dnsResponse.getHeader(), sizeof(cleartextDH));
+ memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
dnsResponse.ids.du = std::move(dohUnit);
if (!processResponse(udpResponse, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
DNSResponse dnsResponse(unit->ids, unit->response, unit->downstream);
dnsheader cleartextDH{};
- memcpy(&cleartextDH, dnsResponse.getHeader(), sizeof(cleartextDH));
+ memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
if (!response.isAsync()) {
</tr></table>
<p>
Uptime: <span id="uptime"></span>, Number of queries: <span id="questions"></span> (<span id="qps"></span> qps), ACL drops: <span id="acl-drops"></span>, Dynamic drops: <span id="dyn-drops"></span>, Rule drops: <span id="rule-drops"></span><br/>
- Average response time: UDP <span id="latency"></span> ms, TCP <span id="latency-tcp"></span> ms, DoT <span id="latency-dot"></span> ms, DoH <span id="latency-doh"></span> ms <br/>
+ Average response time: UDP <span id="latency"></span> ms, TCP <span id="latency-tcp"></span> ms, DoT <span id="latency-dot"></span> ms, DoH <span id="latency-doh"></span> ms, DoQ <span id="latency-doq"></span> ms <br/>
CPU Usage: <span id="cpu"></span>%, Cache hitrate: <span id="phitrate"></span>%, Server selection policy: <span id="server-policy"></span><br/>
Listening on: <span id="local"></span>, ACL: <span id="acl"></span>
</p>
$("#latency-tcp").text((data["latency-tcp-avg10000"]/1000.0).toFixed(2));
$("#latency-dot").text((data["latency-dot-avg10000"]/1000.0).toFixed(2));
$("#latency-doh").text((data["latency-doh-avg10000"]/1000.0).toFixed(2));
+ $("#latency-doq").text((data["latency-doq-avg10000"]/1000.0).toFixed(2));
if(!gdata["cpu-sys-msec"])
gdata=data;
AC_DEFUN([DNSDIST_ENABLE_DNS_OVER_QUIC], [
- AC_MSG_CHECKING([whether to enable incoming DNS over QUIC (DoH) support])
+ AC_MSG_CHECKING([whether to enable incoming DNS over QUIC (DoQ) support])
AC_ARG_ENABLE([dns-over-quic],
AS_HELP_STRING([--enable-dns-over-quic], [enable incoming DNS over QUIC (DoQ) support (requires quiche) @<:@default=no@:>@]),
[enable_dns_over_quic=$enableval],
AS_IF([test "x$with_quiche" != "xno"], [
AS_IF([test "x$with_quiche" = "xyes" -o "x$with_quiche" = "xauto"], [
- PKG_CHECK_MODULES([QUICHE], [quiche], [
+ PKG_CHECK_MODULES([QUICHE], [quiche >= 0.15.0], [
[HAVE_QUICHE=1]
AC_DEFINE([HAVE_QUICHE], [1], [Define to 1 if you have quiche])
], [ : ])
BOOST_CHECK_EQUAL(record.d_name, target);
BOOST_CHECK_EQUAL(record.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(record.d_ttl, 7200);
+ BOOST_CHECK_EQUAL(record.d_ttl, 7200U);
BOOST_CHECK_EQUAL(record.d_place, 1U);
BOOST_CHECK_GE(record.d_contentOffset, lastOffset);
lastOffset = record.d_contentOffset + record.d_contentLength;
ids.queryRealTime.start();
DNSQuestion dq(ids, query);
packetCache->get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
- packetCache->insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ packetCache->insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
std::string poolName("test-pool");
auto testPool = std::make_shared<ServerPool>();
for (size_t idx = 0; idx < 2; idx++) {
BOOST_CHECK(dnsdist_ffi_ring_entry_get_name(list, idx) == qname.toString());
BOOST_CHECK(dnsdist_ffi_ring_entry_get_type(list, idx) == qtype);
- BOOST_CHECK(dnsdist_ffi_ring_entry_get_requestor(list, idx) == requestor1.toString());
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_requestor(list, idx) == requestor1.toStringWithPort());
BOOST_CHECK(dnsdist_ffi_ring_entry_get_protocol(list, idx) == protocol.toNumber());
BOOST_CHECK_EQUAL(dnsdist_ffi_ring_entry_get_size(list, idx), size);
BOOST_CHECK(!dnsdist_ffi_ring_entry_has_mac_address(list, idx));
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-nghttp2-in.hh"
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
#include <nghttp2/nghttp2.h>
extern std::function<ProcessQueryResult(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)> s_processQuery;
}
BOOST_AUTO_TEST_SUITE_END();
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
#include "dnsdist-nghttp2.hh"
#include "sstuff.hh"
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
#include <nghttp2/nghttp2.h>
BOOST_AUTO_TEST_SUITE(test_dnsdistnghttp2_cc)
auto& query = conn->d_queries.at(frame->hd.stream_id);
BOOST_REQUIRE_GT(query.size(), sizeof(dnsheader));
- auto dh = reinterpret_cast<const dnsheader*>(query.data());
+ const dnsheader_aligned dh(query.data());
uint16_t id = ntohs(dh->id);
// cerr<<"got query ID "<<id<<endl;
}
BOOST_REQUIRE_GT(response.d_buffer.size(), sizeof(dnsheader));
- auto dh = reinterpret_cast<const dnsheader*>(response.d_buffer.data());
+ const dnsheader_aligned dh(response.d_buffer.data());
uint16_t id = ntohs(dh->id);
BOOST_REQUIRE_EQUAL(id, d_id);
}
BOOST_AUTO_TEST_SUITE_END();
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
PacketReader pr(std::string_view(reinterpret_cast<const char*>(packet.data()), packet.size()), packet.size() - serialized.size() - sizeof(dnsrecordheader));
/* needed to get the record boundaries right */
pr.getDnsrecordheader(drh);
- auto content = DNSRecordContent::mastermake(dr, pr, Opcode::Query);
+ auto content = DNSRecordContent::make(dr, pr, Opcode::Query);
return content;
}
-std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &dr,
- PacketReader& pr)
+std::shared_ptr<DNSRecordContent> DNSRecordContent::make(const DNSRecord& dr,
+ PacketReader& pr)
{
uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
return i->second(dr, pr);
}
-std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
- const string& content)
+std::shared_ptr<DNSRecordContent> DNSRecordContent::make(uint16_t qtype, uint16_t qclass,
+ const string& content)
{
auto i = getZmakermap().find(pair(qclass, qtype));
if(i==getZmakermap().end()) {
return i->second(content);
}
-std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t oc) {
+std::shared_ptr<DNSRecordContent> DNSRecordContent::make(const DNSRecord& dr, PacketReader& pr, uint16_t oc)
+{
// For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is
// not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent.
// For section 3.2.3, we do need content so we need to get it properly. But only for the correct QClasses.
d_class = rr.qclass;
d_place = DNSResourceRecord::ANSWER;
d_clen = 0;
- d_content = DNSRecordContent::mastermake(d_type, rr.qclass, rr.content);
+ d_content = DNSRecordContent::make(d_type, rr.qclass, rr.content);
}
// If you call this and you are not parsing a packet coming from a socket, you are doing it wrong.
}
else {
// cerr<<"parsing RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
- dr.setContent(DNSRecordContent::mastermake(dr, pr, d_header.opcode));
+ dr.setContent(DNSRecordContent::make(dr, pr, d_header.opcode));
}
/* XXX: XPF records should be allowed after TSIG as soon as the actual XPF option code has been assigned:
}
try {
- auto dh = reinterpret_cast<const dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
DNSPacketMangler dpm(const_cast<char*>(reinterpret_cast<const char*>(packet.data())), length);
const uint16_t qdcount = ntohs(dh->qdcount);
return EINVAL;
}
try {
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
+ const dnsheader_aligned dh(initialPacket.data());
if (ntohs(dh->qdcount) == 0)
return ENOENT;
}
try
{
- const dnsheader* dh = (const dnsheader*) packet;
+ const dnsheader_aligned dh(packet);
DNSPacketMangler dpm(const_cast<char*>(packet), length);
const uint16_t qdcount = ntohs(dh->qdcount);
}
try
{
- const dnsheader* dh = reinterpret_cast<const dnsheader*>(packet);
+ const dnsheader_aligned dh(packet);
DNSPacketMangler dpm(const_cast<char*>(packet), length);
const uint16_t qdcount = ntohs(dh->qdcount);
}
try
{
- const dnsheader* dh = (const dnsheader*) packet;
+ const dnsheader_aligned dh(packet);
DNSPacketMangler dpm(const_cast<char*>(packet), length);
const uint16_t qdcount = ntohs(dh->qdcount);
try
{
- const dnsheader* dh = (const dnsheader*) packet;
+ const dnsheader_aligned dh(packet);
DNSPacketMangler dpm(const_cast<char*>(packet), length);
const uint16_t qdcount = ntohs(dh->qdcount);
try
{
- dnsheader dh;
- memcpy(&dh, reinterpret_cast<const dnsheader*>(packet.data()), sizeof(dh));
- uint64_t numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount);
+ const dnsheader_aligned dh(packet.data());
+ uint64_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount);
PacketReader reader(packet);
uint64_t n;
- for (n = 0; n < ntohs(dh.qdcount) ; ++n) {
+ for (n = 0; n < ntohs(dh->qdcount) ; ++n) {
(void) reader.getName();
/* type and class */
reader.skip(4);
for (n = 0; n < numrecords; ++n) {
(void) reader.getName();
- uint8_t section = n < ntohs(dh.ancount) ? 1 : (n < (ntohs(dh.ancount) + ntohs(dh.nscount)) ? 2 : 3);
+ uint8_t section = n < ntohs(dh->ancount) ? 1 : (n < (ntohs(dh->ancount) + ntohs(dh->nscount)) ? 2 : 3);
uint16_t dnstype = reader.get16BitInt();
uint16_t dnsclass = reader.get16BitInt();
class DNSRecordContent
{
public:
- static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr);
- static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t opcode);
- static std::shared_ptr<DNSRecordContent> mastermake(uint16_t qtype, uint16_t qclass, const string& zone);
+ static std::shared_ptr<DNSRecordContent> make(const DNSRecord& dr, PacketReader& pr);
+ static std::shared_ptr<DNSRecordContent> make(const DNSRecord& dr, PacketReader& pr, uint16_t opcode);
+ static std::shared_ptr<DNSRecordContent> make(uint16_t qtype, uint16_t qclass, const string& zone);
static string upgradeContent(const DNSName& qname, const QType& qtype, const string& content);
virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
bool doIPv6 = g_vm["ipv6"].as<bool>();
bool doServFailTree = g_vm.count("servfail-tree");
bool noservfailstats = g_vm.count("no-servfail-stats");
- int dnserrors=0, parsefail=0;
+ int dnserrors = 0;
+ int parsefail = 0;
typedef map<uint32_t,uint32_t> cumul_t;
cumul_t cumul;
- unsigned int untracked=0, errorresult=0, nonRDQueries=0, queries=0;
- unsigned int ipv4DNSPackets=0, ipv6DNSPackets=0, fragmented=0, rdNonRAAnswers=0;
- unsigned int answers=0, nonDNSIP=0, rdFilterMismatch=0;
- unsigned int dnssecOK=0, edns=0;
- unsigned int dnssecCD=0, dnssecAD=0;
- unsigned int reuses=0;
+ unsigned int untracked = 0;
+ unsigned int nonRDQueries = 0;
+ unsigned int queries = 0;
+ unsigned int ipv4DNSPackets = 0;
+ unsigned int ipv6DNSPackets = 0;
+ unsigned int fragmented = 0;
+ unsigned int rdNonRAAnswers = 0;
+ unsigned int answers = 0;
+ unsigned int nonDNSIP = 0;
+ unsigned int rdFilterMismatch = 0;
+ unsigned int dnssecOK = 0;
+ unsigned int edns = 0;
+ unsigned int dnssecCD = 0;
+ unsigned int dnssecAD = 0;
+ unsigned int reuses = 0;
typedef map<uint16_t,uint32_t> rcodes_t;
rcodes_t rcodes;
if(!noservfailstats || header.rcode != 2)
cumul[usecs]++;
- if(header.rcode != 0 && header.rcode!=3)
- errorresult++;
ComboAddress rem = pr.getDest();
rem.sin4.sin_port=0;
bool unsetPublishCDS(const DNSName& zname);
bool TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname);
- bool getTSIGForAccess(const DNSName& zone, const ComboAddress& master, DNSName* keyname);
+ bool getTSIGForAccess(const DNSName& zone, const ComboAddress& primary, DNSName* keyname);
void startTransaction(const DNSName& zone, int zone_id)
{
rrc.d_signature = rc->sign(msg);
(*g_signatureCount)++;
if(doCache) {
- /* we add some jitter here so not all your slaves start pruning their caches at the very same millisecond */
+ /* we add some jitter here so not all your secondaries start pruning their caches at the very same millisecond */
int weekno = (time(nullptr) - dns_random(3600)) / (86400*7); // we just spent milliseconds doing a signature, microsecond more won't kill us
const static int maxcachesize=::arg().asNum("max-signature-cache-entries", INT_MAX);
}
if (packet != nullptr && len >= sizeof(dnsheader)) {
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+ const dnsheader_aligned dh(packet);
if (!dh->qr) {
pbf_message.add_bytes(DnstapMessageFields::query_message, packet, len);
} else {
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
#include <boost/accumulators/statistics/median.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/accumulators.hpp>
-
#include <boost/accumulators/statistics.hpp>
+#pragma GCC diagnostic pop
#include <thread>
}
template<typename T, typename... Args>
-void dolog(std::ostream& os, const char* s, T value, Args... args)
+void dolog(std::ostream& os, const char* s, T value, const Args&... args)
{
while (*s) {
if (*s == '%') {
}
template<typename... Args>
-void genlog(std::ostream& stream, int level, bool doSyslog, const char* s, Args... args)
+void genlog(std::ostream& stream, int level, bool doSyslog, const char* s, const Args&... args)
{
std::ostringstream str;
dolog(str, s, args...);
}
template<typename... Args>
-void verboselog(const char* s, Args... args)
+void verboselog(const char* s, const Args&... args)
{
#ifdef DNSDIST
if (g_verboseStream) {
#define vinfolog if (g_verbose) verboselog
template<typename... Args>
-void infolog(const char* s, Args... args)
+void infolog(const char* s, const Args&... args)
{
genlog(std::cout, LOG_INFO, g_syslog, s, args...);
}
template<typename... Args>
-void warnlog(const char* s, Args... args)
+void warnlog(const char* s, const Args&... args)
{
genlog(std::cout, LOG_WARNING, g_syslog, s, args...);
}
template<typename... Args>
-void errlog(const char* s, Args... args)
+void errlog(const char* s, const Args&... args)
{
genlog(std::cout, LOG_ERR, g_syslog, s, args...);
}
}
template<typename T, typename... Args>
-void dolog(Logger::Urgency u, const char* s, T value, Args... args)
+void dolog(Logger::Urgency u, const char* s, T value, const Args&... args)
{
g_log << u;
while (*s) {
#define vinfolog if(g_verbose)infolog
template<typename... Args>
-void infolog(const char* s, Args... args)
+void infolog(const char* s, const Args&... args)
{
dolog(Logger::Info, s, args...);
}
template<typename... Args>
-void warnlog(const char* s, Args... args)
+void warnlog(const char* s, const Args&... args)
{
dolog(Logger::Warning, s, args...);
}
template<typename... Args>
-void errlog(const char* s, Args... args)
+void errlog(const char* s, const Args&... args)
{
dolog(Logger::Error, s, args...);
}
return "Failed to parse zone as valid DNS name";
}
- ComboAddress master_ip;
- bool override_master = false;
+ ComboAddress primary_ip;
+ bool override_primary = false;
if (parts.size() == 3) {
try {
- master_ip = ComboAddress{parts[2], 53};
+ primary_ip = ComboAddress{parts[2], 53};
} catch (...) {
return "Invalid primary address";
}
- override_master = true;
+ override_primary = true;
}
DomainInfo di;
return " Zone '" + domain.toString() + "' unknown";
}
- if (override_master) {
- di.masters.clear();
- di.masters.push_back(master_ip);
+ if (override_primary) {
+ di.primaries.clear();
+ di.primaries.push_back(primary_ip);
}
- if (!override_master && (!di.isSecondaryType() || di.masters.empty()))
+ if (!override_primary && (!di.isSecondaryType() || di.primaries.empty()))
return "Zone '" + domain.toString() + "' is not a secondary/consumer zone (or has no primary defined)";
- shuffle(di.masters.begin(), di.masters.end(), pdns::dns_random_engine());
- const auto& master = di.masters.front();
- Communicator.addSuckRequest(domain, master, SuckRequest::PdnsControl, override_master);
- g_log << Logger::Warning << "Retrieval request for zone '" << domain << "' from primary '" << master << "' received from operator" << endl;
- return "Added retrieval request for '" + domain.toLogString() + "' from primary " + master.toLogString();
+ shuffle(di.primaries.begin(), di.primaries.end(), pdns::dns_random_engine());
+ const auto& primary = di.primaries.front();
+ Communicator.addSuckRequest(domain, primary, SuckRequest::PdnsControl, override_primary);
+ g_log << Logger::Warning << "Retrieval request for zone '" << domain << "' from primary '" << primary << "' received from operator" << endl;
+ return "Added retrieval request for '" + domain.toLogString() + "' from primary " + primary.toLogString();
}
string DLNotifyHostHandler(const vector<string>& parts, Utility::pid_t /* ppid */)
#pragma once
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
+#pragma clang diagnostic pop
#include <vector>
#include <fstream>
return toStringWithPortExcept(53);
}
+ [[nodiscard]] string toStructuredLogString() const
+ {
+ return toStringWithPort();
+ }
+
string toByteString() const
{
if (isIPv4()) {
}
//<! checks whether the container is empty.
- bool empty() const {
+ [[nodiscard]] bool empty() const {
return (d_size == 0);
}
tree.erase(nm);
}
+ void deleteMasks(const NetmaskGroup& group)
+ {
+ for (const auto& entry : group.tree) {
+ deleteMask(entry.first);
+ }
+ }
+
void deleteMask(const std::string& ip)
{
if (!ip.empty())
if (!domainStats.empty()) {
stats<<"# HELP "<<prefix<<"soa_serial The SOA serial number of a domain"<<std::endl;
stats<<"# TYPE "<<prefix<<"soa_serial gauge"<<std::endl;
- stats<<"# HELP "<<prefix<<"soa_checks_total Number of times a SOA check at the master was attempted"<<std::endl;
+ stats << "# HELP " << prefix << "soa_checks_total Number of times a SOA check at the primary was attempted" << std::endl;
stats<<"# TYPE "<<prefix<<"soa_checks_total counter"<<std::endl;
- stats<<"# HELP "<<prefix<<"soa_checks_failed_total Number of times a SOA check at the master failed"<<std::endl;
+ stats << "# HELP " << prefix << "soa_checks_failed_total Number of times a SOA check at the primary failed" << std::endl;
stats<<"# TYPE "<<prefix<<"soa_checks_failed_total counter"<<std::endl;
stats<<"# HELP "<<prefix<<"soa_inqueries_total Number of times a SOA query was received"<<std::endl;
stats<<"# TYPE "<<prefix<<"soa_inqueries_total counter"<<std::endl;
stats<<prefix<<"ixfr_failures_total{domain=\""<<d.first<<"\"} "<<d.second.numIXFRFailures<<std::endl;
}
+ if (!notimpStats.empty()) {
+ stats<<"# HELP "<<prefix<<"notimp An unimplemented opcode"<<std::endl;
+ stats<<"# TYPE "<<prefix<<"notimp counter"<<std::endl;
+ }
+
+ for (std::size_t i = 0; i < notimpStats.size() ; i++) {
+ auto val = notimpStats.at(i).load();
+
+ if (val > 0) {
+ stats<<prefix<<"notimp{opcode=\""<<Opcode::to_s(i)<<"\"} "<<val<<std::endl;
+ }
+ }
+
stats<<"# HELP "<<prefix<<"unknown_domain_inqueries_total Number of queries received for domains unknown to us"<<std::endl;
stats<<"# TYPE "<<prefix<<"unknown_domain_inqueries_total counter"<<std::endl;
stats<<prefix<<"unknown_domain_inqueries_total "<<progStats.unknownDomainInQueries<<std::endl;
#include <map>
#include <string>
+#include "dns.hh"
#include "dnsname.hh"
#include "pdnsexception.hh"
progStats.unknownDomainInQueries += 1;
}
+ void incrementNotImplemented(uint8_t opcode)
+ {
+ notimpStats.at(opcode) ++;
+ }
+
private:
class perDomainStat {
public:
};
std::map<DNSName, perDomainStat> domainStats;
+ std::array<std::atomic<uint64_t>, 16> notimpStats{};
programStats progStats;
std::map<DNSName, perDomainStat>::iterator getRegisteredDomain(const DNSName& d) {
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "dns.hh"
+#include "dnsparser.hh"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "logger.hh"
#include "ixfrdist-stats.hh"
#include "ixfrdist-web.hh"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
#include <yaml-cpp/yaml.h>
+#pragma GCC diagnostic pop
/* BEGIN Needed because of deeper dependencies */
#include "arguments.hh"
// Why a struct? This way we can add more options to a domain in the future
struct ixfrdistdomain_t {
- set<ComboAddress> masters; // A set so we can do multiple master addresses in the future
+ set<ComboAddress> primaries; // A set so we can do multiple primary addresses in the future
uint32_t maxSOARefresh{0}; // Cap SOA refresh value to the given value in seconds
};
// Map domains and their data
static LockGuarded<std::map<DNSName, std::shared_ptr<ixfrinfo_t>>> g_soas;
+// Queue of received NOTIFYs, already verified against their primary IPs
+// Lazily implemented as a set
+static LockGuarded<std::set<DNSName>> g_notifiesReceived;
+
// Condition variable for TCP handling
static std::condition_variable g_tcpHandlerCV;
static std::queue<pair<int, ComboAddress>> g_tcpRequestFDs;
static bool g_exiting = false;
-static NetmaskGroup g_acl;
+static NetmaskGroup g_acl; // networks that can QUERY us
+static NetmaskGroup g_notifySources; // networks (well, IPs) that can NOTIFY us
static bool g_compress = false;
static ixfrdistStats g_stats;
static void cleanUpDomain(const DNSName& domain, const uint16_t& keep, const string& workdir) {
string dir = workdir + "/" + domain.toString();
- DIR *dp;
- dp = opendir(dir.c_str());
- if (dp == nullptr) {
- return;
- }
vector<uint32_t> zoneVersions;
- struct dirent *d;
- while ((d = readdir(dp)) != nullptr) {
- if(!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {
- continue;
+ {
+ auto dirHandle = std::unique_ptr<DIR, decltype(&closedir)>(opendir(dir.c_str()), closedir);
+ if (!dirHandle) {
+ return;
+ }
+
+ struct dirent* entry = nullptr;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
+ while ((entry = readdir(dirHandle.get())) != nullptr) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
+ continue;
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
+ zoneVersions.push_back(std::stoi(entry->d_name));
}
- zoneVersions.push_back(std::stoi(d->d_name));
}
- closedir(dp);
+
g_log<<Logger::Info<<"Found "<<zoneVersions.size()<<" versions of "<<domain<<", asked to keep "<<keep<<", ";
if (zoneVersions.size() <= keep) {
g_log<<Logger::Info<<"not cleaning up"<<endl;
// FIXME: also report zone size?
}
-static void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& axfrTimeout, const uint16_t& soaRetry, const uint32_t axfrMaxRecords) {
+static void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& axfrTimeout, const uint16_t& soaRetry, const uint32_t axfrMaxRecords) { // NOLINT(readability-function-cognitive-complexity) 13400 https://github.com/PowerDNS/pdns/issues/13400 Habbie: ixfrdist: reduce complexity
setThreadName("ixfrdist/update");
std::map<DNSName, time_t> lastCheck;
refresh = std::min(refresh, domainConfig.second.maxSOARefresh);
}
}
- if (now - zoneLastCheck < refresh) {
+
+
+ if (now - zoneLastCheck < refresh && g_notifiesReceived.lock()->erase(domain) == 0) {
continue;
}
- // TODO Keep track of 'down' masters
- set<ComboAddress>::const_iterator it(domainConfig.second.masters.begin());
- std::advance(it, dns_random(domainConfig.second.masters.size()));
- ComboAddress master = *it;
+ // TODO Keep track of 'down' primaries
+ set<ComboAddress>::const_iterator it(domainConfig.second.primaries.begin());
+ std::advance(it, dns_random(domainConfig.second.primaries.size()));
+ ComboAddress primary = *it;
string dir = workdir + "/" + domain.toString();
- g_log<<Logger::Info<<"Attempting to retrieve SOA Serial update for '"<<domain<<"' from '"<<master.toStringWithPort()<<"'"<<endl;
+ g_log << Logger::Info << "Attempting to retrieve SOA Serial update for '" << domain << "' from '" << primary.toStringWithPort() << "'" << endl;
shared_ptr<const SOARecordContent> sr;
try {
zoneLastCheck = now;
g_stats.incrementSOAChecks(domain);
- auto newSerial = getSerialFromMaster(master, domain, sr); // TODO TSIG
+ auto newSerial = getSerialFromPrimary(primary, domain, sr); // TODO TSIG
if(current_soa != nullptr) {
- g_log<<Logger::Info<<"Got SOA Serial for "<<domain<<" from "<<master.toStringWithPort()<<": "<< newSerial<<", had Serial: "<<current_soa->d_st.serial;
+ g_log << Logger::Info << "Got SOA Serial for " << domain << " from " << primary.toStringWithPort() << ": " << newSerial << ", had Serial: " << current_soa->d_st.serial;
if (newSerial == current_soa->d_st.serial) {
g_log<<Logger::Info<<", not updating."<<endl;
continue;
g_log<<Logger::Info<<", will update."<<endl;
}
} catch (runtime_error &e) {
- g_log<<Logger::Warning<<"Unable to get SOA serial update for '"<<domain<<"' from master "<<master.toStringWithPort()<<": "<<e.what()<<endl;
+ g_log << Logger::Warning << "Unable to get SOA serial update for '" << domain << "' from primary " << primary.toStringWithPort() << ": " << e.what() << endl;
g_stats.incrementSOAChecksFailed(domain);
continue;
}
// Now get the full zone!
g_log<<Logger::Info<<"Attempting to receive full zonedata for '"<<domain<<"'"<<endl;
- ComboAddress local = master.isIPv4() ? ComboAddress("0.0.0.0") : ComboAddress("::");
+ ComboAddress local = primary.isIPv4() ? ComboAddress("0.0.0.0") : ComboAddress("::");
TSIGTriplet tt;
// The *new* SOA
uint32_t soaTTL = 0;
records_t records;
try {
- AXFRRetriever axfr(master, domain, tt, &local);
+ AXFRRetriever axfr(primary, domain, tt, &local);
uint32_t nrecords=0;
Resolver::res_t nop;
vector<DNSRecord> chunk;
} /* while (true) */
} /* updateThread */
-static bool checkQuery(const MOADNSParser& mdp, const ComboAddress& saddr, const bool udp = true, const string& logPrefix="") {
- vector<string> info_msg;
+enum class ResponseType {
+ Unknown,
+ ValidQuery,
+ RefusedOpcode,
+ RefusedQuery,
+ EmptyNoError
+};
- g_log<<Logger::Debug<<logPrefix<<"Had "<<mdp.d_qname<<"|"<<QType(mdp.d_qtype).toString()<<" query from "<<saddr.toStringWithPort()<<endl;
+static ResponseType maybeHandleNotify(const MOADNSParser& mdp, const ComboAddress& saddr, const string& logPrefix="") {
+ if (mdp.d_header.opcode != Opcode::Notify) { // NOLINT(bugprone-narrowing-conversions, cppcoreguidelines-narrowing-conversions) opcode is 4 bits, this is not a dangerous conversion
+ return ResponseType::Unknown;
+ }
+
+ g_log<<Logger::Info<<logPrefix<<"NOTIFY for "<<mdp.d_qname<<"|"<<QType(mdp.d_qtype).toString()<<" "<< Opcode::to_s(mdp.d_header.opcode) <<" from "<<saddr.toStringWithPort()<<endl;
+
+ auto found = g_domainConfigs.find(mdp.d_qname);
+ if (found == g_domainConfigs.end()) {
+ g_log<<Logger::Info<<("Domain name '" + mdp.d_qname.toLogString() + "' is not configured for notification")<<endl;
+ return ResponseType::RefusedQuery;
+ }
+
+ auto primaries = found->second.primaries;
+
+ bool primaryFound = false;
- if (udp && mdp.d_qtype != QType::SOA && mdp.d_qtype != QType::IXFR) {
- info_msg.push_back("QType is unsupported (" + QType(mdp.d_qtype).toString() + " is not in {SOA,IXFR})");
+ for (const auto& primary : primaries) {
+ if (ComboAddress::addressOnlyEqual()(saddr, primary)) {
+ primaryFound = true;
+ break;
+ }
}
- if (!udp && mdp.d_qtype != QType::SOA && mdp.d_qtype != QType::IXFR && mdp.d_qtype != QType::AXFR) {
- info_msg.push_back("QType is unsupported (" + QType(mdp.d_qtype).toString() + " is not in {SOA,IXFR,AXFR})");
+ if (primaryFound) {
+ g_notifiesReceived.lock()->insert(mdp.d_qname);
+ return ResponseType::EmptyNoError;
}
- {
- if (g_domainConfigs.find(mdp.d_qname) == g_domainConfigs.end()) {
- info_msg.push_back("Domain name '" + mdp.d_qname.toLogString() + "' is not configured for distribution");
+ return ResponseType::RefusedQuery;
+}
+
+static ResponseType checkQuery(const MOADNSParser& mdp, const ComboAddress& saddr, const bool udp = true, const string& logPrefix="") {
+ vector<string> info_msg;
+
+ auto ret = ResponseType::ValidQuery;
+
+ g_log<<Logger::Debug<<logPrefix<<"Had "<<mdp.d_qname<<"|"<<QType(mdp.d_qtype).toString()<<" query from "<<saddr.toStringWithPort()<<endl;
+
+ if (mdp.d_header.opcode != Opcode::Query) { // NOLINT(bugprone-narrowing-conversions, cppcoreguidelines-narrowing-conversions) opcode is 4 bits, this is not a dangerous conversion
+ info_msg.push_back("Opcode is unsupported (" + Opcode::to_s(mdp.d_header.opcode) + "), expected QUERY"); // note that we also emit this for a NOTIFY from a wrong source
+ ret = ResponseType::RefusedOpcode;
+ }
+ else {
+ if (udp && mdp.d_qtype != QType::SOA && mdp.d_qtype != QType::IXFR) {
+ info_msg.push_back("QType is unsupported (" + QType(mdp.d_qtype).toString() + " is not in {SOA,IXFR})");
+ ret = ResponseType::RefusedQuery;
}
- else {
- const auto zoneInfo = getCurrentZoneInfo(mdp.d_qname);
- if (zoneInfo == nullptr) {
- info_msg.push_back("Domain has not been transferred yet");
+
+ if (!udp && mdp.d_qtype != QType::SOA && mdp.d_qtype != QType::IXFR && mdp.d_qtype != QType::AXFR) {
+ info_msg.push_back("QType is unsupported (" + QType(mdp.d_qtype).toString() + " is not in {SOA,IXFR,AXFR})");
+ ret = ResponseType::RefusedQuery;
+ }
+
+ {
+ if (g_domainConfigs.find(mdp.d_qname) == g_domainConfigs.end()) {
+ info_msg.push_back("Domain name '" + mdp.d_qname.toLogString() + "' is not configured for distribution");
+ ret = ResponseType::RefusedQuery;
+ }
+ else {
+ const auto zoneInfo = getCurrentZoneInfo(mdp.d_qname);
+ if (zoneInfo == nullptr) {
+ info_msg.emplace_back("Domain has not been transferred yet");
+ ret = ResponseType::RefusedQuery;
+ }
}
}
}
- if (!info_msg.empty()) {
- g_log<<Logger::Warning<<logPrefix<<"Refusing "<<mdp.d_qname<<"|"<<QType(mdp.d_qtype).toString()<<" query from "<<saddr.toStringWithPort();
+ if (!info_msg.empty()) { // which means ret is not SOA
+ g_log<<Logger::Warning<<logPrefix<<"Refusing "<<mdp.d_qname<<"|"<<QType(mdp.d_qtype).toString()<<" "<< Opcode::to_s(mdp.d_header.opcode) <<" from "<<saddr.toStringWithPort();
g_log<<Logger::Warning<<": ";
bool first = true;
for (const auto& s : info_msg) {
g_log<<Logger::Warning<<s;
}
g_log<<Logger::Warning<<endl;
- return false;
+ // fall through to return below
}
+ return ret;
+}
+
+/*
+ * Returns a vector<uint8_t> that represents the full empty NOERROR response.
+ * QNAME is read from mdp.
+ */
+static bool makeEmptyNoErrorPacket(const MOADNSParser& mdp, vector<uint8_t>& packet) {
+ DNSPacketWriter pw(packet, mdp.d_qname, mdp.d_qtype);
+ pw.getHeader()->opcode = mdp.d_header.opcode;
+ pw.getHeader()->id = mdp.d_header.id;
+ pw.getHeader()->rd = mdp.d_header.rd;
+ pw.getHeader()->qr = 1;
+ pw.getHeader()->aa = 1;
+
+ pw.commit();
+
return true;
}
}
DNSPacketWriter pw(packet, mdp.d_qname, mdp.d_qtype);
+ pw.getHeader()->opcode = mdp.d_header.opcode;
pw.getHeader()->id = mdp.d_header.id;
pw.getHeader()->rd = mdp.d_header.rd;
pw.getHeader()->qr = 1;
*/
static bool makeRefusedPacket(const MOADNSParser& mdp, vector<uint8_t>& packet) {
DNSPacketWriter pw(packet, mdp.d_qname, mdp.d_qtype);
+ pw.getHeader()->opcode = mdp.d_header.opcode;
pw.getHeader()->id = mdp.d_header.id;
pw.getHeader()->rd = mdp.d_header.rd;
pw.getHeader()->qr = 1;
return true;
}
+/*
+ * Returns a vector<uint8_t> that represents the full NOTIMP response to a
+ * query. QNAME and type are read from mdp.
+ */
+static bool makeNotimpPacket(const MOADNSParser& mdp, vector<uint8_t>& packet) {
+ DNSPacketWriter pw(packet, mdp.d_qname, mdp.d_qtype);
+ pw.getHeader()->opcode = mdp.d_header.opcode;
+ pw.getHeader()->id = mdp.d_header.id;
+ pw.getHeader()->rd = mdp.d_header.rd;
+ pw.getHeader()->qr = 1;
+ pw.getHeader()->rcode = RCode::NotImp;
+
+ return true;
+}
+
static vector<uint8_t> getSOAPacket(const MOADNSParser& mdp, const shared_ptr<const SOARecordContent>& soa, uint32_t soaTTL) {
vector<uint8_t> packet;
DNSPacketWriter pw(packet, mdp.d_qname, mdp.d_qtype);
return true;
}
-static bool allowedByACL(const ComboAddress& addr) {
+static bool allowedByACL(const ComboAddress& addr, bool forNotify = false) {
+ if (forNotify) {
+ return g_notifySources.match(addr);
+ }
+
return g_acl.match(addr);
}
-static void handleUDPRequest(int fd, boost::any&) {
+static void handleUDPRequest(int fd, boost::any& /*unused*/)
+try
+{
// TODO make the buffer-size configurable
char buf[4096];
ComboAddress saddr;
return;
}
- if (!allowedByACL(saddr)) {
- g_log<<Logger::Warning<<"UDP query from "<<saddr.toString()<<" is not allowed, dropping"<<endl;
+ if (!allowedByACL(saddr, true) && !allowedByACL(saddr, false)) {
+ g_log<<Logger::Warning<<"UDP query from "<<saddr.toString()<<" did not match any valid query or NOTIFY source, dropping"<<endl;
return;
}
- MOADNSParser mdp(true, string(buf, res));
+ MOADNSParser mdp(true, string(&buf[0], static_cast<size_t>(res)));
vector<uint8_t> packet;
- if (checkQuery(mdp, saddr)) {
+
+ ResponseType respt = ResponseType::Unknown;
+
+ if (allowedByACL(saddr, true)) {
+ respt = maybeHandleNotify(mdp, saddr);
+ }
+ else if (!allowedByACL(saddr)) {
+ g_log<<Logger::Warning<<"UDP query from "<<saddr.toString()<<" is not allowed, dropping"<<endl;
+ return;
+ }
+
+ if (respt == ResponseType::Unknown) {
+ // query was not handled yet (so not a valid NOTIFY)
+ respt = checkQuery(mdp, saddr);
+ }
+ if (respt == ResponseType::ValidQuery) {
/* RFC 1995 Section 2
* Transport of a query may be by either UDP or TCP. If an IXFR query
* is via UDP, the IXFR server may attempt to reply using UDP if the
*/
g_stats.incrementSOAinQueries(mdp.d_qname); // FIXME: this also counts IXFR queries (but the response is the same as to a SOA query)
makeSOAPacket(mdp, packet);
- } else {
+ } else if (respt == ResponseType::EmptyNoError) {
+ makeEmptyNoErrorPacket(mdp, packet);
+ } else if (respt == ResponseType::RefusedQuery) {
g_stats.incrementUnknownDomainInQueries(mdp.d_qname);
makeRefusedPacket(mdp, packet);
+ } else if (respt == ResponseType::RefusedOpcode) {
+ g_stats.incrementNotImplemented(mdp.d_header.opcode);
+ makeNotimpPacket(mdp, packet);
}
if(sendto(fd, &packet[0], packet.size(), 0, (struct sockaddr*) &saddr, fromlen) < 0) {
}
return;
}
+catch(std::exception& e) {
+ return;
+}
+
static void handleTCPRequest(int fd, boost::any&) {
ComboAddress saddr;
return;
}
- if (!allowedByACL(saddr)) {
+ // we allow the connection if this is a legit client or a legit NOTIFY source
+ // need to check per-operation later
+ if (!allowedByACL(saddr) && !allowedByACL(saddr, true)) {
g_log<<Logger::Warning<<"TCP query from "<<saddr.toString()<<" is not allowed, dropping"<<endl;
close(cfd);
return;
try {
MOADNSParser mdp(true, string(buf, res));
- if (!checkQuery(mdp, saddr, false, prefix)) {
+ ResponseType respt = ResponseType::Unknown;
+
+ // this code is duplicated from the UDP path
+ if (allowedByACL(saddr, true)) {
+ respt = maybeHandleNotify(mdp, saddr);
+ }
+ else if (!allowedByACL(saddr)) {
+ close(cfd);
+ continue;
+ }
+
+ if (respt == ResponseType::Unknown) {
+ respt = checkQuery(mdp, saddr, false, prefix);
+ }
+
+ if (respt != ResponseType::ValidQuery && respt != ResponseType::EmptyNoError) { // on TCP, we currently do not bother with sending useful errors
close(cfd);
continue;
}
- if (mdp.d_qtype == QType::SOA) {
- vector<uint8_t> packet;
+ vector<uint8_t> packet;
+
+ if (respt == ResponseType::EmptyNoError) {
+ bool ret = makeEmptyNoErrorPacket(mdp, packet);
+ if (!ret) {
+ close(cfd);
+ continue;
+ }
+ sendPacketOverTCP(cfd, packet);
+ }
+ else if (mdp.d_qtype == QType::SOA) {
bool ret = makeSOAPacket(mdp, packet);
if (!ret) {
close(cfd);
}
try {
if (!domain["master"]) {
- g_log<<Logger::Error<<"Domain '"<<domain["domain"].as<string>()<<"' has no master configured!"<<endl;
+ g_log << Logger::Error << "Domain '" << domain["domain"].as<string>() << "' has no primary configured!" << endl;
retval = false;
continue;
}
domain["master"].as<ComboAddress>();
+
+ auto notifySource = domain["master"].as<ComboAddress>();
+
+ g_notifySources.addMask(notifySource);
} catch (const runtime_error &e) {
- g_log<<Logger::Error<<"Unable to read domain '"<<domain["domain"].as<string>()<<"' master address: "<<e.what()<<endl;
+ g_log << Logger::Error << "Unable to read domain '" << domain["domain"].as<string>() << "' primary address: " << e.what() << endl;
retval = false;
}
if (domain["max-soa-refresh"]) {
for (auto const &domain : config["domains"]) {
set<ComboAddress> s;
s.insert(domain["master"].as<ComboAddress>());
- g_domainConfigs[domain["domain"].as<DNSName>()].masters = s;
+ g_domainConfigs[domain["domain"].as<DNSName>()].primaries = s;
if (domain["max-soa-refresh"].IsDefined()) {
g_domainConfigs[domain["domain"].as<DNSName>()].maxSOARefresh = domain["max-soa-refresh"].as<uint32_t>();
}
g_log<<Logger::Error<<"Error printing ACL: "<<exp.what()<<endl;
}
+ g_log<<Logger::Notice<<"NOTIFY accepted from "<<g_notifySources.toString()<<"."<<endl;
+
if (config["compress"].IsDefined()) {
g_compress = config["compress"].as<bool>();
if (g_compress) {
#include <cinttypes>
#include <dirent.h>
#include <cerrno>
+#include <sys/stat.h>
+
#include "ixfrutils.hh"
#include "sstuff.hh"
#include "dnssecinfra.hh"
#include "zoneparser-tng.hh"
#include "dnsparser.hh"
-uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<const SOARecordContent>& sr, const TSIGTriplet& tt, const uint16_t timeout)
+uint32_t getSerialFromPrimary(const ComboAddress& primary, const DNSName& zone, shared_ptr<const SOARecordContent>& sr, const TSIGTriplet& tt, const uint16_t timeout)
{
vector<uint8_t> packet;
DNSPacketWriter pw(packet, zone, QType::SOA);
addTSIG(pw, trc, tt.name, tt.secret, "", false);
}
- Socket s(master.sin4.sin_family, SOCK_DGRAM);
- s.connect(master);
+ Socket s(primary.sin4.sin_family, SOCK_DGRAM);
+ s.connect(primary);
string msg((const char*)&packet[0], packet.size());
s.writen(msg);
uint32_t getSerialFromDir(const std::string& dir)
{
- uint32_t ret=0;
- DIR* dirhdl=opendir(dir.c_str());
- if(!dirhdl)
+ uint32_t ret = 0;
+ auto dirhdl = std::unique_ptr<DIR, decltype(&closedir)>(opendir(dir.c_str()), closedir);
+ if (!dirhdl) {
throw runtime_error("Could not open IXFR directory '" + dir + "': " + stringerror());
- struct dirent *entry;
+ }
- while((entry = readdir(dirhdl))) {
+ struct dirent* entry = nullptr;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
+ while ((entry = readdir(dirhdl.get())) != nullptr) {
uint32_t num = atoi(entry->d_name);
- if(std::to_string(num) == entry->d_name)
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
+ auto name = std::string_view(entry->d_name, strlen(entry->d_name));
+ if (std::to_string(num) == name) {
ret = max(num, ret);
+ }
}
- closedir(dirhdl);
+
return ret;
}
{
DNSRecord soa;
auto serial = getSerialFromRecords(records, soa);
- string fname=directory +"/"+std::to_string(serial);
- auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen((fname+".partial").c_str(), "w"), fclose);
- if (!fp) {
+ string fname = directory + "/" + std::to_string(serial);
+ /* ensure that the partial zone file will only be accessible by the current user, not even
+ by other users in the same group, and certainly not by other users. */
+ umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ auto filePtr = std::unique_ptr<FILE, int(*)(FILE*)>(fopen((fname+".partial").c_str(), "w"), fclose);
+ if (!filePtr) {
throw runtime_error("Unable to open file '"+fname+".partial' for writing: "+stringerror());
}
records_t soarecord;
soarecord.insert(soa);
- if (fprintf(fp.get(), "$ORIGIN %s\n", zone.toString().c_str()) < 0) {
+ if (fprintf(filePtr.get(), "$ORIGIN %s\n", zone.toString().c_str()) < 0) {
string error = "Error writing to zone file for " + zone.toLogString() + " in file " + fname + ".partial" + ": " + stringerror();
- fp.reset();
+ filePtr.reset();
unlink((fname+".partial").c_str());
throw std::runtime_error(error);
}
try {
- writeRecords(fp.get(), soarecord);
- writeRecords(fp.get(), records);
- writeRecords(fp.get(), soarecord);
+ writeRecords(filePtr.get(), soarecord);
+ writeRecords(filePtr.get(), records);
+ writeRecords(filePtr.get(), soarecord);
} catch (runtime_error &e) {
- fp.reset();
+ filePtr.reset();
unlink((fname+".partial").c_str());
throw runtime_error("Error closing zone file for " + zone.toLogString() + " in file " + fname + ".partial" + ": " + e.what());
}
- if (fclose(fp.release()) != 0) {
+ if (fclose(filePtr.release()) != 0) {
string error = "Error closing zone file for " + zone.toLogString() + " in file " + fname + ".partial" + ": " + stringerror();
unlink((fname+".partial").c_str());
throw std::runtime_error(error);
> /* indexed_by */
> /* multi_index_container */ records_t;
-uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<const SOARecordContent>& sr, const TSIGTriplet& tt = TSIGTriplet(), const uint16_t timeout = 2);
+uint32_t getSerialFromPrimary(const ComboAddress& primary, const DNSName& zone, shared_ptr<const SOARecordContent>& sr, const TSIGTriplet& tt = TSIGTriplet(), const uint16_t timeout = 2);
uint32_t getSerialFromDir(const std::string& dir);
uint32_t getSerialFromRecords(const records_t& records, DNSRecord& soaret);
void writeZoneToDisk(const records_t& records, const DNSName& zone, const std::string& directory);
/* goal in life:
in directory/zone-name we leave files with their name the serial number
- at startup, retrieve current SOA SERIAL for domain from master server
+ at startup, retrieve current SOA SERIAL for domain from primary server
compare with what the best is we have in our directory, IXFR from that.
Store result in memory, read that best zone in memory, apply deltas, write it out.
Next up, loop this every REFRESH seconds */
DNSName zone(argv[4]);
- ComboAddress master(argv[2], atoi(argv[3]));
+ ComboAddress primary(argv[2], atoi(argv[3]));
string directory(argv[5]);
records_t records;
}
catch(std::exception& e) {
cout<<"Could not load zone from disk: "<<e.what()<<endl;
- cout<<"Retrieving latest from master "<<master.toStringWithPort()<<endl;
- ComboAddress local = master.sin4.sin_family == AF_INET ? ComboAddress("0.0.0.0") : ComboAddress("::");
- AXFRRetriever axfr(master, zone, tt, &local);
+ cout << "Retrieving latest from primary " << primary.toStringWithPort() << endl;
+ ComboAddress local = primary.sin4.sin_family == AF_INET ? ComboAddress("0.0.0.0") : ComboAddress("::");
+ AXFRRetriever axfr(primary, zone, tt, &local);
unsigned int nrecords=0;
Resolver::res_t nop;
vector<DNSRecord> chunk;
cout<<"Checking for update, our serial number is "<<ourSerial<<".. ";
cout.flush();
shared_ptr<const SOARecordContent> sr;
- uint32_t serial = getSerialFromMaster(master, zone, sr, tt);
+ uint32_t serial = getSerialFromPrimary(primary, zone, sr, tt);
if(ourSerial == serial) {
unsigned int sleepTime = sr ? sr->d_st.refresh : 60;
cout<<"still up to date, their serial is "<<serial<<", sleeping "<<sleepTime<<" seconds"<<endl;
}
cout<<"got new serial: "<<serial<<", initiating IXFR!"<<endl;
- auto deltas = getIXFRDeltas(master, zone, ourSoa, 20, false, tt);
+ auto deltas = getIXFRDeltas(primary, zone, ourSoa, 20, false, tt);
cout<<"Got "<<deltas.size()<<" deltas, applying.."<<endl;
for(const auto& delta : deltas) {
#include <openssl/core.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
+#else
+#include <openssl/hmac.h>
#endif
#ifdef HAVE_LIBSODIUM
#endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */
#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
-std::pair<bool, std::string> libssl_load_engine(const std::string& engineName, const std::optional<std::string>& defaultString)
+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
return { false, "OpenSSL has been built without engine support" };
return 1;
}
-static long libssl_server_name_callback(SSL* ssl, int* al, void* arg)
+static int libssl_server_name_callback(SSL* ssl, int* /* alert */, void* /* arg */)
{
- (void) al;
- (void) arg;
-
- if (SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)) {
+ if (SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != nullptr) {
return SSL_TLSEXT_ERR_OK;
}
{
};
-// Same mechanism for t.toLogString()
+// Same mechanism for t.toLogString() and t.toStructuredLogString()
template <typename T, typename = void>
struct is_toLogString_available : std::false_type
{
{
};
+template <typename T, typename = void>
+struct is_toStructuredLogString_available : std::false_type
+{
+};
+
+template <typename T>
+struct is_toStructuredLogString_available<T, std::void_t<decltype(std::declval<T>().toStructuredLogString())>> : std::true_type
+{
+};
+
template <typename T, typename = void>
struct is_toString_available : std::false_type
{
if constexpr (std::is_same_v<T, std::string>) {
return _t;
}
+ else if constexpr (is_toStructuredLogString_available<T>::value) {
+ return _t.toStructuredLogString();
+ }
else if constexpr (is_toLogString_available<T>::value) {
return _t.toLogString();
}
// SLOG(g_log<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl,
// startupLog->error("No such file", "Unable to parse configuration file", "config_file", Logging::Loggable(configname));
//
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define SLOG(oldStyle, slogCall) \
- if (true) { \
+ do { \
if (g_slogStructured) { \
slogCall; \
} \
else { \
oldStyle; \
} \
- }
+ } while (0)
#else // No structured logging (e.g. auth)
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define SLOG(oldStyle, slogCall) \
do { \
oldStyle; \
- } while (0);
+ } while (0)
#endif // RECURSOR
d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
// DNSRecord
- d_lw->writeFunction("newDR", [](const DNSName &name, const std::string &type, unsigned int ttl, const std::string &content, int place){ QType qtype; qtype = type; auto dr = DNSRecord(); dr.d_name = name; dr.d_type = qtype.getCode(); dr.d_ttl = ttl; dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(dr.d_type, QClass::IN, content))); dr.d_place = static_cast<DNSResourceRecord::Place>(place); return dr; });
+ d_lw->writeFunction("newDR", [](const DNSName& name, const std::string& type, unsigned int ttl, const std::string& content, int place) { QType qtype; qtype = type; auto dr = DNSRecord(); dr.d_name = name; dr.d_type = qtype.getCode(); dr.d_ttl = ttl; dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::make(dr.d_type, QClass::IN, content))); dr.d_place = static_cast<DNSResourceRecord::Place>(place); return dr; });
d_lw->registerMember("name", &DNSRecord::d_name);
d_lw->registerMember("type", &DNSRecord::d_type);
d_lw->registerMember("ttl", &DNSRecord::d_ttl);
ret=aaaarec->getCA(53);
return ret;
});
- d_lw->registerFunction<void(DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(dr.d_type, 1, newContent))); });
+ d_lw->registerFunction<void (DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::make(dr.d_type, 1, newContent))); });
// pdnsload
d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) {
for(const auto& content_it: contents) {
if(qtype==QType::TXT)
- ret.push_back(DNSRecordContent::mastermake(qtype, QClass::IN, '"'+content_it+'"' ));
+ ret.push_back(DNSRecordContent::make(qtype, QClass::IN, '"' + content_it + '"'));
else
- ret.push_back(DNSRecordContent::mastermake(qtype, QClass::IN, content_it ));
+ ret.push_back(DNSRecordContent::make(qtype, QClass::IN, content_it));
}
} catch(std::exception &e) {
g_log << Logger::Info << "Lua record ("<<query<<"|"<<QType(qtype).toString()<<") reported: " << e.what();
uint64_t getOpenFileDescriptors(const std::string&)
{
#ifdef __linux__
- DIR* dirhdl=opendir(("/proc/"+std::to_string(getpid())+"/fd/").c_str());
- if(!dirhdl)
+ auto dirHandle = std::unique_ptr<DIR, decltype(&closedir)>(opendir(("/proc/"+std::to_string(getpid())+"/fd/").c_str()), closedir);
+ if (!dirHandle) {
return 0;
+ }
- struct dirent *entry;
- int ret=0;
- while((entry = readdir(dirhdl))) {
+ int ret = 0;
+ struct dirent* entry = nullptr;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
+ while ((entry = readdir(dirHandle.get())) != nullptr) {
uint32_t num;
try {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
pdns::checked_stoi_into(num, entry->d_name);
} catch (...) {
continue; // was not a number.
}
- if(std::to_string(num) == entry->d_name)
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
+ if (std::to_string(num) == entry->d_name) {
ret++;
+ }
}
- closedir(dirhdl);
return ret;
#elif defined(__OpenBSD__)
}
else
content=mode;
- rr.dr.setContent(DNSRecordContent::mastermake(QType::TXT, 1, "\""+content+"\""));
+ rr.dr.setContent(DNSRecordContent::make(QType::TXT, 1, "\"" + content + "\""));
}
else if (target==idserver) {
// modes: disabled, hostname or custom
if(!tid.empty() && tid[0]!='"') { // see #6010 however
tid = "\"" + tid + "\"";
}
- rr.dr.setContent(DNSRecordContent::mastermake(QType::TXT, 1, tid));
+ rr.dr.setContent(DNSRecordContent::make(QType::TXT, 1, tid));
}
else {
r->setRcode(RCode::Refused);
*/
-int PacketHandler::trySuperMaster(const DNSPacket& p, const DNSName& tsigkeyname)
+int PacketHandler::tryAutoPrimary(const DNSPacket& p, const DNSName& tsigkeyname)
{
if(p.d_tcp)
{
// do it right now if the client is TCP
// rarely happens
- return trySuperMasterSynchronous(p, tsigkeyname);
+ return tryAutoPrimarySynchronous(p, tsigkeyname);
}
else
{
// queue it if the client is on UDP
- Communicator.addTrySuperMasterRequest(p);
+ Communicator.addTryAutoPrimaryRequest(p);
return 0;
}
}
-int PacketHandler::trySuperMasterSynchronous(const DNSPacket& p, const DNSName& tsigkeyname)
+int PacketHandler::tryAutoPrimarySynchronous(const DNSPacket& p, const DNSName& tsigkeyname)
{
ComboAddress remote = p.getInnerRemote();
if(p.hasEDNSSubnet() && pdns::isAddressTrustedNotificationProxy(remote)) {
}
if(!haveNS) {
- g_log<<Logger::Error<<"While checking for supermaster, did not find NS for "<<p.qdomain<<" at: "<< remote <<endl;
+ g_log << Logger::Error << "While checking for autoprimary, did not find NS for " << p.qdomain << " at: " << remote << endl;
return RCode::ServFail;
}
DNSBackend *db;
if (!::arg().mustDo("allow-unsigned-autoprimary") && tsigkeyname.empty()) {
- g_log<<Logger::Error<<"Received unsigned NOTIFY for "<<p.qdomain<<" from potential supermaster "<<remote<<". Refusing."<<endl;
+ g_log << Logger::Error << "Received unsigned NOTIFY for " << p.qdomain << " from potential autoprimary " << remote << ". Refusing." << endl;
return RCode::Refused;
}
- if(!B.superMasterBackend(remote.toString(), p.qdomain, nsset, &nameserver, &account, &db)) {
- g_log<<Logger::Error<<"Unable to find backend willing to host "<<p.qdomain<<" for potential supermaster "<<remote<<". Remote nameservers: "<<endl;
+ if (!B.autoPrimaryBackend(remote.toString(), p.qdomain, nsset, &nameserver, &account, &db)) {
+ g_log << Logger::Error << "Unable to find backend willing to host " << p.qdomain << " for potential autoprimary " << remote << ". Remote nameservers: " << endl;
for(const auto& rr: nsset) {
if(rr.qtype==QType::NS)
g_log<<Logger::Error<<rr.content<<endl;
return RCode::Refused;
}
try {
- db->createSlaveDomain(remote.toString(), p.qdomain, nameserver, account);
+ db->createSecondaryDomain(remote.toString(), p.qdomain, nameserver, account);
DomainInfo di;
if (!db->getDomainInfo(p.qdomain, di, false)) {
- g_log << Logger::Error << "Failed to create " << p.qdomain << " for potential supermaster " << remote << endl;
+ g_log << Logger::Error << "Failed to create " << p.qdomain << " for potential autoprimary " << remote << endl;
return RCode::ServFail;
}
g_zoneCache.add(p.qdomain, di.id);
}
}
catch(PDNSException& ae) {
- g_log<<Logger::Error<<"Database error trying to create "<<p.qdomain<<" for potential supermaster "<<remote<<": "<<ae.reason<<endl;
+ g_log << Logger::Error << "Database error trying to create " << p.qdomain << " for potential autoprimary " << remote << ": " << ae.reason << endl;
return RCode::ServFail;
}
- g_log<<Logger::Warning<<"Created new slave zone '"<<p.qdomain<<"' from supermaster "<<remote<<endl;
+ g_log << Logger::Warning << "Created new secondary zone '" << p.qdomain << "' from autoprimary " << remote << endl;
return RCode::NoError;
}
was this notification from an approved address?
was this notification approved by TSIG?
We determine our internal SOA id (via UeberBackend)
- We determine the SOA at our (known) master
- if master is higher -> do stuff
+ We determine the SOA at our (known) primary
+ if primary is higher -> do stuff
*/
g_log<<Logger::Debug<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<endl;
if(!::arg().mustDo("secondary") && s_forwardNotify.empty()) {
- g_log<<Logger::Warning<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" but slave support is disabled in the configuration"<<endl;
+ g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from " << p.getRemoteString() << " but secondary support is disabled in the configuration" << endl;
return RCode::Refused;
}
DomainInfo di;
if(!B.getDomainInfo(p.qdomain, di, false) || !di.backend) {
if(::arg().mustDo("autosecondary")) {
- g_log<<Logger::Warning<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" for which we are not authoritative, trying supermaster"<<endl;
- return trySuperMaster(p, p.getTSIGKeyname());
+ g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from " << p.getRemoteString() << " for which we are not authoritative, trying autoprimary" << endl;
+ return tryAutoPrimary(p, p.getTSIGKeyname());
}
g_log<<Logger::Notice<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" for which we are not authoritative (Refused)"<<endl;
return RCode::Refused;
}
if(pdns::isAddressTrustedNotificationProxy(p.getInnerRemote())) {
- if(di.masters.empty()) {
- g_log<<Logger::Warning<<"Received NOTIFY for "<<p.qdomain<<" from trusted-notification-proxy "<<p.getRemoteString()<<", zone does not have any masters defined (Refused)"<<endl;
+ if (di.primaries.empty()) {
+ g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from trusted-notification-proxy " << p.getRemoteString() << ", zone does not have any primaries defined (Refused)" << endl;
return RCode::Refused;
}
g_log<<Logger::Notice<<"Received NOTIFY for "<<p.qdomain<<" from trusted-notification-proxy "<<p.getRemoteString()<<endl;
g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from " << p.getRemoteString() << " but we are primary (Refused)" << endl;
return RCode::Refused;
}
- else if(!di.isMaster(p.getInnerRemote())) {
- g_log<<Logger::Warning<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" which is not a master (Refused)"<<endl;
+ else if (!di.isPrimary(p.getInnerRemote())) {
+ g_log << Logger::Warning << "Received NOTIFY for " << p.qdomain << " from " << p.getRemoteString() << " which is not a primary (Refused)" << endl;
return RCode::Refused;
}
if(::arg().mustDo("secondary")) {
g_log<<Logger::Notice<<"Received NOTIFY for "<<p.qdomain<<" from "<<p.getRemoteString()<<" - queueing check"<<endl;
di.receivedNotify = true;
- Communicator.addSlaveCheckRequest(di, p.getInnerRemote());
+ Communicator.addSecondaryCheckRequest(di, p.getInnerRemote());
}
return 0;
}
UeberBackend *getBackend();
- int trySuperMasterSynchronous(const DNSPacket& p, const DNSName& tsigkeyname);
+ int tryAutoPrimarySynchronous(const DNSPacket& p, const DNSName& tsigkeyname);
static NetmaskGroup s_allowNotifyFrom;
static set<string> s_forwardNotify;
static bool s_SVCAutohints;
static const std::shared_ptr<CDSRecordContent> s_deleteCDSContent;
private:
- int trySuperMaster(const DNSPacket& p, const DNSName& tsigkeyname);
+ int tryAutoPrimary(const DNSPacket& p, const DNSName& tsigkeyname);
int processNotify(const DNSPacket& );
void addRootReferral(DNSPacket& r);
int doChaosRequest(const DNSPacket& p, std::unique_ptr<DNSPacket>& r, DNSName &target) const;
+#include <boost/smart_ptr/make_shared_array.hpp>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
return 1;
}
} catch(const PDNSException &e) {
- if (di.kind == DomainInfo::Slave) {
+ if (di.kind == DomainInfo::Secondary) {
cout << "[Error] non-IP address for primaries: " << e.reason << endl;
numerrors++;
}
rr.content = "\""+rr.content+"\"";
try {
- shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), QClass::IN, rr.content));
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::make(rr.qtype.getCode(), QClass::IN, rr.content));
string tmp=drc->serialize(rr.qname);
tmp = drc->getZoneRepresentation(true);
if (rr.qtype.getCode() != QType::AAAA) {
}
if (rr.qtype.getCode() == QType::SVCB || rr.qtype.getCode() == QType::HTTPS) {
- shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), QClass::IN, rr.content));
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::make(rr.qtype.getCode(), QClass::IN, rr.content));
// I, too, like to live dangerously
auto svcbrc = std::dynamic_pointer_cast<SVCBBaseRecordContent>(drc);
if (svcbrc->getPriority() == 0 && svcbrc->hasParams()) {
for (auto const &rr : checkCNAME) {
DNSName target;
- shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), QClass::IN, rr.content));
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::make(rr.qtype.getCode(), QClass::IN, rr.content));
switch (rr.qtype) {
case QType::MX:
target = std::dynamic_pointer_cast<MXRecordContent>(drc)->d_mxname;
haveSOA = true;
}
try {
- DNSRecordContent::mastermake(rr.qtype, QClass::IN, rr.content);
+ DNSRecordContent::make(rr.qtype, QClass::IN, rr.content);
}
catch (const PDNSException &pe) {
cerr<<"Bad record content in record for "<<rr.qname<<"|"<<rr.qtype.toString()<<": "<<pe.reason<<endl;
return EXIT_SUCCESS;
}
-static int createSlaveZone(const vector<string>& cmds) {
+static int createSecondaryZone(const vector<string>& cmds)
+{
UeberBackend B;
DomainInfo di;
DNSName zone(cmds.at(1));
cerr << "Zone '" << zone << "' exists already" << endl;
return EXIT_FAILURE;
}
- vector<ComboAddress> masters;
+ vector<ComboAddress> primaries;
for (unsigned i=2; i < cmds.size(); i++) {
- masters.emplace_back(cmds.at(i), 53);
+ primaries.emplace_back(cmds.at(i), 53);
}
- cerr << "Creating secondary zone '" << zone << "', with primaries '" << comboAddressVecToString(masters) << "'" << endl;
- B.createDomain(zone, DomainInfo::Slave, masters, "");
+ cerr << "Creating secondary zone '" << zone << "', with primaries '" << comboAddressVecToString(primaries) << "'" << endl;
+ B.createDomain(zone, DomainInfo::Secondary, primaries, "");
if(!B.getDomainInfo(zone, di)) {
cerr << "Zone '" << zone << "' was not created!" << endl;
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
-static int changeSlaveZoneMaster(const vector<string>& cmds) {
+static int changeSecondaryZonePrimary(const vector<string>& cmds)
+{
UeberBackend B;
DomainInfo di;
DNSName zone(cmds.at(1));
cerr << "Zone '" << zone << "' doesn't exist" << endl;
return EXIT_FAILURE;
}
- vector<ComboAddress> masters;
+ vector<ComboAddress> primaries;
for (unsigned i=2; i < cmds.size(); i++) {
- masters.emplace_back(cmds.at(i), 53);
+ primaries.emplace_back(cmds.at(i), 53);
}
- cerr << "Updating secondary zone '" << zone << "', primaries to '" << comboAddressVecToString(masters) << "'" << endl;
+ cerr << "Updating secondary zone '" << zone << "', primaries to '" << comboAddressVecToString(primaries) << "'" << endl;
try {
- di.backend->setMasters(zone, masters);
+ di.backend->setPrimaries(zone, primaries);
return EXIT_SUCCESS;
}
catch (PDNSException& e) {
cout<<"Current records for "<<rr.qname<<" IN "<<rr.qtype.toString()<<" will be replaced"<<endl;
}
for(auto i = contentStart ; i < cmds.size() ; ++i) {
- rr.content = DNSRecordContent::mastermake(rr.qtype.getCode(), QClass::IN, cmds.at(i))->getZoneRepresentation(true);
+ rr.content = DNSRecordContent::make(rr.qtype.getCode(), QClass::IN, cmds.at(i))->getZoneRepresentation(true);
newrrs.push_back(rr);
}
return EXIT_SUCCESS;
}
-// addSuperMaster add a new autoprimary
-static int addSuperMaster(const std::string &IP, const std::string &nameserver, const std::string &account)
+// addAutoPrimary add a new autoprimary
+static int addAutoPrimary(const std::string& IP, const std::string& nameserver, const std::string& account)
{
UeberBackend B("default");
const AutoPrimary primary(IP, nameserver, account);
- if ( B.superMasterAdd(primary) ){
+ if (B.autoPrimaryAdd(primary)) {
return EXIT_SUCCESS;
}
cerr<<"could not find a backend with autosecondary support"<<endl;
if(rr.qtype.getCode() == QType::DNSKEY) {
cerr<<"got DNSKEY!"<<endl;
apex=rr.qname;
- drc = *std::dynamic_pointer_cast<DNSKEYRecordContent>(DNSRecordContent::mastermake(QType::DNSKEY, QClass::IN, rr.content));
+ drc = *std::dynamic_pointer_cast<DNSKEYRecordContent>(DNSRecordContent::make(QType::DNSKEY, QClass::IN, rr.content));
}
else if(rr.qtype.getCode() == QType::RRSIG) {
cerr<<"got RRSIG"<<endl;
- rrc = *std::dynamic_pointer_cast<RRSIGRecordContent>(DNSRecordContent::mastermake(QType::RRSIG, QClass::IN, rr.content));
+ rrc = *std::dynamic_pointer_cast<RRSIGRecordContent>(DNSRecordContent::make(QType::RRSIG, QClass::IN, rr.content));
}
else if(rr.qtype.getCode() == QType::DS) {
cerr<<"got DS"<<endl;
- dsrc = *std::dynamic_pointer_cast<DSRecordContent>(DNSRecordContent::mastermake(QType::DS, QClass::IN, rr.content));
+ dsrc = *std::dynamic_pointer_cast<DSRecordContent>(DNSRecordContent::make(QType::DS, QClass::IN, rr.content));
}
else {
qname = rr.qname;
- toSign.insert(DNSRecordContent::mastermake(rr.qtype.getCode(), QClass::IN, rr.content));
+ toSign.insert(DNSRecordContent::make(rr.qtype.getCode(), QClass::IN, rr.content));
}
}
}
}
else if (di.isSecondaryType()) {
- cout << "Primar" << addS(di.masters, "y", "ies") << ": ";
- for(const auto& m : di.masters)
+ cout << "Primar" << addS(di.primaries, "y", "ies") << ": ";
+ for (const auto& m : di.primaries)
cout<<m.toStringWithPort()<<" ";
cout<<endl;
struct tm tm;
return false;
}
- if(di.kind == DomainInfo::Slave)
- {
+ if (di.kind == DomainInfo::Secondary) {
cerr << "Warning! This is a secondary zone! If this was a mistake, please run" << endl;
cerr<<"pdnsutil disable-dnssec "<<zone<<" right now!"<<endl;
}
cout<<"Constructing UeberBackend"<<endl;
UeberBackend B("default");
cout<<"Picking first backend - if this is not what you want, edit launch line!"<<endl;
- DNSBackend *db = B.backends[0];
+ DNSBackend *db = B.backends[0].get();
cout << "Creating secondary zone " << zone << endl;
- db->createSlaveDomain("127.0.0.1", zone, "", "_testschema");
+ db->createSecondaryDomain("127.0.0.1", zone, "", "_testschema");
cout << "Secondary zone created" << endl;
DomainInfo di;
return 0;
}
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): TODO Clean this function up.
int main(int argc, char** argv)
try
{
// DNSResourceRecord rr;
// rr.qtype = DNSRecordContent::TypeToNumber(cmds.at(1));
// rr.content = cmds.at(2);
- auto drc = DNSRecordContent::mastermake(DNSRecordContent::TypeToNumber(cmds.at(1)), QClass::IN, cmds.at(2));
+ auto drc = DNSRecordContent::make(DNSRecordContent::TypeToNumber(cmds.at(1)), QClass::IN, cmds.at(2));
cout<<makeLuaString(drc->serialize(DNSName(), true))<<endl;
return 0;
}
return createZone(DNSName(cmds.at(1)), cmds.size() > 2 ? DNSName(cmds.at(2)) : DNSName());
}
- else if (cmds.at(0) == "create-secondary-zone" || cmds.at(0) == "create-slave-zone") {
+ else if (cmds.at(0) == "create-secondary-zone") {
if(cmds.size() < 3 ) {
cerr << "Syntax: pdnsutil create-secondary-zone ZONE primary-ip [primary-ip..]" << endl;
return 0;
}
- return createSlaveZone(cmds);
+ return createSecondaryZone(cmds);
}
- else if (cmds.at(0) == "change-secondary-zone-primary" || cmds.at(0) == "change-slave-zone-master") {
+ else if (cmds.at(0) == "change-secondary-zone-primary") {
if(cmds.size() < 3 ) {
cerr << "Syntax: pdnsutil change-secondary-zone-primary ZONE primary-ip [primary-ip..]" << endl;
return 0;
}
- return changeSlaveZoneMaster(cmds);
+ return changeSecondaryZonePrimary(cmds);
}
else if (cmds.at(0) == "add-record") {
if(cmds.size() < 5) {
}
return addOrReplaceRecord(true, cmds);
}
- else if (cmds.at(0) == "add-autoprimary" || cmds.at(0) == "add-supermaster") {
+ else if (cmds.at(0) == "add-autoprimary" || cmds.at(0) == "add-autoprimary") {
if(cmds.size() < 3) {
cerr << "Syntax: pdnsutil add-autoprimary IP NAMESERVER [account]" << endl;
return 0;
}
- exit(addSuperMaster(cmds.at(1), cmds.at(2), cmds.size() > 3 ? cmds.at(3) : ""));
+ exit(addAutoPrimary(cmds.at(1), cmds.at(2), cmds.size() > 3 ? cmds.at(3) : ""));
}
else if (cmds.at(0) == "remove-autoprimary") {
if(cmds.size() < 3) {
}
DNSName zname(cmds.at(1));
string name = cmds.at(2);
- if (cmds.at(3) == "primary" || cmds.at(3) == "master" || cmds.at(3) == "producer")
+ if (cmds.at(3) == "primary" || cmds.at(3) == "producer")
metaKey = "TSIG-ALLOW-AXFR";
- else if (cmds.at(3) == "secondary" || cmds.at(3) == "consumer" || cmds.at(3) == "slave")
+ else if (cmds.at(3) == "secondary" || cmds.at(3) == "consumer")
metaKey = "AXFR-MASTER-TSIG";
else {
cerr << "Invalid parameter '" << cmds.at(3) << "', expected primary or secondary type" << endl;
}
DNSName zname(cmds.at(1));
string name = cmds.at(2);
- if (cmds.at(3) == "primary" || cmds.at(3) == "producer" || cmds.at(3) == "master")
+ if (cmds.at(3) == "primary" || cmds.at(3) == "producer")
metaKey = "TSIG-ALLOW-AXFR";
- else if (cmds.at(3) == "secondary" || cmds.at(3) == "consumer" || cmds.at(3) == "slave")
+ else if (cmds.at(3) == "secondary" || cmds.at(3) == "consumer")
metaKey = "AXFR-MASTER-TSIG";
else {
cerr << "Invalid parameter '" << cmds.at(3) << "', expected primary or secondary type" << endl;
}
else if (cmds.at(0) == "b2b-migrate") {
if (cmds.size() < 3) {
- cerr<<"Usage: b2b-migrate OLD NEW"<<endl;
+ cerr << "Usage: b2b-migrate OLD NEW" << endl;
+ return 1;
+ }
+
+ if (cmds.at(1) == cmds.at(2)) {
+ cerr << "Error: b2b-migrate OLD NEW: OLD cannot be the same as NEW" << endl;
return 1;
}
- DNSBackend *src = nullptr;
- DNSBackend *tgt = nullptr;
+ unique_ptr<DNSBackend> src{nullptr};
+ unique_ptr<DNSBackend> tgt{nullptr};
- for(DNSBackend *b : BackendMakers().all()) {
- if (b->getPrefix() == cmds.at(1))
- src = b;
- if (b->getPrefix() == cmds.at(2))
- tgt = b;
+ for (auto& backend : BackendMakers().all()) {
+ if (backend->getPrefix() == cmds.at(1)) {
+ src = std::move(backend);
+ }
+ else if (backend->getPrefix() == cmds.at(2)) {
+ tgt = std::move(backend);
+ }
}
+
if (src == nullptr) {
cerr << "Unknown source backend '" << cmds.at(1) << "'" << endl;
return 1;
DNSResourceRecord rr;
cout<<"Processing '"<<di.zone<<"'"<<endl;
// create zone
- if (!tgt->createDomain(di.zone, di.kind, di.masters, di.account)) throw PDNSException("Failed to create zone");
+ if (!tgt->createDomain(di.zone, di.kind, di.primaries, di.account))
+ throw PDNSException("Failed to create zone");
if (!tgt->getDomainInfo(di.zone, di_new)) throw PDNSException("Failed to create zone");
// move records
if (!src->list(di.zone, di.id, true)) throw PDNSException("Failed to list records");
return 1;
}
- DNSBackend *db = nullptr;
+ std::unique_ptr<DNSBackend> matchingBackend{nullptr};
- for(DNSBackend *b : BackendMakers().all()) {
- if (b->getPrefix() == cmds.at(1))
- db = b;
+ for (auto& backend : BackendMakers().all()) {
+ if (backend->getPrefix() == cmds.at(1)) {
+ matchingBackend = std::move(backend);
+ }
}
- if (db == nullptr) {
+ if (matchingBackend == nullptr) {
cerr << "Unknown backend '" << cmds.at(1) << "'" << endl;
return 1;
}
- for(auto i=next(begin(cmds),2); i != end(cmds); ++i) {
- cerr<<"== "<<*i<<endl;
- cout<<db->directBackendCmd(*i);
+ for (auto i = next(begin(cmds), 2); i != end(cmds); ++i) {
+ cerr << "== " << *i << endl;
+ cout << matchingBackend->directBackendCmd(*i);
}
return 0;
return;
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+ const dnsheader_aligned dh(packet);
if (ntohs(dh->ancount) == 0) {
return;
m4_pattern_forbid([^_?PKG_[A-Z_]+$], [*** pkg.m4 missing, please install pkg-config])
AX_CXX_COMPILE_STDCXX_17([noext], [mandatory])
+PDNS_CHECK_CARGO([1.64])
# Rust runtime used dlopen from its static lib
LT_INIT([dlopen])
--- /dev/null
+Structured Logging Dictionary
+=============================
+
+This page describes the common entries of the Structured Logging component.
+Currently there are two possible values for :ref:`setting-structured-logging-backend`:
+
+- The ``default`` text based backend
+- The ``systemd-journal`` backend
+
+The ``default`` backend
+-----------------------
+The default backend uses a text representation of the key-value pairs.
+A line is constructed by appending all key-value pairs as ``key="value"``, separated by spaces.
+The output is written by passing the resulting text line to the standard error stream and also to ``syslog`` if :ref:`setting-disable-syslog` is false.
+Depending on the value of :ref:`setting-log-timestamp` a timestamp is prepended to the log line.
+
+An example line (including prepended timestamp) looks like this::
+
+ Oct 18 08:45:21 msg="Raised soft limit on number of filedescriptors to match max-mthreads and threads settings" subsystem="config" level="0" prio="Warning" tid="0" ts="1697611521.119" limit="6469"
+
+- Key names are not quoted.
+- Values are quoted with double quotes.
+- If a value contains a double quote, it is escaped with a backslash.
+- Backslashes in the value are escaped by prepending a backslash.
+
+The following keys are always present:
+
++-------------+------------------+--------------------------------------+---------------------------------------+
+| **Key** | **Type** | **Example** | **Remarks** |
++-------------+------------------+--------------------------------------+---------------------------------------+
+|``msg`` |``string`` | ``"Launching distributor threads"`` |Value is the same for all instances of |
+| | | |this log entry, together with |
+| | | |``subsystem`` it uniquely identifies |
+| | | |the log message. |
++-------------+------------------+--------------------------------------+---------------------------------------+
+|``subsystem``|``string`` |``"incoming"`` |Uniquely identifies the log |
+| | | |entry together with the value of |
+| | | |``msg``. |
++-------------+------------------+--------------------------------------+---------------------------------------+
+| ``level`` |``number`` |``"0"`` |The detail level of the log entry, do |
+| | | |not confuse with |
+| | | |:ref:`setting-loglevel`. Not actively |
+| | | |used currently. |
++-------------+------------------+--------------------------------------+---------------------------------------+
+| ``prio`` |``enum`` |``"Notice"`` |One of ``Alert=1``, ``Critical=2``, |
+| | | |``Error=3``, ``Warning=4``, |
+| | | |``Notice=5``, ``Info=6``, |
+| | | |``Debug=7``. A log entry will only |
+| | | |produced if its ``prio`` is equal or |
+| | | |lower than :ref:`setting-loglevel`. |
++-------------+------------------+--------------------------------------+---------------------------------------+
+| ``tid`` |``number`` |``"2"`` |The Posix worker thread id that |
+| | | |produced the log entry. If not produced|
+| | | |by a worker thread, the value is zero. |
++-------------+------------------+--------------------------------------+---------------------------------------+
+| ``ts`` |``number`` |``"1697614303.039"`` |Number of seconds since the Unix epoch,|
+| | | |including fractional part. |
++-------------+------------------+--------------------------------------+---------------------------------------+
+
+A log entry can also have zero or more additional key-value pairs. Common keys are:
+
++-------------+---------------------+--------------------------------------+---------------------------------------+
+| **Key** | **Type** |**Example** | **Remarks** |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+|``error`` |``string`` |``"No such file or directory"`` |An error cause. |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+|``address`` |``ip address:port`` |``"[::]:5301"`` |An IP: port combination. |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+|``addresses``|``list of subnets`` |``"127.0.0.0/8 ::ffff:0:0/96"`` |A list of subnets, space separated. |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+|``path`` |``filesystem path`` |``"tmp/api-dir/apizones"`` | |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+|``proto`` |``string`` |``"udp"`` | |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+|``qname`` |``DNS name`` |``"example.com"`` | |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+|``qtype`` |``DNS Query Type`` |``"AAAA"`` |Text representation of DNS query type. |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+| ``rcode`` |``DNS Response Code``|``"3"`` |Numeric DNS response code |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+|``mtid`` |``Number`` |``"234"`` |The id of the MThread that produced the|
+| | | |log entry. |
++-------------+---------------------+--------------------------------------+---------------------------------------+
+
+The ``systemd-journal`` backend
+-------------------------------
+The ``systemd-journal`` structured logging backend uses mostly the same keys and values as the default backend, with the exceptions:
+
+- keys are capitalized as required for ``systemd-journal``.
+- ``msg`` is translated to ``MESSAGE``.
+- ``prio`` is translated to ``PRIORITY``.
+- ``ts`` is translated to ``TIMESTAMP``.
+- If the original key is in a list of keys special to ``systemd-journal``, it is capitalized and prepended by ``PDNS_``.
+ The list of special keys is: message, message_id, priority, code_file, code_line, code_func, errno, invocation_id, user_invocation_id, syslog_facility, syslog_identifier, syslog_pid, syslog_timestamp, syslog_raw, documentation, tid, unit, user_unit, object_pid.
+
+To use this logging backend, add the ``--structured-logging-backend=systemd-journal`` to the command line in the systemd unit file.
+Note that adding it to the recursor configuration file does not work as expected, as this file is processed after the logging has been set up.
+
+To query the log, use a command similar to::
+
+ # journalctl -r -n 1 -o json-pretty -u pdns-recursor.service
+
Changelogs for 4.9.X
====================
+.. changelog::
+ :version: 4.9.2
+ :released: 8th of November 2023
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13449
+ :tickets: 13383, 13409
+
+ Handle serve stale logic in getRootNXTrust().
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13411
+ :tickets: 13353
+
+ If serving stale, wipe CNAME records from cache when we get a NODATA negative response for them.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13412
+ :tickets: 13408
+
+ Handle stack memory on NetBSD as on OpenBSD.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13286
+ :tickets: 13092
+
+ Prevent two cases of copy of data that can be moved.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13284
+ :tickets: 13210
+
+ Remove Before=nss-lookup.target line from systemd unit file.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13283
+ :tickets: 13278
+
+ Prevent lookups for unsupported qtypes or rcode != 0 to submit refresh tasks.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13282
+ :tickets: 13209
+
+ Implement a more fair way to prune the aggressive cache.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13176
+ :tickets: 13102
+
+ Do not assume the records are in a particular order when determining if an answer is NODATA.
+
.. changelog::
:version: 4.9.1
:released: 25th of August 2023
Changelogs for 5.0.X
====================
+
+.. changelog::
+ :version: 5.0.0-beta1
+ :released: 10th of November 2023
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13468
+
+ Fix ubsan error: using a value of 80 for bool.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13462
+
+ Be more memory efficient handling RPZ updates.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13464
+
+ Change default of extended-resolution-errors setting to true.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13455
+
+ Move a few settings from recursor to outgoing section.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13446
+
+ For structured logging always log addresses including port.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13438
+
+ Teach configure to check for cargo version and require >= 1.64.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13410
+ :tickets: 12612
+
+ Tidy cache and only copy values if non-expired entry was found.
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 13409
+ :tickets: 13383
+
+ Handle serve stale logic in getRootNXTrust().
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13432,13430
+ :tickets: 13430
+
+ Add endbr64 instructions in the right spots for OpenBSD/amd64.
+
+ .. change::
+ :tags: Improvements
+ :pullreq: 13408
+
+ Handle stack memory on NetBSD as on OpenBSD (Tom Ivar Helbekkmo)
+
.. changelog::
:version: 5.0.0-alpha2
:released: 17th of October 2023
Changed settings
^^^^^^^^^^^^^^^^
- The :ref:`setting-loglevel` can now be set to a level below 3 (error).
+- The :ref:`setting-extended-resolution-errors` now defaults to enabled.
4.8.0 to 4.9.0
--------------
dr.d_ttl = static_cast<uint32_t>(d_ttl);
dr.d_type = QType::CNAME;
dr.d_class = QClass::IN;
- dr.setContent(DNSRecordContent::mastermake(QType::CNAME, QClass::IN, getKindToString(d_kind)));
+ dr.setContent(DNSRecordContent::make(QType::CNAME, QClass::IN, getKindToString(d_kind)));
result.push_back(std::move(dr));
}
void DNSFilterEngine::Zone::dump(FILE* fp) const
{
/* fake the SOA record */
- auto soa = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
+ 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(fp, "%s IN SOA %s\n", d_domain.toString().c_str(), soa->getZoneRepresentation().c_str());
for (const auto& pair : d_qpolName) {
#include <sys/mman.h>
#include <unistd.h>
-// On OpenBSD mem used as stack should be marked MAP_STACK
-#ifdef __OpenBSD__
+// On OpenBSD and NetBSD mem used as stack should be marked MAP_STACK
+#if defined(__OpenBSD__) || defined(__NetBSD__)
#define PDNS_MAP_STACK MAP_STACK
#else
#define PDNS_MAP_STACK 0
const auto padding = getAlignmentPadding(requestedSize, pageSize);
const size_type allocatedSize = requestedSize + padding + (pageSize * 2);
-#ifdef __OpenBSD__
- // OpenBSD does not like mmap MAP_STACK regions that have
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+ // OpenBSD and NetBSD don't like mmap MAP_STACK regions that have
// PROT_NONE, so allocate r/w and mprotect the guard pages
// explicitly.
const int protection = PROT_READ | PROT_WRITE;
}
char* basePointer = static_cast<char*>(p);
void* usablePointer = basePointer + pageSize;
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) || defined(__NetBSD__)
int res = mprotect(basePointer, pageSize, PROT_NONE);
if (res != 0) {
munmap(p, allocatedSize);
dr.d_ttl = ttl.get_value_or(3600);
dr.d_type = type;
dr.d_place = place;
- dr.setContent(DNSRecordContent::mastermake(type, QClass::IN, content));
+ dr.setContent(DNSRecordContent::make(type, QClass::IN, content));
records.push_back(dr);
}
[](DNSFilterEngine::Policy& pol, const std::string& content) {
// Only CNAMES for now, when we ever add a d_custom_type, there will be pain
pol.d_custom.clear();
- pol.d_custom.push_back(DNSRecordContent::mastermake(QType::CNAME, QClass::IN, content));
+ pol.d_custom.push_back(DNSRecordContent::make(QType::CNAME, QClass::IN, content));
}
);
d_lw->registerFunction("getDH", &DNSQuestion::getDH);
d_lw->registerFunction<const ProxyProtocolValue, std::string()>("getContent", [](const ProxyProtocolValue& value) { return value.content; });
d_lw->registerFunction<const ProxyProtocolValue, uint8_t()>("getType", [](const ProxyProtocolValue& value) { return value.type; });
- d_lw->registerFunction<void(DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.setContent(DNSRecordContent::mastermake(dr.d_type, QClass::IN, newContent)); });
+ d_lw->registerFunction<void(DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.setContent(DNSRecordContent::make(dr.d_type, QClass::IN, newContent)); });
d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer);
d_lw->registerFunction("addRecord", &DNSQuestion::addRecord);
d_lw->registerFunction("getRecords", &DNSQuestion::getRecords);
dr.d_type = type;
dr.d_class = QClass::IN;
dr.d_place = DNSResourceRecord::Place(place);
- dr.setContent(DNSRecordContent::mastermake(type, QClass::IN, std::string(content, contentSize)));
+ dr.setContent(DNSRecordContent::make(type, QClass::IN, std::string(content, contentSize)));
ref->params.records.push_back(std::move(dr));
return true;
r.setContent(DNSRecordContent::deserialize(r.d_name, r.d_type, string(content, contentLen)));
}
else {
- r.setContent(DNSRecordContent::mastermake(r.d_type, QClass::IN, string(content, contentLen)));
+ r.setContent(DNSRecordContent::make(r.d_type, QClass::IN, string(content, contentLen)));
}
return true;
dr.setContent(DNSRecordContent::deserialize(dr.d_name, dr.d_type, string(content, contentLen)));
}
else {
- dr.setContent(DNSRecordContent::mastermake(type, QClass::IN, string(content, contentLen)));
+ dr.setContent(DNSRecordContent::make(type, QClass::IN, string(content, contentLen)));
}
ref->handle.d_dq.currentRecords->push_back(std::move(dr));
--- /dev/null
+../../../m4/ax_compare_version.m4
\ No newline at end of file
--- /dev/null
+AC_DEFUN([PDNS_CHECK_CARGO], [
+ AC_REQUIRE([AC_PROG_SED])
+
+ AC_CHECK_PROG(CARGO, [cargo], [cargo], $CARGO)
+ AS_IF(test x$CARGO = x,
+ AC_MSG_ERROR([cargo is required])
+ )
+ minimum=$1
+ cargo_version=`$CARGO --version | $SED -e 's/^cargo //g'`
+ AX_COMPARE_VERSION([$cargo_version],[lt],[$minimum], [
+ AC_MSG_ERROR([need at least cargo version $minimum])
+ ])
+])
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 */
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
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
#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
* \param ne A NegCacheEntry that is filled when there is a cache entry
* \return true if ne was filled out, false otherwise
*/
-bool NegCache::getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& ne, bool serveStale, bool refresh)
+bool NegCache::getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& negEntry, bool serveStale, bool refresh)
{
// Never deny the root.
- if (qname.isRoot())
+ if (qname.isRoot()) {
return false;
+ }
- // An 'ENT' QType entry, used as "whole name" in the neg-cache context.
- static const QType qtnull(0);
DNSName lastLabel = qname.getLastLabel();
-
- auto& map = getMap(lastLabel);
- auto content = map.lock();
-
- negcache_t::const_iterator ni = content->d_map.find(std::tie(lastLabel, qtnull));
-
- while (ni != content->d_map.end() && ni->d_name == lastLabel && ni->d_auth.isRoot() && ni->d_qtype == qtnull) {
- if (!refresh && (serveStale || ni->d_servedStale > 0) && ni->d_ttd <= now.tv_sec && ni->d_servedStale < s_maxServedStaleExtensions) {
- updateStaleEntry(now.tv_sec, ni, QType::A);
- }
- // We have something
- if (now.tv_sec < ni->d_ttd) {
- ne = *ni;
- moveCacheItemToBack<SequenceTag>(content->d_map, ni);
- return true;
- }
- if (ni->d_servedStale == 0 && !serveStale) {
- moveCacheItemToFront<SequenceTag>(content->d_map, ni);
- }
- ++ni;
+ NegCacheEntry found;
+ // An 'ENT' QType entry, used as "whole name" in the neg-cache context.
+ auto exists = get(lastLabel, QType::ENT, now, found, true, serveStale, refresh);
+ if (exists && found.d_auth.isRoot()) {
+ negEntry = found;
+ return true;
}
return false;
}
void NegCache::prune(time_t now, size_t maxEntries)
{
size_t cacheSize = size();
- pruneMutexCollectionsVector<SequenceTag>(now, *this, d_maps, maxEntries, cacheSize);
+ pruneMutexCollectionsVector<SequenceTag>(now, d_maps, maxEntries, cacheSize);
}
/*!
void add(const NegCacheEntry& ne);
void updateValidationStatus(const DNSName& qname, QType qtype, vState newState, boost::optional<time_t> capTTD);
bool get(const DNSName& qname, QType qtype, const struct timeval& now, NegCacheEntry& ne, bool typeMustMatch = false, bool serverStale = false, bool refresh = false);
- bool getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& ne, bool serveStale, bool refresh);
+ bool getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& negEntry, bool serveStale, bool refresh);
size_t count(const DNSName& qname);
size_t count(const DNSName& qname, QType qtype);
void prune(time_t now, size_t maxEntries);
uint64_t d_contended_count{0};
uint64_t d_acquired_count{0};
void invalidate() {}
+ void preRemoval(const NegCacheEntry& /* entry */) {}
};
LockGuardedTryHolder<MapCombo::LockedContent> lock()
{
return d_maps.at(qname.hash() % d_maps.size());
}
-
-public:
- void preRemoval(MapCombo::LockedContent& /* map */, const NegCacheEntry& /* entry */) {}
};
fprintf(filep.get(), " us === START OF TRACE %s ===\n", timebuf.data());
fprintf(filep.get(), "%s", trace.c_str());
isoDateTimeMillis(now, timebuf.data(), timebuf.size());
- fprintf(filep.get(), "=== END OF TRACE %s ===\n", timebuf.data());
if (ferror(filep.get()) != 0) {
int err = errno;
SLOG(g_log << Logger::Error << "Problems writing to trace file: " << stringerror(err) << endl,
g_slog->withName("trace")->error(Logr::Error, err, "Problems writing to trace file"));
+ // There's no guarantee the message below will end up in the stream, but we try our best
+ clearerr(filep.get());
+ fprintf(filep.get(), "=== TRACE %s TRUNCATED; USE FILE ARGUMENT INSTEAD OF `-' ===\n", timebuf.data());
+ }
+ else {
+ fprintf(filep.get(), "=== END OF TRACE %s ===\n", timebuf.data());
}
// fclose by unique_ptr does implicit flush
}
if (comboWriter->d_mdp.d_header.opcode == static_cast<unsigned>(Opcode::Query)) {
if (resolver.d_outqueries != 0 || resolver.d_authzonequeries != 0) {
- g_recCache->cacheMisses++;
+ g_recCache->incCacheMisses();
}
else {
- g_recCache->cacheHits++;
+ g_recCache->incCacheHits();
}
}
static void handleNewUDPQuestion(int fileDesc, FDMultiplexer::funcparam_t& /* var */) // NOLINT(readability-function-cognitive-complexity): https://github.com/PowerDNS/pdns/issues/12791
{
- ssize_t len = 0;
static const size_t maxIncomingQuerySize = g_proxyProtocolACL.empty() ? 512 : (512 + g_proxyProtocolMaximumSize);
static thread_local std::string data;
ComboAddress fromaddr; // the address the query is coming from
fromaddr.sin6.sin6_family = AF_INET6; // this makes sure fromaddr is big enough
fillMSGHdr(&msgh, &iov, &cbuf, sizeof(cbuf), data.data(), data.size(), &fromaddr);
- if ((len = recvmsg(fileDesc, &msgh, 0)) >= 0) {
+ if (ssize_t len = recvmsg(fileDesc, &msgh, 0); len >= 0) {
eventTrace.clear();
eventTrace.setEnabled(SyncRes::s_event_trace_enabled != 0);
eventTrace.add(RecEventTrace::ReqRecv);
defpol->d_kind = (DNSFilterEngine::PolicyKind)boost::get<uint32_t>(have["defpol"]);
defpol->setName(polName);
if (defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) {
- defpol->d_custom.push_back(DNSRecordContent::mastermake(QType::CNAME, QClass::IN,
- boost::get<string>(have["defcontent"])));
+ defpol->d_custom.push_back(DNSRecordContent::make(QType::CNAME, QClass::IN,
+ boost::get<string>(have["defcontent"])));
if (have.count("defttl") != 0) {
defpol->d_ttl = static_cast<int32_t>(boost::get<uint32_t>(have["defttl"]));
catch (const PDNSException& exp) {
// exp is the exception that was thrown from inside the lambda
SLOG(g_log << exp.reason << std::endl,
- lci.d_slog->error(Logr::Error, exp.reason, "Exception loading Lua", "exception", Logging::Loggable("PDNSException"))) }
+ lci.d_slog->error(Logr::Error, exp.reason, "Exception loading Lua", "exception", Logging::Loggable("PDNSException")));
+ }
throw;
}
catch (std::exception& err) {
static time_t lastOutputTime;
static uint64_t lastQueryCount;
- uint64_t cacheHits = g_recCache->cacheHits;
- uint64_t cacheMisses = g_recCache->cacheMisses;
+ uint64_t cacheHits = g_recCache->getCacheHits();
+ uint64_t cacheMisses = g_recCache->getCacheMisses();
uint64_t cacheSize = g_recCache->size();
auto rc_stats = g_recCache->stats();
auto pc_stats = g_packetCache ? g_packetCache->stats() : std::pair<uint64_t, uint64_t>{0, 0};
0, 0
};
struct timeval period;
- const string name;
+ string name;
};
static void houseKeepingWork(Logr::log_t log)
if (threadInfo.isHandler()) {
if (::arg().mustDo("webserver")) {
SLOG(g_log << Logger::Warning << "Enabling web server" << endl,
- log->info(Logr::Info, "Enabling web server"))
+ log->info(Logr::Info, "Enabling web server"));
try {
rws = make_unique<RecursorWebServer>(t_fdm.get());
}
}
catch (PDNSException& ae) {
SLOG(g_log << Logger::Error << "Exception: " << ae.reason << endl,
- log->error(Logr::Error, ae.reason, "Exception in RecursorThread", "exception", Logging::Loggable("PDNSException")))
+ log->error(Logr::Error, ae.reason, "Exception in RecursorThread", "exception", Logging::Loggable("PDNSException")));
}
catch (std::exception& e) {
SLOG(g_log << Logger::Error << "STL Exception: " << e.what() << endl,
- log->error(Logr::Error, e.what(), "Exception in RecursorThread", "exception", Logging::Loggable("std::exception")))
+ log->error(Logr::Error, e.what(), "Exception in RecursorThread", "exception", Logging::Loggable("std::exception")));
}
catch (...) {
SLOG(g_log << Logger::Error << "any other exception in main: " << endl,
void TCPOutConnectionManager::store(const struct timeval& now, const ComboAddress& ip, Connection&& connection)
{
++connection.d_numqueries;
- if (s_maxQueries > 0 && connection.d_numqueries > s_maxQueries) {
+ if (s_maxQueries > 0 && connection.d_numqueries >= s_maxQueries) {
return;
}
return g_recCache->bytes();
}
-static uint64_t doGetCacheHits()
-{
- return g_recCache->cacheHits;
-}
-
-static uint64_t doGetCacheMisses()
-{
- return g_recCache->cacheMisses;
-}
-
static uint64_t doGetMallocated()
{
// this turned out to be broken
addGetStat("ipv6-questions", [] { return g_Counters.sum(rec::Counter::ipv6qcounter); });
addGetStat("tcp-questions", [] { return g_Counters.sum(rec::Counter::tcpqcounter); });
- addGetStat("cache-hits", doGetCacheHits);
- addGetStat("cache-misses", doGetCacheMisses);
+ addGetStat("cache-hits", []() { return g_recCache->getCacheHits(); });
+ addGetStat("cache-misses", []() { return g_recCache->getCacheMisses(); });
addGetStat("cache-entries", doGetCacheSize);
addGetStat("max-cache-entries", []() { return g_maxCacheEntries.load(); });
addGetStat("max-packetcache-entries", []() { return g_maxPacketCacheEntries.load(); });
void RecursorPacketCache::doPruneTo(time_t now, size_t maxSize)
{
size_t cacheSize = size();
- pruneMutexCollectionsVector<SequencedTag>(now, *this, d_maps, maxSize, cacheSize);
+ pruneMutexCollectionsVector<SequencedTag>(now, d_maps, maxSize, cacheSize);
}
uint64_t RecursorPacketCache::doDump(int file)
uint64_t d_contended_count{0};
uint64_t d_acquired_count{0};
void invalidate() {}
+ void preRemoval(const Entry& /* entry */) {}
};
LockGuardedTryHolder<MapCombo::LockedContent> lock()
static bool checkResponseMatches(MapCombo::LockedContent& shard, std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, OptPBData* pbdata);
void setShardSizes(size_t shardSize);
-
-public:
- void preRemoval(MapCombo::LockedContent& /* map */, const Entry& /* entry */)
- {
- }
};
#include "dnsrecords.hh"
#include "arguments.hh"
#include "syncres.hh"
-#include "recursor_cache.hh"
#include "namespaces.hh"
#include "cachecleaner.hh"
#include "rec-taskqueue.hh"
else if (stateUpdate == vState::NTA) {
state = vState::Insecure;
}
- else if (vStateIsBogus(stateUpdate)) {
- state = stateUpdate;
- }
- else if (stateUpdate == vState::Indeterminate) {
+ else if (vStateIsBogus(stateUpdate) || stateUpdate == vState::Indeterminate) {
state = stateUpdate;
}
- else if (stateUpdate == vState::Insecure) {
+ else if (stateUpdate == vState::Insecure || stateUpdate == vState::Secure) {
if (!vStateIsBogus(*state) && *state != vState::Indeterminate) {
state = stateUpdate;
}
}
- else if (stateUpdate == vState::Secure) {
- if (!vStateIsBogus(*state) && *state != vState::Indeterminate) {
- state = stateUpdate;
- }
+}
+
+template <typename T>
+static void ptrAssign(T* ptr, const T& value)
+{
+ if (ptr != nullptr) {
+ *ptr = value;
}
}
-time_t MemRecursorCache::handleHit(MapCombo::LockedContent& content, MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector<DNSRecord>* res, vector<std::shared_ptr<const RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* fromAuthZone, ComboAddress* fromAuthIP)
+time_t MemRecursorCache::handleHit(time_t now, MapCombo::LockedContent& content, MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector<DNSRecord>* res, vector<std::shared_ptr<const RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* fromAuthZone, ComboAddress* fromAuthIP)
{
// MUTEX SHOULD BE ACQUIRED (as indicated by the reference to the content which is protected by a lock)
time_t ttd = entry->d_ttd;
+ if (ttd <= now) {
+ // Expired, don't bother returning contents. Callers *MUST* check return value of get(), and only look at the entry
+ // if it returned > 0
+ return ttd;
+ }
origTTL = entry->d_orig_ttl;
- if (variable != nullptr && (!entry->d_netmask.empty() || entry->d_rtag)) {
- *variable = true;
+ if (!entry->d_netmask.empty() || entry->d_rtag) {
+ ptrAssign(variable, true);
}
if (res != nullptr) {
if (wasAuth != nullptr) {
*wasAuth = *wasAuth && entry->d_auth;
}
-
- if (fromAuthZone != nullptr) {
- *fromAuthZone = entry->d_authZone;
- }
-
- if (fromAuthIP != nullptr) {
- *fromAuthIP = entry->d_from;
- }
+ ptrAssign(fromAuthZone, entry->d_authZone);
+ ptrAssign(fromAuthIP, entry->d_from);
moveCacheItemToBack<SequencedTag>(content.d_map, entry);
/* we need auth data and the best match is not authoritative */
return map.d_map.end();
}
- else {
- /* this netmask-specific entry has expired */
- moveCacheItemToFront<SequencedTag>(map.d_map, entry);
- // XXX when serving stale, it should be kept, but we don't want a match wth lookupBestMatch()...
- ecsIndex->removeNetmask(best);
- if (ecsIndex->isEmpty()) {
- map.d_ecsIndex.erase(ecsIndex);
- break;
- }
+ /* this netmask-specific entry has expired */
+ moveCacheItemToFront<SequencedTag>(map.d_map, entry);
+ // XXX when serving stale, it should be kept, but we don't want a match wth lookupBestMatch()...
+ ecsIndex->removeNetmask(best);
+ if (ecsIndex->isEmpty()) {
+ map.d_ecsIndex.erase(ecsIndex);
+ break;
}
}
}
return map.d_map.end();
}
-MemRecursorCache::Entries MemRecursorCache::getEntries(MapCombo::LockedContent& map, const DNSName& qname, const QType /* qt */, const OptTag& rtag)
+MemRecursorCache::Entries MemRecursorCache::getEntries(MapCombo::LockedContent& map, const DNSName& qname, const QType /* qtype */, const OptTag& rtag)
{
// MUTEX SHOULD BE ACQUIRED
if (!map.d_cachecachevalid || map.d_cachedqname != qname || map.d_cachedrtag != rtag) {
return map.d_cachecache;
}
-bool MemRecursorCache::entryMatches(MemRecursorCache::OrderedTagIterator_t& entry, const QType qt, bool requireAuth, const ComboAddress& who)
+bool MemRecursorCache::entryMatches(MemRecursorCache::OrderedTagIterator_t& entry, const QType qtype, bool requireAuth, const ComboAddress& who)
{
// This code assumes that if a routing tag is present, it matches
// MUTEX SHOULD BE ACQUIRED
- if (requireAuth && !entry->d_auth)
+ if (requireAuth && !entry->d_auth) {
return false;
+ }
- bool match = (entry->d_qtype == qt || qt == QType::ANY || (qt == QType::ADDR && (entry->d_qtype == QType::A || entry->d_qtype == QType::AAAA)))
+ bool match = (entry->d_qtype == qtype || qtype == QType::ANY || (qtype == QType::ADDR && (entry->d_qtype == QType::A || entry->d_qtype == QType::AAAA)))
&& (entry->d_netmask.empty() || entry->d_netmask.match(who));
return match;
}
if (refresh) {
return -1;
}
- else {
- if (!entry->d_submitted) {
- pushRefreshTask(qname, qtype, entry->d_ttd, entry->d_netmask);
- entry->d_submitted = true;
- }
+ if (!entry->d_submitted) {
+ pushRefreshTask(qname, qtype, entry->d_ttd, entry->d_netmask);
+ entry->d_submitted = true;
}
}
}
return ttl;
}
+
// returns -1 for no hits
-time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qt, Flags flags, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag, vector<std::shared_ptr<const RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth, DNSName* fromAuthZone, ComboAddress* fromAuthIP)
+time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype, Flags flags, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag, vector<std::shared_ptr<const RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth, DNSName* fromAuthZone, ComboAddress* fromAuthIP)
{
- bool requireAuth = flags & RequireAuth;
- bool refresh = flags & Refresh;
- bool serveStale = flags & ServeStale;
+ bool requireAuth = (flags & RequireAuth) != 0;
+ bool refresh = (flags & Refresh) != 0;
+ bool serveStale = (flags & ServeStale) != 0;
boost::optional<vState> cachedState{boost::none};
- uint32_t origTTL;
+ uint32_t origTTL = 0;
if (res != nullptr) {
res->clear();
}
- const uint16_t qtype = qt.getCode();
- if (wasAuth != nullptr) {
- // we might retrieve more than one entry, we need to set that to true
- // so it will be set to false if at least one entry is not auth
- *wasAuth = true;
- }
+
+ // we might retrieve more than one entry, we need to set that to true
+ // so it will be set to false if at least one entry is not auth
+ ptrAssign(wasAuth, true);
auto& shard = getMap(qname);
auto lockedShard = shard.lock();
auto entryA = getEntryUsingECSIndex(*lockedShard, now, qname, QType::A, requireAuth, who, serveStale);
if (entryA != lockedShard->d_map.end()) {
- ret = handleHit(*lockedShard, entryA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
+ ret = handleHit(now, *lockedShard, entryA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
}
auto entryAAAA = getEntryUsingECSIndex(*lockedShard, now, qname, QType::AAAA, requireAuth, who, serveStale);
if (entryAAAA != lockedShard->d_map.end()) {
- time_t ttdAAAA = handleHit(*lockedShard, entryAAAA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
+ time_t ttdAAAA = handleHit(now, *lockedShard, entryAAAA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
if (ret > 0) {
ret = std::min(ret, ttdAAAA);
}
}
}
- if (state && cachedState) {
- *state = *cachedState;
+ if (cachedState && ret > 0) {
+ ptrAssign(state, *cachedState);
}
return ret > 0 ? (ret - now) : ret;
}
- else {
- auto entry = getEntryUsingECSIndex(*lockedShard, now, qname, qtype, requireAuth, who, serveStale);
- if (entry != lockedShard->d_map.end()) {
- time_t ret = handleHit(*lockedShard, entry, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
- if (state && cachedState) {
- *state = *cachedState;
- }
- return fakeTTD(entry, qname, qtype, ret, now, origTTL, refresh);
+ auto entry = getEntryUsingECSIndex(*lockedShard, now, qname, qtype, requireAuth, who, serveStale);
+ if (entry != lockedShard->d_map.end()) {
+ time_t ret = handleHit(now, *lockedShard, entry, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
+ if (cachedState && ret > now) {
+ ptrAssign(state, *cachedState);
}
- return -1;
+ return fakeTTD(entry, qname, qtype, ret, now, origTTL, refresh);
}
+ return -1;
}
if (routingTag) {
- auto entries = getEntries(*lockedShard, qname, qt, routingTag);
+ auto entries = getEntries(*lockedShard, qname, qtype, routingTag);
bool found = false;
- time_t ttd;
+ time_t ttd{};
if (entries.first != entries.second) {
OrderedTagIterator_t firstIndexIterator;
handleServeStaleBookkeeping(now, serveStale, firstIndexIterator);
- ttd = handleHit(*lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
+ ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
- if (qt != QType::ANY && qt != QType::ADDR) { // normally if we have a hit, we are done
+ if (qtype != QType::ANY && qtype != QType::ADDR) { // normally if we have a hit, we are done
break;
}
}
if (found) {
- if (state && cachedState) {
- *state = *cachedState;
+ if (cachedState && ttd > now) {
+ ptrAssign(state, *cachedState);
}
return fakeTTD(firstIndexIterator, qname, qtype, ttd, now, origTTL, refresh);
}
- else {
- return -1;
- }
+ return -1;
}
}
// Try (again) without tag
- auto entries = getEntries(*lockedShard, qname, qt, boost::none);
+ auto entries = getEntries(*lockedShard, qname, qtype, boost::none);
if (entries.first != entries.second) {
OrderedTagIterator_t firstIndexIterator;
bool found = false;
- time_t ttd;
+ time_t ttd{};
for (auto i = entries.first; i != entries.second; ++i) {
firstIndexIterator = lockedShard->d_map.project<OrderedTag>(i);
handleServeStaleBookkeeping(now, serveStale, firstIndexIterator);
- ttd = handleHit(*lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
+ ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP);
- if (qt != QType::ANY && qt != QType::ADDR) { // normally if we have a hit, we are done
+ if (qtype != QType::ANY && qtype != QType::ADDR) { // normally if we have a hit, we are done
break;
}
}
if (found) {
- if (state && cachedState) {
- *state = *cachedState;
+ if (cachedState && ttd > now) {
+ ptrAssign(state, *cachedState);
}
return fakeTTD(firstIndexIterator, qname, qtype, ttd, now, origTTL, refresh);
}
return true;
}
-void MemRecursorCache::replace(time_t now, const DNSName& qname, const QType qt, const vector<DNSRecord>& content, const vector<shared_ptr<const RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, const DNSName& authZone, boost::optional<Netmask> ednsmask, const OptTag& routingTag, vState state, boost::optional<ComboAddress> from, bool refresh, time_t ttl_time)
+void MemRecursorCache::replace(time_t now, const DNSName& qname, const QType qtype, const vector<DNSRecord>& content, const vector<shared_ptr<const RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, const DNSName& authZone, boost::optional<Netmask> ednsmask, const OptTag& routingTag, vState state, boost::optional<ComboAddress> from, bool refresh, time_t ttl_time)
{
auto& shard = getMap(qname);
auto lockedShard = shard.lock();
// We only store with a tag if we have an ednsmask and the tag is available
// We only store an ednsmask if we do not have a tag and we do have a mask.
- auto key = std::tuple(qname, qt.getCode(), ednsmask ? routingTag : boost::none, (ednsmask && !routingTag) ? *ednsmask : Netmask());
+ auto key = std::tuple(qname, qtype.getCode(), ednsmask ? routingTag : boost::none, (ednsmask && !routingTag) ? *ednsmask : Netmask());
bool isNew = false;
cache_t::iterator stored = lockedShard->d_map.find(key);
if (stored == lockedShard->d_map.end()) {
if (isNew || stored->d_ttd <= now) {
/* don't bother building an ecsIndex if we don't have any netmask-specific entries */
if (!routingTag && ednsmask && !ednsmask->empty()) {
- auto ecsIndexKey = std::tuple(qname, qt.getCode());
+ auto ecsIndexKey = std::tuple(qname, qtype.getCode());
auto ecsIndex = lockedShard->d_ecsIndex.find(ecsIndexKey);
if (ecsIndex == lockedShard->d_ecsIndex.end()) {
- ecsIndex = lockedShard->d_ecsIndex.insert(ECSIndexEntry(qname, qt.getCode())).first;
+ ecsIndex = lockedShard->d_ecsIndex.insert(ECSIndexEntry(qname, qtype.getCode())).first;
}
ecsIndex->addMask(*ednsmask);
}
}
time_t maxTTD = std::numeric_limits<time_t>::max();
- CacheEntry ce = *stored; // this is a COPY
- ce.d_qtype = qt.getCode();
+ CacheEntry cacheEntry = *stored; // this is a COPY
+ cacheEntry.d_qtype = qtype.getCode();
- if (!isNew && !ce.shouldReplace(now, auth, state, refresh)) {
+ if (!isNew && !cacheEntry.shouldReplace(now, auth, state, refresh)) {
return;
}
- ce.d_state = state;
+ cacheEntry.d_state = state;
// refuse any attempt to *raise* the TTL of auth NS records, as it would make it possible
// for an auth to keep a "ghost" zone alive forever, even after the delegation is gone from
// the parent
// BUT make sure that we CAN refresh the root
- if (ce.d_auth && auth && qt == QType::NS && !isNew && !qname.isRoot()) {
- maxTTD = ce.d_ttd;
+ if (cacheEntry.d_auth && auth && qtype == QType::NS && !isNew && !qname.isRoot()) {
+ maxTTD = cacheEntry.d_ttd;
}
if (auth) {
- ce.d_auth = true;
+ cacheEntry.d_auth = true;
}
- ce.d_signatures = signatures;
- ce.d_authorityRecs = authorityRecs;
- ce.d_records.clear();
- ce.d_records.reserve(content.size());
- ce.d_authZone = authZone;
+ cacheEntry.d_signatures = signatures;
+ cacheEntry.d_authorityRecs = authorityRecs;
+ cacheEntry.d_records.clear();
+ cacheEntry.d_records.reserve(content.size());
+ cacheEntry.d_authZone = authZone;
if (from) {
- ce.d_from = *from;
+ cacheEntry.d_from = *from;
}
else {
- ce.d_from = ComboAddress();
+ cacheEntry.d_from = ComboAddress();
}
- for (const auto& i : content) {
+ for (const auto& record : content) {
/* Yes, we have altered the d_ttl value by adding time(nullptr) to it
prior to calling this function, so the TTL actually holds a TTD. */
- ce.d_ttd = min(maxTTD, static_cast<time_t>(i.d_ttl)); // XXX this does weird things if TTLs differ in the set
+ cacheEntry.d_ttd = min(maxTTD, static_cast<time_t>(record.d_ttl)); // XXX this does weird things if TTLs differ in the set
- ce.d_orig_ttl = ce.d_ttd - ttl_time;
+ cacheEntry.d_orig_ttl = cacheEntry.d_ttd - ttl_time;
// Even though we record the time the ttd was computed, there still seems to be a case where the computed
// d_orig_ttl can wrap.
// So santize the computed ce.d_orig_ttl to be on the safe side
- if (ce.d_orig_ttl < SyncRes::s_minimumTTL || ce.d_orig_ttl > SyncRes::s_maxcachettl) {
- ce.d_orig_ttl = SyncRes::s_minimumTTL;
+ if (cacheEntry.d_orig_ttl < SyncRes::s_minimumTTL || cacheEntry.d_orig_ttl > SyncRes::s_maxcachettl) {
+ cacheEntry.d_orig_ttl = SyncRes::s_minimumTTL;
}
- ce.d_records.push_back(i.getContent());
+ cacheEntry.d_records.push_back(record.getContent());
}
if (!isNew) {
moveCacheItemToBack<SequencedTag>(lockedShard->d_map, stored);
}
- ce.d_submitted = false;
- ce.d_servedStale = 0;
- lockedShard->d_map.replace(stored, ce);
+ cacheEntry.d_submitted = false;
+ cacheEntry.d_servedStale = 0;
+ lockedShard->d_map.replace(stored, cacheEntry);
}
size_t MemRecursorCache::doWipeCache(const DNSName& name, bool sub, const QType qtype)
lockedShard->d_cachecachevalid = false;
auto& idx = lockedShard->d_map.get<OrderedTag>();
auto range = idx.equal_range(name);
- auto i = range.first;
- while (i != range.second) {
- if (i->d_qtype == qtype || qtype == 0xffff) {
- i = idx.erase(i);
+ auto iter = range.first;
+ while (iter != range.second) {
+ if (iter->d_qtype == qtype || qtype == 0xffff) {
+ iter = idx.erase(iter);
count++;
shard.decEntriesCount();
}
else {
- ++i;
+ ++iter;
}
}
}
}
else {
- for (auto& mc : d_maps) {
- auto map = mc.lock();
+ for (auto& content : d_maps) {
+ auto map = content.lock();
map->d_cachecachevalid = false;
auto& idx = map->d_map.get<OrderedTag>();
for (auto i = idx.lower_bound(name); i != idx.end();) {
- if (!i->d_qname.isPartOf(name))
+ if (!i->d_qname.isPartOf(name)) {
break;
+ }
if (i->d_qtype == qtype || qtype == 0xffff) {
count++;
i = idx.erase(i);
- mc.decEntriesCount();
+ content.decEntriesCount();
}
else {
++i;
}
auto& ecsIdx = map->d_ecsIndex.get<OrderedTag>();
for (auto i = ecsIdx.lower_bound(name); i != ecsIdx.end();) {
- if (!i->d_qname.isPartOf(name))
+ if (!i->d_qname.isPartOf(name)) {
break;
+ }
if (i->d_qtype == qtype || qtype == 0xffff) {
i = ecsIdx.erase(i);
}
return false;
}
- CacheEntry ce = *iter;
- if (ce.d_ttd < now) {
+ CacheEntry cacheEntry = *iter;
+ if (cacheEntry.d_ttd < now) {
return false; // would be dead anyhow
}
- uint32_t maxTTL = static_cast<uint32_t>(ce.d_ttd - now);
+ auto maxTTL = static_cast<uint32_t>(cacheEntry.d_ttd - now);
if (maxTTL > newTTL) {
lockedShard->d_cachecachevalid = false;
time_t newTTD = now + newTTL;
- if (ce.d_ttd > newTTD) {
- ce.d_ttd = newTTD;
- lockedShard->d_map.replace(iter, ce);
+ if (cacheEntry.d_ttd > newTTD) {
+ cacheEntry.d_ttd = newTTD;
+ lockedShard->d_map.replace(iter, cacheEntry);
}
return true;
}
return false;
}
-bool MemRecursorCache::updateValidationStatus(time_t now, const DNSName& qname, const QType qt, const ComboAddress& who, const OptTag& routingTag, bool requireAuth, vState newState, boost::optional<time_t> capTTD)
+bool MemRecursorCache::updateValidationStatus(time_t now, const DNSName& qname, const QType qtype, const ComboAddress& who, const OptTag& routingTag, bool requireAuth, vState newState, boost::optional<time_t> capTTD)
{
- uint16_t qtype = qt.getCode();
if (qtype == QType::ANY) {
throw std::runtime_error("Trying to update the DNSSEC validation status of all (via ANY) records for " + qname.toLogString());
}
throw std::runtime_error("Trying to update the DNSSEC validation status of several (via ADDR) records for " + qname.toLogString());
}
- auto& mc = getMap(qname);
- auto map = mc.lock();
+ auto& content = getMap(qname);
+ auto map = content.lock();
bool updated = false;
if (!map->d_ecsIndex.empty() && !routingTag) {
return true;
}
- auto entries = getEntries(*map, qname, qt, routingTag);
+ auto entries = getEntries(*map, qname, qtype, routingTag);
for (auto i = entries.first; i != entries.second; ++i) {
auto firstIndexIterator = map->d_map.project<OrderedTag>(i);
return updated;
}
-uint64_t MemRecursorCache::doDump(int fd, size_t maxCacheEntries)
+uint64_t MemRecursorCache::doDump(int fileDesc, size_t maxCacheEntries)
{
- int newfd = dup(fd);
+ int newfd = dup(fileDesc);
if (newfd == -1) {
return 0;
}
- auto fp = std::unique_ptr<FILE, int (*)(FILE*)>(fdopen(newfd, "w"), fclose);
- if (!fp) { // dup probably failed
+ auto filePtr = std::unique_ptr<FILE, int (*)(FILE*)>(fdopen(newfd, "w"), fclose);
+ if (!filePtr) { // dup probably failed
close(newfd);
return 0;
}
- fprintf(fp.get(), "; main record cache dump follows\n;\n");
+ fprintf(filePtr.get(), "; main record cache dump follows\n;\n");
uint64_t count = 0;
size_t shardNumber = 0;
size_t min = std::numeric_limits<size_t>::max();
for (auto& shard : d_maps) {
auto lockedShard = shard.lock();
const auto shardSize = lockedShard->d_map.size();
- fprintf(fp.get(), "; record cache shard %zu; size %zu\n", shardNumber, shardSize);
+ fprintf(filePtr.get(), "; record cache shard %zu; size %zu\n", shardNumber, shardSize);
min = std::min(min, shardSize);
max = std::max(max, shardSize);
shardNumber++;
const auto& sidx = lockedShard->d_map.get<SequencedTag>();
time_t now = time(nullptr);
- for (const auto& i : sidx) {
- for (const auto& j : i.d_records) {
+ for (const auto& recordSet : sidx) {
+ for (const auto& record : recordSet.d_records) {
count++;
try {
- fprintf(fp.get(), "%s %" PRIu32 " %" PRId64 " IN %s %s ; (%s) auth=%i zone=%s from=%s nm=%s rtag=%s ss=%hd\n", i.d_qname.toString().c_str(), i.d_orig_ttl, static_cast<int64_t>(i.d_ttd - now), i.d_qtype.toString().c_str(), j->getZoneRepresentation().c_str(), vStateToString(i.d_state).c_str(), i.d_auth, i.d_authZone.toLogString().c_str(), i.d_from.toString().c_str(), i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str(), !i.d_rtag ? "" : i.d_rtag.get().c_str(), i.d_servedStale);
+ fprintf(filePtr.get(), "%s %" PRIu32 " %" PRId64 " IN %s %s ; (%s) auth=%i zone=%s from=%s nm=%s rtag=%s ss=%hd\n", recordSet.d_qname.toString().c_str(), recordSet.d_orig_ttl, static_cast<int64_t>(recordSet.d_ttd - now), recordSet.d_qtype.toString().c_str(), record->getZoneRepresentation().c_str(), vStateToString(recordSet.d_state).c_str(), static_cast<int>(recordSet.d_auth), recordSet.d_authZone.toLogString().c_str(), recordSet.d_from.toString().c_str(), recordSet.d_netmask.empty() ? "" : recordSet.d_netmask.toString().c_str(), !recordSet.d_rtag ? "" : recordSet.d_rtag.get().c_str(), recordSet.d_servedStale);
}
catch (...) {
- fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
+ fprintf(filePtr.get(), "; error printing '%s'\n", recordSet.d_qname.empty() ? "EMPTY" : recordSet.d_qname.toString().c_str());
}
}
- for (const auto& sig : i.d_signatures) {
+ for (const auto& sig : recordSet.d_signatures) {
count++;
try {
- fprintf(fp.get(), "%s %" PRIu32 " %" PRId64 " IN RRSIG %s ; %s\n", i.d_qname.toString().c_str(), i.d_orig_ttl, static_cast<int64_t>(i.d_ttd - now), sig->getZoneRepresentation().c_str(), i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str());
+ fprintf(filePtr.get(), "%s %" PRIu32 " %" PRId64 " IN RRSIG %s ; %s\n", recordSet.d_qname.toString().c_str(), recordSet.d_orig_ttl, static_cast<int64_t>(recordSet.d_ttd - now), sig->getZoneRepresentation().c_str(), recordSet.d_netmask.empty() ? "" : recordSet.d_netmask.toString().c_str());
}
catch (...) {
- fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
+ fprintf(filePtr.get(), "; error printing '%s'\n", recordSet.d_qname.empty() ? "EMPTY" : recordSet.d_qname.toString().c_str());
}
}
}
}
- fprintf(fp.get(), "; main record cache size: %zu/%zu shards: %zu min/max shard size: %zu/%zu\n", size(), maxCacheEntries, d_maps.size(), min, max);
+ fprintf(filePtr.get(), "; main record cache size: %zu/%zu shards: %zu min/max shard size: %zu/%zu\n", size(), maxCacheEntries, d_maps.size(), min, max);
return count;
}
void MemRecursorCache::doPrune(time_t now, size_t keep)
{
size_t cacheSize = size();
- pruneMutexCollectionsVector<SequencedTag>(now, *this, d_maps, keep, cacheSize);
+ pruneMutexCollectionsVector<SequencedTag>(now, d_maps, keep, cacheSize);
}
namespace boost
// The time a stale cache entry is extended
static constexpr uint32_t s_serveStaleExtensionPeriod = 30;
- size_t size() const;
- size_t bytes();
- pair<uint64_t, uint64_t> stats();
- size_t ecsIndexSize();
+ [[nodiscard]] size_t size() const;
+ [[nodiscard]] size_t bytes();
+ [[nodiscard]] pair<uint64_t, uint64_t> stats();
+ [[nodiscard]] size_t ecsIndexSize();
- typedef boost::optional<std::string> OptTag;
+ using OptTag = boost::optional<std::string>;
- typedef uint8_t Flags;
+ using Flags = uint8_t;
static constexpr Flags None = 0;
static constexpr Flags RequireAuth = 1 << 0;
static constexpr Flags Refresh = 1 << 1;
static constexpr Flags ServeStale = 1 << 2;
- time_t get(time_t, const DNSName& qname, const QType qt, Flags flags, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag = boost::none, vector<std::shared_ptr<const RRSIGRecordContent>>* signatures = nullptr, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs = nullptr, bool* variable = nullptr, vState* state = nullptr, bool* wasAuth = nullptr, DNSName* fromAuthZone = nullptr, ComboAddress* fromAuthIP = nullptr);
+ [[nodiscard]] time_t get(time_t, const DNSName& qname, QType qtype, Flags flags, vector<DNSRecord>* res, const ComboAddress& who, const OptTag& routingTag = boost::none, vector<std::shared_ptr<const RRSIGRecordContent>>* signatures = nullptr, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs = nullptr, bool* variable = nullptr, vState* state = nullptr, bool* wasAuth = nullptr, DNSName* fromAuthZone = nullptr, ComboAddress* fromAuthIP = nullptr);
- void replace(time_t, const DNSName& qname, const QType qt, const vector<DNSRecord>& content, const vector<shared_ptr<const RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, const DNSName& authZone, boost::optional<Netmask> ednsmask = boost::none, const OptTag& routingTag = boost::none, vState state = vState::Indeterminate, boost::optional<ComboAddress> from = boost::none, bool refresh = false, time_t ttl_time = time(nullptr));
+ void replace(time_t, const DNSName& qname, QType qtype, const vector<DNSRecord>& content, const vector<shared_ptr<const RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, const DNSName& authZone, boost::optional<Netmask> ednsmask = boost::none, const OptTag& routingTag = boost::none, vState state = vState::Indeterminate, boost::optional<ComboAddress> from = boost::none, bool refresh = false, time_t ttl_time = time(nullptr));
void doPrune(time_t now, size_t keep);
- uint64_t doDump(int fd, size_t maxCacheEntries);
+ uint64_t doDump(int fileDesc, size_t maxCacheEntries);
size_t doWipeCache(const DNSName& name, bool sub, QType qtype = 0xffff);
bool doAgeCache(time_t now, const DNSName& name, QType qtype, uint32_t newTTL);
- bool updateValidationStatus(time_t now, const DNSName& qname, QType qt, const ComboAddress& who, const OptTag& routingTag, bool requireAuth, vState newState, boost::optional<time_t> capTTD);
-
- pdns::stat_t cacheHits{0}, cacheMisses{0};
+ bool updateValidationStatus(time_t now, const DNSName& qname, QType qtype, const ComboAddress& who, const OptTag& routingTag, bool requireAuth, vState newState, boost::optional<time_t> capTTD);
static void resetStaticsForTests();
+ [[nodiscard]] auto getCacheHits() const
+ {
+ return cacheHits.load();
+ }
+ [[nodiscard]] auto getCacheMisses() const
+ {
+ return cacheMisses.load();
+ }
+
+ void incCacheHits()
+ {
+ ++cacheHits;
+ }
+ void incCacheMisses()
+ {
+ ++cacheMisses;
+ }
+
private:
+ pdns::stat_t cacheHits{0}, cacheMisses{0};
+
struct CacheEntry
{
CacheEntry(const std::tuple<DNSName, QType, OptTag, Netmask>& key, bool auth) :
- d_qname(std::get<0>(key)), d_netmask(std::get<3>(key).getNormalized()), d_rtag(std::get<2>(key)), d_state(vState::Indeterminate), d_ttd(0), d_orig_ttl{0}, d_servedStale(0), d_qtype(std::get<1>(key)), d_auth(auth), d_submitted(false)
+ d_qname(std::get<0>(key)), d_netmask(std::get<3>(key).getNormalized()), d_rtag(std::get<2>(key)), d_qtype(std::get<1>(key)), d_auth(auth)
{
}
- typedef vector<std::shared_ptr<const DNSRecordContent>> records_t;
+ using records_t = vector<std::shared_ptr<const DNSRecordContent>>;
bool isStale(time_t now) const
{
if (s_maxServedStaleExtensions > 0) {
return d_ttd + static_cast<time_t>(s_maxServedStaleExtensions) * std::min(s_serveStaleExtensionPeriod, d_orig_ttl) < now;
}
- else {
- return d_ttd < now;
- }
+ return d_ttd < now;
}
bool isEntryUsable(time_t now, bool serveStale) const
ComboAddress d_from;
Netmask d_netmask;
OptTag d_rtag;
- mutable vState d_state;
- mutable time_t d_ttd;
- uint32_t d_orig_ttl;
- mutable uint16_t d_servedStale;
+ mutable vState d_state{vState::Indeterminate};
+ mutable time_t d_ttd{0};
+ uint32_t d_orig_ttl{0};
+ mutable uint16_t d_servedStale{0};
QType d_qtype;
bool d_auth;
- mutable bool d_submitted; // whether this entry has been queued for refetch
+ mutable bool d_submitted{false}; // whether this entry has been queued for refetch
};
/* The ECS Index (d_ecsIndex) keeps track of whether there is any ECS-specific
class ECSIndexEntry
{
public:
- ECSIndexEntry(const DNSName& qname, QType qtype) :
- d_nmt(), d_qname(qname), d_qtype(qtype)
+ ECSIndexEntry(DNSName qname, QType qtype) :
+ d_qname(std::move(qname)), d_qtype(qtype)
{
}
- Netmask lookupBestMatch(const ComboAddress& addr) const
+ [[nodiscard]] Netmask lookupBestMatch(const ComboAddress& addr) const
{
- const auto best = d_nmt.lookup(addr);
+ const auto* best = d_nmt.lookup(addr);
if (best != nullptr) {
return best->first;
}
- return Netmask();
+ return {};
}
- void addMask(const Netmask& nm) const
+ void addMask(const Netmask& netmask) const
{
- d_nmt.insert(nm).second = true;
+ d_nmt.insert(netmask).second = true;
}
- void removeNetmask(const Netmask& nm) const
+ void removeNetmask(const Netmask& netmask) const
{
- d_nmt.erase(nm);
+ d_nmt.erase(netmask);
}
- bool isEmpty() const
+ [[nodiscard]] bool isEmpty() const
{
return d_nmt.empty();
}
{
};
- typedef multi_index_container<
+ using cache_t = multi_index_container<
CacheEntry,
indexed_by<
ordered_unique<tag<OrderedTag>,
member<CacheEntry, QType, &CacheEntry::d_qtype>,
member<CacheEntry, OptTag, &CacheEntry::d_rtag>,
member<CacheEntry, Netmask, &CacheEntry::d_netmask>>,
- composite_key_compare<CanonDNSNameCompare, std::less<QType>, std::less<OptTag>, std::less<Netmask>>>,
+ composite_key_compare<CanonDNSNameCompare, std::less<>, std::less<>, std::less<>>>,
sequenced<tag<SequencedTag>>,
hashed_non_unique<tag<NameAndRTagOnlyHashedTag>,
composite_key<
CacheEntry,
member<CacheEntry, DNSName, &CacheEntry::d_qname>,
- member<CacheEntry, OptTag, &CacheEntry::d_rtag>>>>>
- cache_t;
+ member<CacheEntry, OptTag, &CacheEntry::d_rtag>>>>>;
- typedef MemRecursorCache::cache_t::index<MemRecursorCache::OrderedTag>::type::iterator OrderedTagIterator_t;
- typedef MemRecursorCache::cache_t::index<MemRecursorCache::NameAndRTagOnlyHashedTag>::type::iterator NameAndRTagOnlyHashedTagIterator_t;
+ using OrderedTagIterator_t = MemRecursorCache::cache_t::index<MemRecursorCache::OrderedTag>::type::iterator;
+ using NameAndRTagOnlyHashedTagIterator_t = MemRecursorCache::cache_t::index<MemRecursorCache::NameAndRTagOnlyHashedTag>::type::iterator;
- typedef multi_index_container<
+ using ecsIndex_t = multi_index_container<
ECSIndexEntry,
indexed_by<
hashed_unique<tag<HashedTag>,
ECSIndexEntry,
member<ECSIndexEntry, DNSName, &ECSIndexEntry::d_qname>,
member<ECSIndexEntry, QType, &ECSIndexEntry::d_qtype>>,
- composite_key_compare<CanonDNSNameCompare, std::less<QType>>>>>
- ecsIndex_t;
+ composite_key_compare<CanonDNSNameCompare, std::less<>>>>>;
- typedef std::pair<NameAndRTagOnlyHashedTagIterator_t, NameAndRTagOnlyHashedTagIterator_t> Entries;
+ using Entries = std::pair<NameAndRTagOnlyHashedTagIterator_t, NameAndRTagOnlyHashedTagIterator_t>;
struct MapCombo
{
- MapCombo() {}
+ MapCombo() = default;
+ ~MapCombo() = default;
MapCombo(const MapCombo&) = delete;
MapCombo& operator=(const MapCombo&) = delete;
+ MapCombo(MapCombo&&) = delete;
+ MapCombo& operator=(MapCombo&&) = delete;
+
struct LockedContent
{
cache_t d_map;
{
d_cachecachevalid = false;
}
+
+ void preRemoval(const CacheEntry& entry)
+ {
+ if (entry.d_netmask.empty()) {
+ return;
+ }
+
+ auto key = std::tie(entry.d_qname, entry.d_qtype);
+ auto ecsIndexEntry = d_ecsIndex.find(key);
+ if (ecsIndexEntry != d_ecsIndex.end()) {
+ ecsIndexEntry->removeNetmask(entry.d_netmask);
+ if (ecsIndexEntry->isEmpty()) {
+ d_ecsIndex.erase(ecsIndexEntry);
+ }
+ }
+ }
};
LockGuardedTryHolder<LockedContent> lock()
static time_t fakeTTD(OrderedTagIterator_t& entry, const DNSName& qname, QType qtype, time_t ret, time_t now, uint32_t origTTL, bool refresh);
- bool entryMatches(OrderedTagIterator_t& entry, QType qt, bool requireAuth, const ComboAddress& who);
- Entries getEntries(MapCombo::LockedContent& content, const DNSName& qname, const QType qt, const OptTag& rtag);
- cache_t::const_iterator getEntryUsingECSIndex(MapCombo::LockedContent& content, time_t now, const DNSName& qname, QType qtype, bool requireAuth, const ComboAddress& who, bool serveStale);
-
- time_t handleHit(MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector<DNSRecord>* res, vector<std::shared_ptr<const RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* authZone, ComboAddress* fromAuthIP);
- void updateStaleEntry(time_t now, OrderedTagIterator_t& entry);
- void handleServeStaleBookkeeping(time_t, bool, OrderedTagIterator_t&);
+ static bool entryMatches(OrderedTagIterator_t& entry, QType qtype, bool requireAuth, const ComboAddress& who);
+ static Entries getEntries(MapCombo::LockedContent& map, const DNSName& qname, QType qtype, const OptTag& rtag);
+ static cache_t::const_iterator getEntryUsingECSIndex(MapCombo::LockedContent& map, time_t now, const DNSName& qname, QType qtype, bool requireAuth, const ComboAddress& who, bool serveStale);
-public:
- void preRemoval(MapCombo::LockedContent& map, const CacheEntry& entry)
- {
- if (entry.d_netmask.empty()) {
- return;
- }
-
- auto key = std::tie(entry.d_qname, entry.d_qtype);
- auto ecsIndexEntry = map.d_ecsIndex.find(key);
- if (ecsIndexEntry != map.d_ecsIndex.end()) {
- ecsIndexEntry->removeNetmask(entry.d_netmask);
- if (ecsIndexEntry->isEmpty()) {
- map.d_ecsIndex.erase(ecsIndexEntry);
- }
- }
- }
+ static time_t handleHit(time_t now, MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector<DNSRecord>* res, vector<std::shared_ptr<const RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, boost::optional<vState>& state, bool* wasAuth, DNSName* authZone, ComboAddress* fromAuthIP);
+ static void updateStaleEntry(time_t now, OrderedTagIterator_t& entry);
+ static void handleServeStaleBookkeeping(time_t, bool, OrderedTagIterator_t&);
};
namespace boost
dr.d_place = DNSResourceRecord::ANSWER;
dr.d_ttl = 86400;
dr.d_type = QType::SOA;
- dr.setContent(DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800"));
+ dr.setContent(DNSRecordContent::make(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800"));
SyncRes::AuthDomain ad;
ad.d_rdForward = false;
auto recType = address.isIPv6() ? QType::AAAA : QType::A;
dr.d_type = recType;
dr.d_ttl = 86400;
- dr.setContent(DNSRecordContent::mastermake(recType, QClass::IN, address.toStringNoInterface()));
+ dr.setContent(DNSRecordContent::make(recType, QClass::IN, address.toStringNoInterface()));
entry->second.d_records.insert(dr);
}
// Add a PTR entry for the primary name for reverse lookups.
dr.d_type = QType::PTR;
- dr.setContent(DNSRecordContent::mastermake(QType::PTR, 1, DNSName(canonicalHostname).toString()));
+ dr.setContent(DNSRecordContent::make(QType::PTR, 1, DNSName(canonicalHostname).toString()));
ad.d_records.insert(dr);
addToDomainMap(newMap, std::move(ad), dr.d_name, log, false, true);
return ret;
}
-static void convertServersForAD(const std::string& zone, const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, Logr::log_t log, bool verbose = true)
+static void convertServersForAD(const std::string& zone, const std::string& input, SyncRes::AuthDomain& authDomain, const char* sepa, Logr::log_t log, bool verbose = true)
{
vector<string> servers;
stringtok(servers, input, sepa);
- ad.d_servers.clear();
+ authDomain.d_servers.clear();
vector<string> addresses;
- for (auto server = servers.begin(); server != servers.end(); ++server) {
- ComboAddress addr = parseIPAndPort(*server, 53);
- ad.d_servers.push_back(addr);
+ for (auto& server : servers) {
+ ComboAddress addr = parseIPAndPort(server, 53);
+ authDomain.d_servers.push_back(addr);
if (verbose) {
addresses.push_back(addr.toStringWithPort());
}
if (verbose) {
if (!g_slogStructured) {
g_log << Logger::Info << "Redirecting queries for zone '" << zone << "' ";
- if (ad.d_rdForward) {
+ if (authDomain.d_rdForward) {
g_log << "with recursion ";
}
g_log << "to: ";
bool first = true;
- for (const auto& a : addresses) {
+ for (const auto& address : addresses) {
if (!first) {
g_log << ", ";
}
else {
first = false;
}
- g_log << a;
+ g_log << address;
}
g_log << endl;
}
else {
- log->info(Logr::Info, "Redirecting queries", "zone", Logging::Loggable(zone), "recursion", Logging::Loggable(ad.d_rdForward), "addresses", Logging::IterLoggable(addresses.begin(), addresses.end()));
+ log->info(Logr::Info, "Redirecting queries", "zone", Logging::Loggable(zone), "recursion", Logging::Loggable(authDomain.d_rdForward), "addresses", Logging::IterLoggable(addresses.begin(), addresses.end()));
}
}
}
static void* pleaseUseNewSDomainsMap(std::shared_ptr<SyncRes::domainmap_t> newmap)
{
SyncRes::setDomainMap(std::move(newmap));
- return 0;
+ return nullptr;
}
string reloadZoneConfiguration(bool yaml)
{
setThreadName("rec/rpzixfr");
bool isPreloaded = sr != nullptr;
- auto luaconfsLocal = g_luaconfs.getLocal();
-
auto logger = g_slog->withName("rpz");
/* we can _never_ modify this zone directly, we need to do a full copy then replace the existing zone */
- std::shared_ptr<DNSFilterEngine::Zone> oldZone = luaconfsLocal->dfe.getZone(zoneIdx);
+ std::shared_ptr<DNSFilterEngine::Zone> oldZone = g_luaconfs.getLocal()->dfe.getZone(zoneIdx);
if (!oldZone) {
SLOG(g_log << Logger::Error << "Unable to retrieve RPZ zone with index " << zoneIdx << " from the configuration, exiting" << endl,
logger->error(Logr::Error, "Unable to retrieve RPZ zone from configuration", "index", Logging::Loggable(zoneIdx)));
incRPZFailedTransfers(polName);
}
}
-
+ // Release newZone before (long) sleep to reduce memory usage
+ newZone = nullptr;
if (!sr) {
sleep(refresh);
}
bool skipRefreshDelay = isPreloaded;
for (;;) {
+ // Don't hold on to oldZone, it well be re-assigned after sleep in the try block
+ oldZone = nullptr;
DNSRecord dr;
dr.setContent(sr);
else {
sleep(refresh);
}
+ auto luaconfsLocal = g_luaconfs.getLocal();
if (luaconfsLocal->generation != configGeneration) {
/* the configuration has been reloaded, meaning that a new thread
if (luaconfsLocal->generation != configGeneration) {
SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl,
- logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"))
+ logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"));
return;
}
oldZone = luaconfsLocal->dfe.getZone(zoneIdx);
#include "validate-recursor.hh"
#include "secpoll.hh"
-#include <stdint.h>
+#include <cstdint>
#ifndef PACKAGEVERSION
#define PACKAGEVERSION getPDNSVersion()
#endif
void doSecPoll(time_t* last_secpoll, Logr::log_t log)
{
- if (::arg()["security-poll-suffix"].empty())
+ if (::arg()["security-poll-suffix"].empty()) {
return;
+ }
string pkgv(PACKAGEVERSION);
- struct timeval now;
- gettimeofday(&now, 0);
+ struct timeval now
+ {
+ };
+ Utility::gettimeofday(&now);
/* update last_secpoll right now, even if it fails
we don't want to retry right away and hammer the server */
*last_secpoll = now.tv_sec;
- SyncRes sr(now);
+ SyncRes resolver(now);
if (g_dnssecmode != DNSSECMode::Off) {
- sr.setDoDNSSEC(true);
- sr.setDNSSECValidationRequested(true);
+ resolver.setDoDNSSEC(true);
+ resolver.setDNSSECValidationRequested(true);
}
- sr.setId("SecPoll");
+ resolver.setId("SecPoll");
vector<DNSRecord> ret;
string version = "recursor-" + pkgv;
string qstring(version.substr(0, 63) + ".security-status." + ::arg()["security-poll-suffix"]);
- if (*qstring.rbegin() != '.')
+ if (*qstring.rbegin() != '.') {
qstring += '.';
+ }
boost::replace_all(qstring, "+", "_");
boost::replace_all(qstring, "~", "_");
vState state = vState::Indeterminate;
DNSName query(qstring);
- int res = sr.beginResolve(query, QType(QType::TXT), 1, ret);
+ int res = resolver.beginResolve(query, QType(QType::TXT), 1, ret);
- if (g_dnssecmode != DNSSECMode::Off && res) {
- state = sr.getValidationState();
+ if (g_dnssecmode != DNSSECMode::Off && res != 0) {
+ state = resolver.getValidationState();
}
auto vlog = log->withValues("version", Logging::Loggable(pkgv), "query", Logging::Loggable(query));
if (vStateIsBogus(state)) {
SLOG(g_log << Logger::Error << "Failed to retrieve security status update for '" + pkgv + "' on '" << query << "', DNSSEC validation result was Bogus!" << endl,
vlog->info(Logr::Error, "Failed to retrieve security status update", "validationResult", Logging::Loggable(vStateToString(state))));
- if (g_security_status == 1) // If we were OK, go to unknown
+ if (g_security_status == 1) { // If we were OK, go to unknown
g_security_status = 0;
+ }
return;
}
}
string security_message;
- int security_status = g_security_status;
+ int security_status = static_cast<int>(g_security_status);
try {
processSecPoll(res, ret, security_status, security_message);
if (rename(tmpfilename.c_str(), yamlfilename.c_str()) != 0) {
int err = errno;
log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(tmpfilename), "to", Logging::Loggable(yamlfilename));
- rename((path + ".converted").c_str(), path.c_str());
+ if (rename((path + ".converted").c_str(), path.c_str()) != 0) {
+ err = errno;
+ log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(path + ".converted"), "to", Logging::Loggable(path));
+ }
throw runtime_error("YAML Conversion");
}
log->info(Logr::Notice, "Converted to YAML", "file", Logging::Loggable(path), "to", Logging::Loggable(yamlfilename));
::rust::String section;
::rust::String fieldname;
::rust::String type_name;
- pdns::rust::settings::rec::Value rustvalue;
+ pdns::rust::settings::rec::Value rustvalue = {false, 0, 0.0, "", {}, {}, {}};
if (pdns::settings::rec::oldKVToBridgeStruct(var, val, section, fieldname, type_name, rustvalue)) {
auto overriding = !mainFile && !incremental && !simpleRustType(type_name);
auto [existing, inserted] = map.emplace(std::pair{std::pair{section, fieldname}, pdns::rust::settings::rec::OldStyle{section, fieldname, var, type_name, rustvalue, overriding}});
::rust::String section;
::rust::String fieldname;
::rust::String type_name;
- pdns::rust::settings::rec::Value rustvalue;
-
+ pdns::rust::settings::rec::Value rustvalue{false, 0, 0.0, "", {}, {}, {}};
string name = var;
string val = arg().getDefault(var);
if (pdns::settings::rec::oldKVToBridgeStruct(name, val, section, fieldname, type_name, rustvalue)) {
- '::2'
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 further.
- In the future we might add a check for this case.
+ It depends on the specific setting how the sequence is processed and interpreted further.
Socket Address
^^^^^^^^^^^^^^
'name' : 'extended_resolution_errors',
'section' : 'recursor',
'type' : LType.Bool,
- 'default' : 'false',
+ 'default' : 'true',
'help' : 'If set, send an EDNS Extended Error extension on resolution failures, like DNSSEC validation errors',
'doc' : '''
If set, the recursor will add an EDNS Extended Error (:rfc:`8914`) to responses when resolution failed, like DNSSEC validation errors, explaining the reason it failed. This setting is not needed to allow setting custom error codes from Lua or from a RPZ hit.
''',
- 'versionadded': '4.5.0'
+ 'versionadded': '4.5.0',
+ 'versionchanged': ('5.0.0', 'Default changed to enabled, previously it was disabled.'),
},
{
'name' : 'forward_zones',
},
{
'name' : 'max_qperq',
- 'section' : 'recursor',
+ 'section' : 'outgoing',
'type' : LType.Uint64,
'default' : '60',
'help' : 'Maximum outgoing queries per query',
},
{
'name' : 'max_ns_address_qperq',
- 'section' : 'recursor',
+ 'section' : 'outgoing',
'type' : LType.Uint64,
'default' : '10',
'help' : 'Maximum outgoing NS address queries per query',
},
{
'name' : 'max_ns_per_resolve',
- 'section' : 'recursor',
+ 'section' : 'outgoing',
'type' : LType.Uint64,
'default' : '13',
'help' : 'Maximum number of NS records to consider to resolve a name, 0 is no limit',
},
{
'name' : 'non_resolving_ns_max_fails',
- 'section' : 'recursor',
+ 'section' : 'outgoing',
'type' : LType.Uint64,
'default' : '5',
'help' : 'Number of failed address resolves of a nameserver to start throttling it, 0 is disabled',
},
{
'name' : 'non_resolving_ns_throttle_time',
- 'section' : 'recursor',
+ 'section' : 'outgoing',
'type' : LType.Uint64,
'default' : '60',
'help' : 'Number of seconds to throttle a nameserver with a name failing to resolve',
'name' : 'nsec3_max_iterations',
'section' : 'dnssec',
'type' : LType.Uint64,
- 'default' : '150',
+ 'default' : '50',
'help' : 'Maximum number of iterations allowed for an NSEC3 record',
'doc' : '''
Maximum number of iterations allowed for an NSEC3 record.
-If an answer containing an NSEC3 record with more iterations is received, its DNSSEC validation status is treated as Insecure.
+If an answer containing an NSEC3 record with more iterations is received, its DNSSEC validation status is treated as ``Insecure``.
''',
'versionadded': '4.1.0',
- 'versionchanged': ('4.5.2', 'Default is now 150, was 2500 before.')
+ 'versionchanged': [('4.5.2', 'Default is now 150, was 2500 before.'),
+ ('5.0.0', 'Default is now 50, was 150 before.')]
},
{
'name' : 'ttl',
},
{
'name' : 'server_down_max_fails',
- 'section' : 'recursor',
+ 'section' : 'outgoing',
'type' : LType.Uint64,
'default' : '64',
'help' : 'Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )',
},
{
'name' : 'server_down_throttle_time',
- 'section' : 'recursor',
+ 'section' : 'outgoing',
'type' : LType.Uint64,
'default' : '60',
'help' : 'Number of seconds to throttle all queries to a server after being marked as down',
},
{
'name' : 'bypass_server_throttling_probability',
- 'section' : 'recursor',
+ 'section' : 'outgoing',
'type' : LType.Uint64,
'default' : '25',
'help' : 'Determines the probability of a server marked down to be used anyway',
'default' : 'normal',
'help' : 'Amount of logging in the webserver (none, normal, detailed)',
'doc' : '''
-One of ``one``, ``normal``, ``detailed``.
+One of ``none``, ``normal``, ``detailed``.
The amount of logging the webserver must do. 'none' means no useful webserver information will be logged.
When set to 'normal', the webserver will log a line per request that should be familiar::
dr.d_ttl = 86400;
for (const auto& ans : answers) {
dr.d_type = ans.first;
- dr.setContent(DNSRecordContent::mastermake(ans.first, qclass, ans.second));
+ dr.setContent(DNSRecordContent::make(ans.first, qclass, ans.second));
ret.push_back(dr);
}
}
auto insertionPair = beenthere.insert(std::move(answer));
if (!insertionPair.second) {
brokeloop = true;
- LOG(prefix << qname << ": We have NS in cache for '" << subdomain << "' but part of LOOP (already seen " << answer.qname << ")! Trying less specific NS" << endl);
+ LOG(prefix << qname << ": We have NS in cache for '" << subdomain << "' but part of LOOP (already seen " << insertionPair.first->qname << ")! Trying less specific NS" << endl);
;
if (doLog())
for (set<GetBestNSAnswer>::const_iterator j = beenthere.begin(); j != beenthere.end(); ++j) {
/* blocked A */
DNSRecord dr;
dr.d_type = QType::A;
- dr.setContent(DNSRecordContent::mastermake(QType::A, QClass::IN, responseIP.toString()));
+ dr.setContent(DNSRecordContent::make(QType::A, QClass::IN, responseIP.toString()));
const auto matchingPolicy = dfe.getPostPolicy({dr}, std::unordered_map<std::string, bool>(), DNSFilterEngine::maximumPriority);
BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::ResponseIP);
BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Drop);
/* allowed A */
DNSRecord dr;
dr.d_type = QType::A;
- dr.setContent(DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.142"));
+ dr.setContent(DNSRecordContent::make(QType::A, QClass::IN, "192.0.2.142"));
const auto matchingPolicy = dfe.getPostPolicy({dr}, std::unordered_map<std::string, bool>(), DNSFilterEngine::maximumPriority);
BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::None);
DNSFilterEngine::Policy zonePolicy;
const DNSName bad1("bad1.example.com.");
const DNSName bad2("bad2.example.com.");
- zone->addQNameTrigger(bad1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden.example.net.")}));
+ zone->addQNameTrigger(bad1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "garden.example.net.")}));
BOOST_CHECK_EQUAL(zone->size(), 1U);
- zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.1")}));
+ zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "192.0.2.1")}));
BOOST_CHECK_EQUAL(zone->size(), 2U);
- zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.2")}));
+ zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "192.0.2.2")}));
BOOST_CHECK_EQUAL(zone->size(), 2U);
- zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::MX, QClass::IN, "10 garden-mail.example.net.")}));
+ zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::MX, QClass::IN, "10 garden-mail.example.net.")}));
BOOST_CHECK_EQUAL(zone->size(), 2U);
dfe.addZone(zone);
}
/* remove only one entry, one of the A local records */
- zone->rmQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.1")}));
+ zone->rmQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "192.0.2.1")}));
BOOST_CHECK_EQUAL(zone->size(), 2U);
{
const DNSName name("foo.example.com");
const Netmask nm1("192.168.1.0/24");
- zone->addClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "1.2.3.4")}));
- zone->addClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "1.2.3.5")}));
- zone->addClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::AAAA, QClass::IN, "::1234")}));
+ zone->addClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "1.2.3.4")}));
+ zone->addClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "1.2.3.5")}));
+ zone->addClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::AAAA, QClass::IN, "::1234")}));
BOOST_CHECK_EQUAL(zone->size(), 1U);
dfe.addZone(zone);
}
// Try to zap 1 nonexisting record
- zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "1.1.1.1")}));
+ zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "1.1.1.1")}));
// Zap a record using a wider netmask
- zone->rmClientTrigger(Netmask("192.168.0.0/16"), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "1.2.3.4")}));
+ zone->rmClientTrigger(Netmask("192.168.0.0/16"), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "1.2.3.4")}));
// Zap a record using a narrow netmask
- zone->rmClientTrigger(Netmask("192.168.1.1/32"), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "1.2.3.4")}));
+ zone->rmClientTrigger(Netmask("192.168.1.1/32"), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "1.2.3.4")}));
// Zap 1 existing record
- zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "1.2.3.5")}));
+ zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "1.2.3.5")}));
{ // A query should match one record now
const auto matchingPolicy = dfe.getClientPolicy(ComboAddress("192.168.1.1"), std::unordered_map<std::string, bool>(), DNSFilterEngine::maximumPriority);
}
// Zap one more A record
- zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "1.2.3.4")}));
+ zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "1.2.3.4")}));
// Zap now nonexisting record
- zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::A, QClass::IN, "1.2.3.4")}));
+ zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::A, QClass::IN, "1.2.3.4")}));
{ // AAAA query should still match one record
const auto matchingPolicy = dfe.getClientPolicy(ComboAddress("192.168.1.1"), std::unordered_map<std::string, bool>(), DNSFilterEngine::maximumPriority);
}
// Zap AAAA record
- zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::AAAA, QClass::IN, "::1234")}));
+ zone->rmClientTrigger(nm1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::AAAA, QClass::IN, "::1234")}));
{ // there should be no match left
const auto matchingPolicy = dfe.getClientPolicy(ComboAddress("192.168.1.1"), std::unordered_map<std::string, bool>(), DNSFilterEngine::maximumPriority);
const DNSName badWildcard("*.bad-wildcard.example.com.");
const DNSName badUnderWildcard("sub.bad-wildcard.example.com.");
- zone1->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden1a.example.net.")}));
- zone2->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden2a.example.net.")}));
- zone1->addQNameTrigger(badWildcard, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden1b.example.net.")}));
- zone2->addQNameTrigger(badUnderWildcard, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden2b.example.net.")}));
+ zone1->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "garden1a.example.net.")}));
+ zone2->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "garden2a.example.net.")}));
+ zone1->addQNameTrigger(badWildcard, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "garden1b.example.net.")}));
+ zone2->addQNameTrigger(badUnderWildcard, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "garden2b.example.net.")}));
dfe.addZone(zone1);
dfe.addZone(zone2);
const DNSName nsName("ns.bad.wolf.");
const ComboAddress responseIP("192.0.2.254");
- zone1->addClientTrigger(Netmask(clientIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "client1a.example.net.")}));
- zone1->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden1a.example.net.")}));
- zone1->addNSIPTrigger(Netmask(nsIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::NSIP, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "nsip1a.example.net.")}));
- zone1->addNSTrigger(nsName, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::NSDName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "nsname1a.example.net.")}));
- zone1->addResponseTrigger(Netmask(responseIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ResponseIP, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "response1a.example.net.")}));
+ zone1->addClientTrigger(Netmask(clientIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "client1a.example.net.")}));
+ zone1->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "garden1a.example.net.")}));
+ zone1->addNSIPTrigger(Netmask(nsIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::NSIP, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "nsip1a.example.net.")}));
+ zone1->addNSTrigger(nsName, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::NSDName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "nsname1a.example.net.")}));
+ zone1->addResponseTrigger(Netmask(responseIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ResponseIP, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "response1a.example.net.")}));
- zone2->addClientTrigger(Netmask(clientIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "client2a.example.net.")}));
- zone2->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden2a.example.net.")}));
- zone2->addNSIPTrigger(Netmask(nsIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::NSIP, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "nsip2a.example.net.")}));
- zone2->addNSTrigger(nsName, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::NSDName, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "nsname2a.example.net.")}));
- zone2->addResponseTrigger(Netmask(responseIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ResponseIP, 0, nullptr, {DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "response2a.example.net.")}));
+ zone2->addClientTrigger(Netmask(clientIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ClientIP, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "client2a.example.net.")}));
+ zone2->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "garden2a.example.net.")}));
+ zone2->addNSIPTrigger(Netmask(nsIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::NSIP, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "nsip2a.example.net.")}));
+ zone2->addNSTrigger(nsName, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::NSDName, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "nsname2a.example.net.")}));
+ zone2->addResponseTrigger(Netmask(responseIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::ResponseIP, 0, nullptr, {DNSRecordContent::make(QType::CNAME, QClass::IN, "response2a.example.net.")}));
dfe.addZone(zone1);
dfe.addZone(zone2);
/* blocked A in the response */
DNSRecord dr;
dr.d_type = QType::A;
- dr.setContent(DNSRecordContent::mastermake(QType::A, QClass::IN, responseIP.toString()));
+ dr.setContent(DNSRecordContent::make(QType::A, QClass::IN, responseIP.toString()));
const auto matchingPolicy = dfe.getPostPolicy({dr}, std::unordered_map<std::string, bool>(), DNSFilterEngine::maximumPriority);
BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::ResponseIP);
BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom);
/* blocked A in the response, except 1 is disabled and 2's priority is too high */
DNSRecord dr;
dr.d_type = QType::A;
- dr.setContent(DNSRecordContent::mastermake(QType::A, QClass::IN, responseIP.toString()));
+ dr.setContent(DNSRecordContent::make(QType::A, QClass::IN, responseIP.toString()));
const auto matchingPolicy = dfe.getPostPolicy({dr}, {{zone1->getName(), true}}, 1);
BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::None);
BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::NoAction);
rec.d_type = qtype;
rec.d_ttl = 600;
rec.d_place = DNSResourceRecord::AUTHORITY;
- rec.setContent(DNSRecordContent::mastermake(qtype, QClass::IN, content));
+ rec.setContent(DNSRecordContent::make(qtype, QClass::IN, content));
ret.records.push_back(rec);
{
static std::shared_ptr<DNSRecordContent> makeLocalhostRootDRC()
{
- return DNSRecordContent::mastermake(QType::SOA, QClass::IN, "localhost. root 1 604800 86400 2419200 604800");
+ return DNSRecordContent::make(QType::SOA, QClass::IN, "localhost. root 1 604800 86400 2419200 604800");
}
static std::shared_ptr<DNSRecordContent> makeLocalhostDRC()
{
- return DNSRecordContent::mastermake(QType::NS, QClass::IN, "localhost.");
+ return DNSRecordContent::make(QType::NS, QClass::IN, "localhost.");
}
static std::shared_ptr<DNSRecordContent> makePtrDRC(const std::string& name)
{
- return DNSRecordContent::mastermake(QType::PTR, QClass::IN, name);
+ return DNSRecordContent::make(QType::PTR, QClass::IN, name);
}
static void addDomainMapFixtureEntry(SyncRes::domainmap_t& domainMap,
{
domainMap[DNSName{name}] = SyncRes::AuthDomain{
.d_records = {
- DNSRecord(name, DNSRecordContent::mastermake(type, QClass::IN, address), type),
+ DNSRecord(name, DNSRecordContent::make(type, QClass::IN, address), type),
DNSRecord(name, makeLocalhostDRC(), QType::NS),
DNSRecord(name, makeLocalhostRootDRC(), QType::SOA),
},
"localhost" + actualSearchSuffix,
{DNSRecord("localhost" + actualSearchSuffix, makeLocalhostDRC(), QType::NS),
DNSRecord("localhost" + actualSearchSuffix, makeLocalhostRootDRC(), QType::SOA),
- DNSRecord("localhost" + actualSearchSuffix, DNSRecordContent::mastermake(QType::AAAA, QClass::IN, "::1"), QType::AAAA),
- DNSRecord("localhost" + actualSearchSuffix, DNSRecordContent::mastermake(QType::A, QClass::IN, "127.0.0.1"), QType::A)});
+ DNSRecord("localhost" + actualSearchSuffix, DNSRecordContent::make(QType::AAAA, QClass::IN, "::1"), QType::AAAA),
+ DNSRecord("localhost" + actualSearchSuffix, DNSRecordContent::make(QType::A, QClass::IN, "127.0.0.1"), QType::A)});
addDomainMapFixtureEntry(domainMap, "self" + actualSearchSuffix, QType::AAAA, "::1");
addDomainMapFixtureEntry(
domainMap,
}
catch (...) {
SLOG(g_log << Logger::Error << logprefix << "Unknown exception" << endl,
- req.d_slog->error(Logr::Error, "Exception handing request"))
+ req.d_slog->error(Logr::Error, "Exception handing request"));
}
}
auto repr = rec.getZoneRepresentation();
if (rec.qtype == QType::TXT) {
DLOG(g_log<<msgPrefix<<"Adjusting TXT content from ["<<repr<<"]"<<endl);
- auto drc = DNSRecordContent::mastermake(rec.qtype.getCode(), QClass::IN, repr);
+ auto drc = DNSRecordContent::make(rec.qtype.getCode(), QClass::IN, repr);
auto ser = drc->serialize(rec.qname, true, true);
auto rc = DNSRecordContent::deserialize(rec.qname, rec.qtype.getCode(), ser);
repr = rc->getZoneRepresentation(true);
B.getDomainMetadata(p.qdomain, "FORWARD-DNSUPDATE", forward);
if (forward.size() == 0 && ! ::arg().mustDo("forward-dnsupdate")) {
- g_log<<Logger::Notice<<msgPrefix<<"Not configured to forward to master, returning Refused."<<endl;
+ g_log << Logger::Notice << msgPrefix << "Not configured to forward to primary, returning Refused." << endl;
return RCode::Refused;
}
- for(const auto& remote : di.masters) {
- g_log<<Logger::Notice<<msgPrefix<<"Forwarding packet to master "<<remote<<endl;
+ for (const auto& remote : di.primaries) {
+ g_log << Logger::Notice << msgPrefix << "Forwarding packet to primary " << remote << endl;
if (!pdns::isQueryLocalAddressFamilyEnabled(remote.sin4.sin_family)) {
continue;
closesocket(sock);
}
catch(const PDNSException& e) {
- g_log<<Logger::Error<<"Error closing master forwarding socket after connect() failed: "<<e.reason<<endl;
+ g_log << Logger::Error << "Error closing primary forwarding socket after connect() failed: " << e.reason << endl;
}
continue;
}
closesocket(sock);
}
catch(const PDNSException& e) {
- g_log<<Logger::Error<<"Error closing master forwarding socket after write() failed: "<<e.reason<<endl;
+ g_log << Logger::Error << "Error closing primary forwarding socket after write() failed: " << e.reason << endl;
}
continue;
}
int res = waitForData(sock, 10, 0);
if (!res) {
- g_log<<Logger::Error<<msgPrefix<<"Timeout waiting for reply from master at "<<remote.toStringWithPort()<<endl;
+ g_log << Logger::Error << msgPrefix << "Timeout waiting for reply from primary at " << remote.toStringWithPort() << endl;
try {
closesocket(sock);
}
catch(const PDNSException& e) {
- g_log<<Logger::Error<<"Error closing master forwarding socket after a timeout occurred: "<<e.reason<<endl;
+ g_log << Logger::Error << "Error closing primary forwarding socket after a timeout occurred: " << e.reason << endl;
}
continue;
}
if (res < 0) {
- g_log<<Logger::Error<<msgPrefix<<"Error waiting for answer from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
+ g_log << Logger::Error << msgPrefix << "Error waiting for answer from primary at " << remote.toStringWithPort() << ", error:" << stringerror() << endl;
try {
closesocket(sock);
}
catch(const PDNSException& e) {
- g_log<<Logger::Error<<"Error closing master forwarding socket after an error occurred: "<<e.reason<<endl;
+ g_log << Logger::Error << "Error closing primary forwarding socket after an error occurred: " << e.reason << endl;
}
continue;
}
ssize_t recvRes;
recvRes = recv(sock, &lenBuf, sizeof(lenBuf), 0);
if (recvRes < 0 || static_cast<size_t>(recvRes) < sizeof(lenBuf)) {
- g_log<<Logger::Error<<msgPrefix<<"Could not receive data (length) from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
+ g_log << Logger::Error << msgPrefix << "Could not receive data (length) from primary at " << remote.toStringWithPort() << ", error:" << stringerror() << endl;
try {
closesocket(sock);
}
catch(const PDNSException& e) {
- g_log<<Logger::Error<<"Error closing master forwarding socket after recv() failed: "<<e.reason<<endl;
+ g_log << Logger::Error << "Error closing primary forwarding socket after recv() failed: " << e.reason << endl;
}
continue;
}
buffer.resize(packetLen);
recvRes = recv(sock, &buffer.at(0), packetLen, 0);
if (recvRes < 0) {
- g_log<<Logger::Error<<msgPrefix<<"Could not receive data (dnspacket) from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
+ g_log << Logger::Error << msgPrefix << "Could not receive data (dnspacket) from primary at " << remote.toStringWithPort() << ", error:" << stringerror() << endl;
try {
closesocket(sock);
}
catch(const PDNSException& e) {
- g_log<<Logger::Error<<"Error closing master forwarding socket after recv() failed: "<<e.reason<<endl;
+ g_log << Logger::Error << "Error closing primary forwarding socket after recv() failed: " << e.reason << endl;
}
continue;
}
closesocket(sock);
}
catch(const PDNSException& e) {
- g_log<<Logger::Error<<"Error closing master forwarding socket: "<<e.reason<<endl;
+ g_log << Logger::Error << "Error closing primary forwarding socket: " << e.reason << endl;
}
try {
return mdp.d_header.rcode;
}
catch (...) {
- g_log<<Logger::Error<<msgPrefix<<"Failed to parse response packet from master at "<<remote.toStringWithPort()<<endl;
+ g_log << Logger::Error << msgPrefix << "Failed to parse response packet from primary at " << remote.toStringWithPort() << endl;
continue;
}
}
- g_log<<Logger::Error<<msgPrefix<<"Failed to forward packet to master(s). Returning ServFail."<<endl;
+ g_log << Logger::Error << msgPrefix << "Failed to forward packet to primary(s). Returning ServFail." << endl;
return RCode::ServFail;
}
return RCode::NotAuth;
}
- if (di.kind == DomainInfo::Slave)
+ if (di.kind == DomainInfo::Secondary)
return forwardPacket(msgPrefix, p, di);
// Check if all the records provided are within the zone
zone.append("$");
purgeAuthCaches(zone);
- // Notify slaves
- if (di.kind == DomainInfo::Master) {
+ // Notify secondaries
+ if (di.kind == DomainInfo::Primary) {
vector<string> notify;
B.getDomainMetadata(p.qdomain, "NOTIFY-DNSUPDATE", notify);
if (!notify.empty() && notify.front() == "1") {
for(char c='a'; c<= 'm';++c) {
pw.startRecord(DNSName("com"), QType::NS, 3600, 1, DNSResourceRecord::AUTHORITY);
gtld[0]=c;
- auto drc = DNSRecordContent::mastermake(QType::NS, 1, gtld);
+ auto drc = DNSRecordContent::make(QType::NS, 1, gtld);
drc->toPacket(pw);
}
for(char c='a'; c<= 'k';++c) {
gtld[0]=c;
pw.startRecord(DNSName(gtld), QType::A, 3600, 1, DNSResourceRecord::ADDITIONAL);
- auto drc = DNSRecordContent::mastermake(QType::A, 1, "1.2.3.4");
+ auto drc = DNSRecordContent::make(QType::A, 1, "1.2.3.4");
drc->toPacket(pw);
}
pw.startRecord(DNSName("a.gtld-servers.net"), QType::AAAA, 3600, 1, DNSResourceRecord::ADDITIONAL);
- auto aaaarc = DNSRecordContent::mastermake(QType::AAAA, 1, "2001:503:a83e::2:30");
+ auto aaaarc = DNSRecordContent::make(QType::AAAA, 1, "2001:503:a83e::2:30");
aaaarc->toPacket(pw);
pw.startRecord(DNSName("b.gtld-servers.net"), QType::AAAA, 3600, 1, DNSResourceRecord::ADDITIONAL);
- aaaarc = DNSRecordContent::mastermake(QType::AAAA, 1, "2001:503:231d::2:30");
+ aaaarc = DNSRecordContent::make(QType::AAAA, 1, "2001:503:231d::2:30");
aaaarc->toPacket(pw);
// shuffle(records);
for(const auto& rec : records) {
pw.startRecord(rec.qname, rec.qtype.getCode(), rec.ttl, 1, DNSResourceRecord::ADDITIONAL);
- auto drc = DNSRecordContent::mastermake(rec.qtype.getCode(), 1, rec.content);
+ auto drc = DNSRecordContent::make(rec.qtype.getCode(), 1, rec.content);
drc->toPacket(pw);
}
void operator()() const
{
- auto drc = DNSRecordContent::mastermake(QType::A, 1,
- "1.2.3.4");
+ auto drc = DNSRecordContent::make(QType::A, 1,
+ "1.2.3.4");
}
};
DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), d_type);
for(int records = 0; records < d_records; records++) {
pw.startRecord(DNSName("outpost.ds9a.nl"), d_type);
- auto drc = DNSRecordContent::mastermake(d_type, 1,
- d_content);
+ auto drc = DNSRecordContent::make(d_type, 1,
+ d_content);
drc->toPacket(pw);
}
pw.commit();
DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::AAAA);
for(int records = 0; records < d_records; records++) {
pw.startRecord(DNSName("outpost.ds9a.nl"), QType::AAAA);
- auto drc = DNSRecordContent::mastermake(QType::AAAA, 1, "fe80::21d:92ff:fe6d:8441");
+ auto drc = DNSRecordContent::make(QType::AAAA, 1, "fe80::21d:92ff:fe6d:8441");
drc->toPacket(pw);
}
pw.commit();
for(int records = 0; records < d_records; records++) {
pw.startRecord(DNSName("outpost.ds9a.nl"), QType::SOA);
- auto drc = DNSRecordContent::mastermake(QType::SOA, 1, "a0.org.afilias-nst.info. noc.afilias-nst.info. 2008758137 1800 900 604800 86400");
+ auto drc = DNSRecordContent::make(QType::SOA, 1, "a0.org.afilias-nst.info. noc.afilias-nst.info. 2008758137 1800 900 604800 86400");
drc->toPacket(pw);
}
pw.commit();
DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::A);
pw.startRecord(DNSName("ds9a.nl"), QType::NS, 3600, 1, DNSResourceRecord::AUTHORITY);
- auto drc = DNSRecordContent::mastermake(QType::NS, 1, "ns1.ds9a.nl");
+ auto drc = DNSRecordContent::make(QType::NS, 1, "ns1.ds9a.nl");
drc->toPacket(pw);
pw.startRecord(DNSName("ds9a.nl"), QType::NS, 3600, 1, DNSResourceRecord::AUTHORITY);
- drc = DNSRecordContent::mastermake(QType::NS, 1, "ns2.ds9a.nl");
+ drc = DNSRecordContent::make(QType::NS, 1, "ns2.ds9a.nl");
drc->toPacket(pw);
pw.startRecord(DNSName("ns1.ds9a.nl"), QType::A, 3600, 1, DNSResourceRecord::ADDITIONAL);
- drc = DNSRecordContent::mastermake(QType::A, 1, "1.2.3.4");
+ drc = DNSRecordContent::make(QType::A, 1, "1.2.3.4");
drc->toPacket(pw);
pw.startRecord(DNSName("ns2.ds9a.nl"), QType::A, 3600, 1, DNSResourceRecord::ADDITIONAL);
- drc = DNSRecordContent::mastermake(QType::A, 1, "4.3.2.1");
+ drc = DNSRecordContent::make(QType::A, 1, "4.3.2.1");
drc->toPacket(pw);
pw.commit();
/* The callback prototype changed in 3.4.0. */
#if GNUTLS_VERSION_NUMBER >= 0x030400
- static int newTicketFromServerCb(gnutls_session_t session, unsigned int htype, unsigned post, unsigned int incoming, const gnutls_datum_t* msg)
+ static int newTicketFromServerCb(gnutls_session_t session, unsigned int htype, unsigned post, unsigned int /* incoming */, const gnutls_datum_t* /* msg */)
#else
- static int newTicketFromServerCb(gnutls_session_t session, unsigned int htype, unsigned post, unsigned int incoming)
+ static int newTicketFromServerCb(gnutls_session_t session, unsigned int htype, unsigned post, unsigned int /* incoming */)
#endif /* GNUTLS_VERSION_NUMBER >= 0x030400 */
{
if (htype != GNUTLS_HANDSHAKE_NEW_SESSION_TICKET || post != GNUTLS_HOOK_POST || session == nullptr) {
return 0;
}
- IOState tryConnect(bool fastOpen, const ComboAddress& remote) override
+ IOState tryConnect(bool fastOpen, [[maybe_unused]] const ComboAddress& remote) override
{
int ret = 0;
vector<BindDomainInfo> domains = BP.getDomains();
BOOST_CHECK_EQUAL(domains.size(), 11U);
-#define checkzone(i, dname, fname, ztype, nmasters) \
- { \
- BOOST_CHECK(domains[i].name == DNSName(dname)); \
- BOOST_CHECK_EQUAL(domains[i].filename, fname); \
- BOOST_CHECK_EQUAL(domains[i].type, #ztype); \
- BOOST_CHECK_EQUAL(domains[i].masters.size(), nmasters); \
+#define checkzone(i, dname, fname, ztype, nprimaries) \
+ { \
+ BOOST_CHECK(domains[i].name == DNSName(dname)); \
+ BOOST_CHECK_EQUAL(domains[i].filename, fname); \
+ BOOST_CHECK_EQUAL(domains[i].type, #ztype); \
+ BOOST_CHECK_EQUAL(domains[i].primaries.size(), nprimaries); \
}
checkzone(0, "example.com", "./zones/example.com", master, 0U);
checkzone(1, "test.com", "./zones/test.com", slave, 1U);
- BOOST_CHECK_EQUAL(domains[1].masters[0].toString(), ComboAddress("1.2.3.4", 5678).toString());
+ BOOST_CHECK_EQUAL(domains[1].primaries[0].toString(), ComboAddress("1.2.3.4", 5678).toString());
checkzone(2, "test.dyndns", "./zones/test.dyndns", garblewarble, 0U);
checkzone(3, "wtest.com", "./zones/wtest.com", primary, 0U);
checkzone(4, "nztest.com", "./zones/nztest.com", secondary, 1U);
- BOOST_CHECK_EQUAL(domains[1].masters[0].toString(), ComboAddress("1.2.3.4", 5678).toString());
+ BOOST_CHECK_EQUAL(domains[1].primaries[0].toString(), ComboAddress("1.2.3.4", 5678).toString());
checkzone(5, "dnssec-parent.com", "./zones/dnssec-parent.com", primary, 0U);
checkzone(6, "delegated.dnssec-parent.com", "./zones/delegated.dnssec-parent.com", primary, 0U);
checkzone(7, "secure-delegated.dnssec-parent.com", "./zones/secure-delegated.dnssec-parent.com", primary, 0U);
result = std::make_shared<OPTRecordContent>();
}
else {
- result = DNSRecordContent::mastermake(type, QClass::IN, content);
+ result = DNSRecordContent::make(type, QClass::IN, content);
}
return result;
#include <boost/test/unit_test.hpp>
#include <boost/assign/std/map.hpp>
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wextra"
#include <boost/accumulators/statistics/median.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
+#pragma GCC diagnostic pop
#include "arguments.hh"
#include "dns_random.hh"
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
if (found == true) {
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::AAAA, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, ids.qname, QType::AAAA, QClass::IN, response, receivedOverUDP, 0, boost::none);
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
if (found == true) {
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none);
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, !receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
BOOST_CHECK(!subnet);
// Insert with failure-TTL of 0 (-> should not enter cache).
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(0));
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(0));
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
// Insert with failure-TTL non-zero (-> should enter cache).
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(300));
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(300));
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
bool allowTruncated = true;
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
DNSQuestion dq(ids, query);
g_PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
- g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
}
}
catch(PDNSException& e) {
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, ids.qtype, ids.qclass, response, receivedOverUDP, 0, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, ids.qname, ids.qtype, ids.qclass, response, receivedOverUDP, 0, boost::none);
found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, false);
}
BOOST_CHECK(aaaa == aaaa1);
-
- auto rec1=DNSRecordContent::mastermake(QType::A, 1, "192.168.0.1");
- auto rec2=DNSRecordContent::mastermake(QType::A, 1, "192.168.222.222");
- auto rec3=DNSRecordContent::mastermake(QType::AAAA, 1, "::1");
- auto recMX=DNSRecordContent::mastermake(QType::MX, 1, "25 smtp.powerdns.com");
- auto recMX2=DNSRecordContent::mastermake(QType::MX, 1, "26 smtp.powerdns.com");
- auto recMX3=DNSRecordContent::mastermake(QType::MX, 1, "26 SMTP.powerdns.com");
+ auto rec1 = DNSRecordContent::make(QType::A, 1, "192.168.0.1");
+ auto rec2 = DNSRecordContent::make(QType::A, 1, "192.168.222.222");
+ auto rec3 = DNSRecordContent::make(QType::AAAA, 1, "::1");
+ auto recMX = DNSRecordContent::make(QType::MX, 1, "25 smtp.powerdns.com");
+ auto recMX2 = DNSRecordContent::make(QType::MX, 1, "26 smtp.powerdns.com");
+ auto recMX3 = DNSRecordContent::make(QType::MX, 1, "26 SMTP.powerdns.com");
BOOST_CHECK(!(*rec1==*rec2));
BOOST_CHECK(*rec1==*rec1);
BOOST_CHECK(*rec3==*rec3);
BOOST_TEST_MESSAGE("Checking record type " << q.toString() << " test #" << n);
try {
std::string recData;
- auto rec = DNSRecordContent::mastermake(q.getCode(), 1, inval);
- BOOST_CHECK_MESSAGE(rec != NULL, "mastermake( " << q.getCode() << ", 1, " << inval << ") should not return NULL");
+ auto rec = DNSRecordContent::make(q.getCode(), 1, inval);
+ BOOST_CHECK_MESSAGE(rec != NULL, "make( " << q.getCode() << ", 1, " << inval << ") should not return NULL");
if (rec == NULL) continue;
// now verify the record (note that this will be same as *zone* value (except for certain QTypes)
bool success=true;
BOOST_WARN_EXCEPTION(
{
- auto drc = DNSRecordContent::mastermake(q.getCode(), 1, input);
+ auto drc = DNSRecordContent::make(q.getCode(), 1, input);
pw.startRecord(DNSName("unit.test"), q.getCode());
drc->toPacket(pw);
success=false;
},
- std::exception, test_dnsrecords_cc_predicate
- );
+ std::exception, test_dnsrecords_cc_predicate);
if (success) REC_FAIL_XSUCCESS(q.toString() << " test #" << n << " has unexpectedly passed"); // a bad record was detected when it was supposed not to be detected
} else {
BOOST_CHECK_EXCEPTION(
{
- auto drc = DNSRecordContent::mastermake(q.getCode(), 1, input);
+ auto drc = DNSRecordContent::make(q.getCode(), 1, input);
pw.startRecord(DNSName("unit.test"), q.getCode());
drc->toPacket(pw);
},
- std::exception, test_dnsrecords_cc_predicate
- );
+ std::exception, test_dnsrecords_cc_predicate);
}
};
}
// special record test, because Unknown record types are the worst
BOOST_AUTO_TEST_CASE(test_unknown_records_in) {
- auto validUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 42");
+ auto validUnknown = DNSRecordContent::make(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 42");
// we need at least two parts
- BOOST_CHECK_THROW(auto notEnoughPartsUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\#"), MOADNSException);
+ BOOST_CHECK_THROW(auto notEnoughPartsUnknown = DNSRecordContent::make(static_cast<QType::typeenum>(65534), QClass::IN, "\\#"), MOADNSException);
// two parts are OK when the RDATA size is 0, not OK otherwise
- auto validEmptyUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 0");
- BOOST_CHECK_THROW(auto twoPartsNotZeroUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1"), MOADNSException);
+ auto validEmptyUnknown = DNSRecordContent::make(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 0");
+ BOOST_CHECK_THROW(auto twoPartsNotZeroUnknown = DNSRecordContent::make(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1"), MOADNSException);
// the first part has to be "\#"
- BOOST_CHECK_THROW(auto invalidFirstPartUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\$ 0"), MOADNSException);
+ BOOST_CHECK_THROW(auto invalidFirstPartUnknown = DNSRecordContent::make(static_cast<QType::typeenum>(65534), QClass::IN, "\\$ 0"), MOADNSException);
// RDATA length is not even
- BOOST_CHECK_THROW(auto unevenUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 A"), MOADNSException);
+ BOOST_CHECK_THROW(auto unevenUnknown = DNSRecordContent::make(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 A"), MOADNSException);
// RDATA length is not equal to the expected size
- BOOST_CHECK_THROW(auto wrongRDATASizeUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 2 AA"), MOADNSException);
+ BOOST_CHECK_THROW(auto wrongRDATASizeUnknown = DNSRecordContent::make(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 2 AA"), MOADNSException);
// RDATA is invalid (invalid hex value)
try {
- auto invalidRDATAUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 JJ");
+ auto invalidRDATAUnknown = DNSRecordContent::make(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 JJ");
// we should not reach that code
BOOST_CHECK(false);
// but if we do let's see what we got (likely what was left over on the stack)
// test that we reject invalid SVCB escaping
BOOST_AUTO_TEST_CASE(test_svcb_records_in) {
- BOOST_CHECK_THROW(auto invalidSVCB1=DNSRecordContent::mastermake(QType::SVCB, QClass::IN, R"FOO(1 . alpn=foo\\)FOO"), std::runtime_error);
-
+ BOOST_CHECK_THROW(auto invalidSVCB1 = DNSRecordContent::make(QType::SVCB, QClass::IN, R"FOO(1 . alpn=foo\\)FOO"), std::runtime_error);
}
// special record test, because EUI are odd
BOOST_AUTO_TEST_CASE(test_eui_records_in) {
- auto validEUI48=DNSRecordContent::mastermake(QType::EUI48, QClass::IN, "00-00-5e-00-53-2a");
+ auto validEUI48 = DNSRecordContent::make(QType::EUI48, QClass::IN, "00-00-5e-00-53-2a");
- BOOST_CHECK_THROW(auto invalidEUI48=DNSRecordContent::mastermake(QType::EUI48, QClass::IN, "00-00-5e-00-53-"), MOADNSException);
+ BOOST_CHECK_THROW(auto invalidEUI48 = DNSRecordContent::make(QType::EUI48, QClass::IN, "00-00-5e-00-53-"), MOADNSException);
- auto validEUI64=DNSRecordContent::mastermake(QType::EUI64, QClass::IN, "00-00-5e-ef-10-00-00-2a");
+ auto validEUI64 = DNSRecordContent::make(QType::EUI64, QClass::IN, "00-00-5e-ef-10-00-00-2a");
- BOOST_CHECK_THROW(auto invalidEUI64=DNSRecordContent::mastermake(QType::EUI64, QClass::IN, "00-00-5e-ef-10-00-00-"), MOADNSException);
+ BOOST_CHECK_THROW(auto invalidEUI64 = DNSRecordContent::make(QType::EUI64, QClass::IN, "00-00-5e-ef-10-00-00-"), MOADNSException);
}
// special record test, because LOC is weird
BOOST_AUTO_TEST_CASE(test_loc_records_in) {
- auto validLOC=DNSRecordContent::mastermake(QType::LOC, QClass::IN, "52 22 23.000 N 4 53 32.000 E -2.00m 0.00m 10000m 10m");
+ auto validLOC = DNSRecordContent::make(QType::LOC, QClass::IN, "52 22 23.000 N 4 53 32.000 E -2.00m 0.00m 10000m 10m");
- BOOST_CHECK_THROW(auto invalidLOC=DNSRecordContent::mastermake(QType::LOC, QClass::IN, "52 22 23.000 N"), MOADNSException);
+ BOOST_CHECK_THROW(auto invalidLOC = DNSRecordContent::make(QType::LOC, QClass::IN, "52 22 23.000 N"), MOADNSException);
vector<uint8_t> packet;
DNSPacketWriter writer(packet, DNSName("powerdns.com."), QType::LOC, QClass::IN, 0);
BOOST_AUTO_TEST_CASE(test_nsec_records_in) {
{
- auto validNSEC=DNSRecordContent::mastermake(QType::NSEC, QClass::IN, "host.example.com. A MX RRSIG NSEC TYPE1234");
+ auto validNSEC = DNSRecordContent::make(QType::NSEC, QClass::IN, "host.example.com. A MX RRSIG NSEC TYPE1234");
vector<uint8_t> packet;
DNSPacketWriter writer(packet, DNSName("powerdns.com."), QType::NSEC, QClass::IN, 0);
}
{
- auto validNSEC3=DNSRecordContent::mastermake(QType::NSEC3, QClass::IN, "1 1 12 aabbccdd 2vptu5timamqttgl4luu9kg21e0aor3s A RRSIG");
+ auto validNSEC3 = DNSRecordContent::make(QType::NSEC3, QClass::IN, "1 1 12 aabbccdd 2vptu5timamqttgl4luu9kg21e0aor3s A RRSIG");
vector<uint8_t> packet;
DNSPacketWriter writer(packet, DNSName("powerdns.com."), QType::NSEC3, QClass::IN, 0);
}
{
- auto validNSEC3PARAM=DNSRecordContent::mastermake(QType::NSEC3PARAM, QClass::IN, "1 0 12 aabbccdd");
+ auto validNSEC3PARAM = DNSRecordContent::make(QType::NSEC3PARAM, QClass::IN, "1 0 12 aabbccdd");
vector<uint8_t> packet;
DNSPacketWriter writer(packet, DNSName("powerdns.com."), QType::NSEC3PARAM, QClass::IN, 0);
BOOST_AUTO_TEST_CASE(test_nsec_records_types) {
{
- auto validNSEC = DNSRecordContent::mastermake(QType::NSEC, QClass::IN, "host.example.com. A MX RRSIG NSEC TYPE1234");
+ auto validNSEC = DNSRecordContent::make(QType::NSEC, QClass::IN, "host.example.com. A MX RRSIG NSEC TYPE1234");
auto nsecContent = std::dynamic_pointer_cast<NSECRecordContent>(validNSEC);
BOOST_REQUIRE(nsecContent);
}
BOOST_AUTO_TEST_CASE(test_nsec_invalid_bitmap_len) {
- auto validNSEC = DNSRecordContent::mastermake(QType::NSEC, QClass::IN, "host.example.com. A MX RRSIG NSEC AAAA NSEC3 TYPE1234 TYPE65535");
+ auto validNSEC = DNSRecordContent::make(QType::NSEC, QClass::IN, "host.example.com. A MX RRSIG NSEC AAAA NSEC3 TYPE1234 TYPE65535");
const DNSName powerdnsName("powerdns.com.");
vector<uint8_t> packet;
{
const std::string str = "1 1 12 aabbccdd 2vptu5timamqttgl4luu9kg21e0aor3s a mx rrsig nsec3 type1234 type65535";
- auto validNSEC3 = DNSRecordContent::mastermake(QType::NSEC3, QClass::IN, str);
+ auto validNSEC3 = DNSRecordContent::make(QType::NSEC3, QClass::IN, str);
auto nsec3Content = std::dynamic_pointer_cast<NSEC3RecordContent>(validNSEC3);
BOOST_REQUIRE(nsec3Content);
const std::string salt = "aabbccdd";
const std::string hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
const std::string str = "1 1 12 " + salt + " " + hash;
- auto validNSEC3=DNSRecordContent::mastermake(QType::NSEC3, QClass::IN, str);
+ auto validNSEC3 = DNSRecordContent::make(QType::NSEC3, QClass::IN, str);
vector<uint8_t> packet;
DNSPacketWriter writer(packet, qname, QType::NSEC3, QClass::IN, 0);
BOOST_AUTO_TEST_SUITE(test_ixfr_cc)
BOOST_AUTO_TEST_CASE(test_ixfr_rfc1995_axfr) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::NS, "NS.JAIN.AD.JP.");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
- auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA));
+ auto ret = processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA));
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(ret.at(0).first.size(), 0U);
BOOST_REQUIRE_EQUAL(ret.at(0).second.size(), records.size());
}
BOOST_AUTO_TEST_CASE(test_ixfr_rfc1995_incremental) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
- auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA));
+ auto ret = processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA));
// two sequences
BOOST_CHECK_EQUAL(ret.size(), 2U);
// the first one has one removal, two additions (plus the corresponding SOA removal/addition)
}
BOOST_AUTO_TEST_CASE(test_ixfr_rfc1995_condensed_incremental) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
- auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA));
+ auto ret = processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA));
// one sequence
BOOST_CHECK_EQUAL(ret.size(), 1U);
// it has one removal, two additions (plus the corresponding SOA removal/addition)
}
BOOST_AUTO_TEST_CASE(test_ixfr_no_additions_in_first_sequence) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
- auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA));
+ auto ret = processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA));
// two sequences
BOOST_CHECK_EQUAL(ret.size(), 2U);
// the first one has one removal, no additions (plus the corresponding SOA removal/addition)
}
BOOST_AUTO_TEST_CASE(test_ixfr_no_removals_in_first_sequence) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
- auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA));
+ auto ret = processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA));
// two sequences
BOOST_CHECK_EQUAL(ret.size(), 2U);
// the first one has no removal, two additions (plus the corresponding SOA removal/addition)
}
BOOST_AUTO_TEST_CASE(test_ixfr_same_serial) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
- auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA));
+ auto ret = processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA));
// this is actually an empty AXFR
BOOST_CHECK_EQUAL(ret.size(), 1U);
}
BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_records) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
- auto ret = processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA));
+ auto ret = processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA));
BOOST_CHECK_EQUAL(ret.size(), 0U);
}
-BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_master_soa) {
- const ComboAddress master("[2001:DB8::1]:53");
+BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_primary_soa)
+{
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
;
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
- auto ret = processIXFRRecords(master, zone, records, nullptr);
+ auto ret = processIXFRRecords(primary, zone, records, nullptr);
BOOST_CHECK_EQUAL(ret.size(), 0U);
}
BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_trailing_soa) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2");
- BOOST_CHECK_THROW(processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA)), std::runtime_error);
+ BOOST_CHECK_THROW(processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA)), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(test_ixfr_invalid_no_soa_after_removals) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800");
addRecordToList(records, DNSName("NEZU.JAIN.AD.JP."), QType::A, "133.69.136.5");
- BOOST_CHECK_THROW(processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA)), std::runtime_error);
+ BOOST_CHECK_THROW(processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA)), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(test_ixfr_mismatching_serial_before_and_after_additions) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "192.41.197.2");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
- BOOST_CHECK_THROW(processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA)), std::runtime_error);
+ BOOST_CHECK_THROW(processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA)), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(test_ixfr_trailing_record_after_end) {
- const ComboAddress master("[2001:DB8::1]:53");
+ const ComboAddress primary("[2001:DB8::1]:53");
const DNSName zone("JAIN.AD.JP.");
- auto masterSOA = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
+ auto primarySOA = DNSRecordContent::make(QType::SOA, QClass::IN, "NS.JAIN.AD.JP. mohta.jain.ad.jp. 3 600 600 3600000 604800");
vector<DNSRecord> records;
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 1 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN.AD.JP."), QType::SOA, "ns.jain.ad.jp. mohta.jain.ad.jp. 3 600 600 3600000 604800");
addRecordToList(records, DNSName("JAIN-BB.JAIN.AD.JP."), QType::A, "133.69.136.3");
- BOOST_CHECK_THROW(processIXFRRecords(master, zone, records, std::dynamic_pointer_cast<SOARecordContent>(masterSOA)), std::runtime_error);
+ BOOST_CHECK_THROW(processIXFRRecords(primary, zone, records, std::dynamic_pointer_cast<SOARecordContent>(primarySOA)), std::runtime_error);
}
BOOST_AUTO_TEST_SUITE_END();
rrc.d_signer = DNSName("example.net.");
inception = 946684800;
expire = 1893456000;
- rrs.insert(DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.1"));
+ rrs.insert(DNSRecordContent::make(QType::A, QClass::IN, "192.0.2.1"));
}
else {
rrc.d_signer = qname;
- rrs.insert(DNSRecordContent::mastermake(QType::MX, QClass::IN, "10 mail.example.com."));
+ rrs.insert(DNSRecordContent::make(QType::MX, QClass::IN, "10 mail.example.com."));
}
rrc.d_originalttl = 3600;
auto testFunction = [](UeberBackend& ub) -> void {
{
- auto sbba = dynamic_cast<SimpleBackendBestAuth*>(ub.backends.at(0));
+ auto* sbba = dynamic_cast<SimpleBackendBestAuth*>(ub.backends.at(0).get());
BOOST_REQUIRE(sbba != nullptr);
+
+ // NOLINTNEXTLINE (clang-analyzer-core.NullDereference): Not sure.
sbba->d_authLookupCount = 0;
// test getAuth()
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <memory>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "auth-zonecache.hh"
#include "utility.hh"
-
-#include <dlfcn.h>
-#include <string>
-#include <map>
-#include <sys/types.h>
-#include <sstream>
#include <cerrno>
+#include <dlfcn.h>
+#include <functional>
#include <iostream>
+#include <map>
#include <sstream>
-#include <functional>
+#include <string>
+#include <sys/types.h>
#include "dns.hh"
#include "arguments.hh"
extern StatBag S;
-LockGuarded<vector<UeberBackend *>> UeberBackend::d_instances;
+LockGuarded<vector<UeberBackend*>> UeberBackend::d_instances;
// initially we are blocked
-bool UeberBackend::d_go=false;
-bool UeberBackend::s_doANYLookupsOnly=false;
+bool UeberBackend::d_go = false;
+bool UeberBackend::s_doANYLookupsOnly = false;
std::mutex UeberBackend::d_mut;
std::condition_variable UeberBackend::d_cond;
AtomicCounter* UeberBackend::s_backendQueries = nullptr;
//! Loads a module and reports it to all UeberBackend threads
-bool UeberBackend::loadmodule(const string &name)
+bool UeberBackend::loadmodule(const string& name)
{
- g_log<<Logger::Warning <<"Loading '"<<name<<"'" << endl;
+ g_log << Logger::Warning << "Loading '" << name << "'" << endl;
- void *dlib=dlopen(name.c_str(), RTLD_NOW);
+ void* dlib = dlopen(name.c_str(), RTLD_NOW);
- if(dlib == nullptr) {
- g_log<<Logger::Error <<"Unable to load module '"<<name<<"': "<<dlerror() << endl;
+ if (dlib == nullptr) {
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): There's no thread-safe alternative to dlerror().
+ g_log << Logger::Error << "Unable to load module '" << name << "': " << dlerror() << endl;
return false;
}
bool UeberBackend::loadModules(const vector<string>& modules, const string& path)
{
- for (const auto& module: modules) {
- bool res;
- if (module.find('.')==string::npos) {
- res = UeberBackend::loadmodule(path+"/lib"+module+"backend.so");
- } else if (module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) {
+ for (const auto& module : modules) {
+ bool res = false;
+
+ if (module.find('.') == string::npos) {
+ auto fullPath = path;
+ fullPath += "/lib";
+ fullPath += module;
+ fullPath += "backend.so";
+ res = UeberBackend::loadmodule(fullPath);
+ }
+ else if (module[0] == '/' || (module[0] == '.' && module[1] == '/') || (module[0] == '.' && module[1] == '.')) {
// absolute or current path
res = UeberBackend::loadmodule(module);
- } else {
- res = UeberBackend::loadmodule(path+"/"+module);
+ }
+ else {
+ auto fullPath = path;
+ fullPath += "/";
+ fullPath += module;
+ res = UeberBackend::loadmodule(fullPath);
}
- if (res == false) {
+ if (!res) {
return false;
}
}
d_cond.notify_all();
}
-bool UeberBackend::getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial)
+bool UeberBackend::getDomainInfo(const DNSName& domain, DomainInfo& domainInfo, bool getSerial)
{
- for(auto backend : backends)
- if(backend->getDomainInfo(domain, di, getSerial))
+ for (auto& backend : backends) {
+ if (backend->getDomainInfo(domain, domainInfo, getSerial)) {
return true;
+ }
+ }
return false;
}
-bool UeberBackend::createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account)
+bool UeberBackend::createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& primaries, const string& account)
{
- for(DNSBackend* mydb : backends) {
- if (mydb->createDomain(domain, kind, masters, account)) {
+ for (auto& backend : backends) {
+ if (backend->createDomain(domain, kind, primaries, account)) {
return true;
}
}
bool UeberBackend::doesDNSSEC()
{
- for(auto* db : backends) {
- if(db->doesDNSSEC())
+ for (auto& backend : backends) {
+ if (backend->doesDNSSEC()) {
return true;
+ }
}
return false;
}
-bool UeberBackend::addDomainKey(const DNSName& name, const DNSBackend::KeyData& key, int64_t& id)
+bool UeberBackend::addDomainKey(const DNSName& name, const DNSBackend::KeyData& key, int64_t& keyID)
{
- id = -1;
- for(DNSBackend* db : backends) {
- if(db->addDomainKey(name, key, id))
+ keyID = -1;
+ for (auto& backend : backends) {
+ if (backend->addDomainKey(name, key, keyID)) {
return true;
+ }
}
return false;
}
bool UeberBackend::getDomainKeys(const DNSName& name, std::vector<DNSBackend::KeyData>& keys)
{
- for(DNSBackend* db : backends) {
- if(db->getDomainKeys(name, keys))
+ for (auto& backend : backends) {
+ if (backend->getDomainKeys(name, keys)) {
return true;
+ }
}
return false;
}
-bool UeberBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
+bool UeberBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta)
{
- for(DNSBackend* db : backends) {
- if(db->getAllDomainMetadata(name, meta))
+ for (auto& backend : backends) {
+ if (backend->getAllDomainMetadata(name, meta)) {
return true;
+ }
}
return false;
}
bool UeberBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
{
- for(DNSBackend* db : backends) {
- if(db->getDomainMetadata(name, kind, meta))
+ for (auto& backend : backends) {
+ if (backend->getDomainMetadata(name, kind, meta)) {
return true;
+ }
}
return false;
}
bool UeberBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::string& meta)
{
- bool ret;
meta.clear();
std::vector<string> tmp;
- if ((ret = getDomainMetadata(name, kind, tmp)) && !tmp.empty()) {
+ const bool ret = getDomainMetadata(name, kind, tmp);
+ if (ret && !tmp.empty()) {
meta = *tmp.begin();
}
return ret;
bool UeberBackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
{
- for(DNSBackend* db : backends) {
- if(db->setDomainMetadata(name, kind, meta))
+ for (auto& backend : backends) {
+ if (backend->setDomainMetadata(name, kind, meta)) {
return true;
+ }
}
return false;
}
return setDomainMetadata(name, kind, tmp);
}
-bool UeberBackend::activateDomainKey(const DNSName& name, unsigned int id)
+bool UeberBackend::activateDomainKey(const DNSName& name, unsigned int keyID)
{
- for(DNSBackend* db : backends) {
- if(db->activateDomainKey(name, id))
+ for (auto& backend : backends) {
+ if (backend->activateDomainKey(name, keyID)) {
return true;
+ }
}
return false;
}
-bool UeberBackend::deactivateDomainKey(const DNSName& name, unsigned int id)
+bool UeberBackend::deactivateDomainKey(const DNSName& name, unsigned int keyID)
{
- for(DNSBackend* db : backends) {
- if(db->deactivateDomainKey(name, id))
+ for (auto& backend : backends) {
+ if (backend->deactivateDomainKey(name, keyID)) {
return true;
+ }
}
return false;
}
-bool UeberBackend::publishDomainKey(const DNSName& name, unsigned int id)
+bool UeberBackend::publishDomainKey(const DNSName& name, unsigned int keyID)
{
- for(DNSBackend* db : backends) {
- if(db->publishDomainKey(name, id))
+ for (auto& backend : backends) {
+ if (backend->publishDomainKey(name, keyID)) {
return true;
+ }
}
return false;
}
-bool UeberBackend::unpublishDomainKey(const DNSName& name, unsigned int id)
+bool UeberBackend::unpublishDomainKey(const DNSName& name, unsigned int keyID)
{
- for(DNSBackend* db : backends) {
- if(db->unpublishDomainKey(name, id))
+ for (auto& backend : backends) {
+ if (backend->unpublishDomainKey(name, keyID)) {
return true;
+ }
}
return false;
}
-
-bool UeberBackend::removeDomainKey(const DNSName& name, unsigned int id)
+bool UeberBackend::removeDomainKey(const DNSName& name, unsigned int keyID)
{
- for(DNSBackend* db : backends) {
- if(db->removeDomainKey(name, id))
+ for (auto& backend : backends) {
+ if (backend->removeDomainKey(name, keyID)) {
return true;
+ }
}
return false;
}
-
-
void UeberBackend::reload()
{
- for (auto & backend : backends)
- {
+ for (auto& backend : backends) {
backend->reload();
}
}
-void UeberBackend::updateZoneCache() {
+void UeberBackend::updateZoneCache()
+{
if (!g_zoneCache.isEnabled()) {
return;
}
vector<std::tuple<DNSName, int>> zone_indices;
g_zoneCache.setReplacePending();
- for (vector<DNSBackend*>::iterator i = backends.begin(); i != backends.end(); ++i )
- {
+ for (auto& backend : backends) {
vector<DomainInfo> zones;
- (*i)->getAllDomains(&zones, false, true);
- for(auto& di: zones) {
- zone_indices.emplace_back(std::move(di.zone), (int)di.id); // this cast should not be necessary
+ backend->getAllDomains(&zones, false, true);
+ for (auto& domainInfo : zones) {
+ zone_indices.emplace_back(std::move(domainInfo.zone), (int)domainInfo.id); // this cast should not be necessary
}
}
g_zoneCache.replace(zone_indices);
}
-void UeberBackend::rediscover(string *status)
+void UeberBackend::rediscover(string* status)
{
- for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
- {
+ for (auto backend = backends.begin(); backend != backends.end(); ++backend) {
string tmpstr;
- ( *i )->rediscover(&tmpstr);
- if(status)
- *status+=tmpstr + (i!=backends.begin() ? "\n" : "");
+ (*backend)->rediscover(&tmpstr);
+ if (status != nullptr) {
+ *status += tmpstr + (backend != backends.begin() ? "\n" : "");
+ }
}
updateZoneCache();
}
-
-void UeberBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains)
+void UeberBackend::getUnfreshSecondaryInfos(vector<DomainInfo>* domains)
{
- for (auto & backend : backends)
- {
- backend->getUnfreshSlaveInfos( domains );
- }
+ for (auto& backend : backends) {
+ backend->getUnfreshSecondaryInfos(domains);
+ }
}
-void UeberBackend::getUpdatedMasters(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
+void UeberBackend::getUpdatedPrimaries(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
{
- for (auto & backend : backends)
- {
- backend->getUpdatedMasters(domains, catalogs, catalogHashes);
+ for (auto& backend : backends) {
+ backend->getUpdatedPrimaries(domains, catalogs, catalogHashes);
}
}
bool UeberBackend::inTransaction()
{
- for (auto* b : backends )
- {
- if(b->inTransaction())
+ for (auto& backend : backends) {
+ if (backend->inTransaction()) {
return true;
+ }
}
return false;
}
-bool UeberBackend::getAuth(const DNSName &target, const QType& qtype, SOAData* sd, bool cachedOk)
+bool UeberBackend::fillSOAFromZoneRecord(DNSName& shorter, const int zoneId, SOAData* const soaData)
+{
+ // Zone exists in zone cache, directly look up SOA.
+ lookup(QType(QType::SOA), shorter, zoneId, nullptr);
+
+ DNSZoneRecord zoneRecord;
+ if (!get(zoneRecord)) {
+ DLOG(g_log << Logger::Info << "Backend returned no SOA for zone '" << shorter.toLogString() << "', which it reported as existing " << endl);
+ return false;
+ }
+
+ if (zoneRecord.dr.d_name != shorter) {
+ throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '" + zoneRecord.dr.d_name.toLogString() + "' is not equal to looked up zone '" + shorter.toLogString() + "'");
+ }
+
+ // Fill soaData.
+ soaData->qname = zoneRecord.dr.d_name;
+
+ try {
+ fillSOAData(zoneRecord, *soaData);
+ }
+ catch (...) {
+ g_log << Logger::Warning << "Backend returned a broken SOA for zone '" << shorter.toLogString() << "'" << endl;
+
+ while (get(zoneRecord)) {
+ ;
+ }
+
+ return false;
+ }
+
+ soaData->db = backends.size() == 1 ? backends.begin()->get() : nullptr;
+
+ // Leave database handle in a consistent state.
+ while (get(zoneRecord)) {
+ ;
+ }
+
+ return true;
+}
+
+UeberBackend::CacheResult UeberBackend::fillSOAFromCache(SOAData* soaData, DNSName& shorter)
+{
+ auto cacheResult = cacheHas(d_question, d_answers);
+
+ if (cacheResult == CacheResult::Hit && !d_answers.empty() && d_cache_ttl != 0U) {
+ DLOG(g_log << Logger::Error << "has pos cache entry: " << shorter << endl);
+ fillSOAData(d_answers[0], *soaData);
+
+ soaData->db = backends.size() == 1 ? backends.begin()->get() : nullptr;
+ soaData->qname = shorter;
+ }
+ else if (cacheResult == CacheResult::NegativeMatch && d_negcache_ttl != 0U) {
+ DLOG(g_log << Logger::Error << "has neg cache entry: " << shorter << endl);
+ }
+
+ return cacheResult;
+}
+
+static std::vector<std::unique_ptr<DNSBackend>>::iterator findBestMatchingBackend(std::vector<std::unique_ptr<DNSBackend>>& backends, std::vector<std::pair<std::size_t, SOAData>>& bestMatches, const DNSName& shorter, SOAData* soaData)
+{
+ auto backend = backends.begin();
+ for (auto bestMatch = bestMatches.begin(); backend != backends.end() && bestMatch != bestMatches.end(); ++backend, ++bestMatch) {
+
+ DLOG(g_log << Logger::Error << "backend: " << backend - backends.begin() << ", qname: " << shorter << endl);
+
+ if (bestMatch->first < shorter.wirelength()) {
+ DLOG(g_log << Logger::Error << "skipped, we already found a shorter best match in this backend: " << bestMatch->second.qname << endl);
+ continue;
+ }
+
+ if (bestMatch->first == shorter.wirelength()) {
+ DLOG(g_log << Logger::Error << "use shorter best match: " << bestMatch->second.qname << endl);
+ *soaData = bestMatch->second;
+ break;
+ }
+
+ DLOG(g_log << Logger::Error << "lookup: " << shorter << endl);
+
+ if ((*backend)->getAuth(shorter, soaData)) {
+ DLOG(g_log << Logger::Error << "got: " << soaData->qname << endl);
+
+ if (!soaData->qname.empty() && !shorter.isPartOf(soaData->qname)) {
+ throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '" + soaData->qname.toLogString() + "' is not part of '" + shorter.toLogString() + "'");
+ }
+
+ bestMatch->first = soaData->qname.wirelength();
+ bestMatch->second = *soaData;
+
+ if (soaData->qname == shorter) {
+ break;
+ }
+ }
+ else {
+ DLOG(g_log << Logger::Error << "no match for: " << shorter << endl);
+ }
+ }
+
+ return backend;
+}
+
+static bool foundTarget(const DNSName& target, const DNSName& shorter, const QType& qtype, [[maybe_unused]] SOAData* soaData, const bool found)
+{
+ if (found == (qtype == QType::DS) || target != shorter) {
+ DLOG(g_log << Logger::Error << "found: " << soaData->qname << endl);
+ return true;
+ }
+
+ DLOG(g_log << Logger::Error << "chasing next: " << soaData->qname << endl);
+ return false;
+}
+
+bool UeberBackend::getAuth(const DNSName& target, const QType& qtype, SOAData* soaData, bool cachedOk)
{
// A backend can respond to our authority request with the 'best' match it
// has. For example, when asked for a.b.c.example.com. it might respond with
// of them has a more specific zone but don't bother asking this specific
// backend again for b.c.example.com., c.example.com. and example.com.
// If a backend has no match it may respond with an empty qname.
+
bool found = false;
- int cstat;
DNSName shorter(target);
- vector<pair<size_t, SOAData> > bestmatch (backends.size(), pair(target.wirelength()+1, SOAData()));
- do {
+ vector<pair<size_t, SOAData>> bestMatches(backends.size(), pair(target.wirelength() + 1, SOAData()));
+
+ bool first = true;
+ while (first || shorter.chopOff()) {
+ first = false;
+
int zoneId{-1};
- if(cachedOk && g_zoneCache.isEnabled()) {
+
+ if (cachedOk && g_zoneCache.isEnabled()) {
if (g_zoneCache.getEntry(shorter, zoneId)) {
- // Zone exists in zone cache, directly look up SOA.
- DNSZoneRecord zr;
- lookup(QType(QType::SOA), shorter, zoneId, nullptr);
- if (!get(zr)) {
- DLOG(g_log << Logger::Info << "Backend returned no SOA for zone '" << shorter.toLogString() << "', which it reported as existing " << endl);
- continue;
- }
- if (zr.dr.d_name != shorter) {
- throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '"+zr.dr.d_name.toLogString()+"' is not equal to looked up zone '"+shorter.toLogString()+"'");
- }
- // fill sd
- sd->qname = zr.dr.d_name;
- try {
- fillSOAData(zr, *sd);
- }
- catch (...) {
- g_log << Logger::Warning << "Backend returned a broken SOA for zone '" << shorter.toLogString() << "'" << endl;
- while (get(zr))
- ;
- continue;
- }
- if (backends.size() == 1) {
- sd->db = *backends.begin();
- }
- else {
- sd->db = nullptr;
+ if (fillSOAFromZoneRecord(shorter, zoneId, soaData)) {
+ if (foundTarget(target, shorter, qtype, soaData, found)) {
+ return true;
+ }
+
+ found = true;
}
- // leave database handle in a consistent state
- while (get(zr))
- ;
- goto found;
+
+ continue;
}
- // zone does not exist, try again with shorter name
+
+ // Zone does not exist, try again with a shorter name.
continue;
}
d_question.qname = shorter;
d_question.zoneId = zoneId;
- // Check cache
- if(cachedOk && (d_cache_ttl || d_negcache_ttl)) {
- cstat = cacheHas(d_question,d_answers);
+ // Check cache.
+ if (cachedOk && (d_cache_ttl != 0 || d_negcache_ttl != 0)) {
+ auto cacheResult = fillSOAFromCache(soaData, shorter);
+ if (cacheResult == CacheResult::Hit) {
+ if (foundTarget(target, shorter, qtype, soaData, found)) {
+ return true;
+ }
- if(cstat == 1 && !d_answers.empty() && d_cache_ttl) {
- DLOG(g_log<<Logger::Error<<"has pos cache entry: "<<shorter<<endl);
- fillSOAData(d_answers[0], *sd);
+ found = true;
+ continue;
+ }
- if (backends.size() == 1) {
- sd->db = *backends.begin();
- } else {
- sd->db = nullptr;
- }
- sd->qname = shorter;
- goto found;
- } else if(cstat == 0 && d_negcache_ttl) {
- DLOG(g_log<<Logger::Error<<"has neg cache entry: "<<shorter<<endl);
+ if (cacheResult == CacheResult::NegativeMatch) {
continue;
}
}
- // Check backends
+ // Check backends.
{
- vector<DNSBackend *>::const_iterator i = backends.begin();
- vector<pair<size_t, SOAData> >::iterator j = bestmatch.begin();
- for(; i != backends.end() && j != bestmatch.end(); ++i, ++j) {
-
- DLOG(g_log<<Logger::Error<<"backend: "<<i-backends.begin()<<", qname: "<<shorter<<endl);
-
- if(j->first < shorter.wirelength()) {
- DLOG(g_log<<Logger::Error<<"skipped, we already found a shorter best match in this backend: "<<j->second.qname<<endl);
- continue;
- } else if(j->first == shorter.wirelength()) {
- DLOG(g_log<<Logger::Error<<"use shorter best match: "<<j->second.qname<<endl);
- *sd = j->second;
- break;
- } else {
- DLOG(g_log<<Logger::Error<<"lookup: "<<shorter<<endl);
- if((*i)->getAuth(shorter, sd)) {
- DLOG(g_log<<Logger::Error<<"got: "<<sd->qname<<endl);
- if(!sd->qname.empty() && !shorter.isPartOf(sd->qname)) {
- throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '"+sd->qname.toLogString()+"' is not part of '"+shorter.toLogString()+"'");
- }
- j->first = sd->qname.wirelength();
- j->second = *sd;
- if(sd->qname == shorter) {
- break;
- }
- } else {
- DLOG(g_log<<Logger::Error<<"no match for: "<<shorter<<endl);
- }
- }
- }
+ auto backend = findBestMatchingBackend(backends, bestMatches, shorter, soaData);
// Add to cache
- if(i == backends.end()) {
- if(d_negcache_ttl) {
- DLOG(g_log<<Logger::Error<<"add neg cache entry:"<<shorter<<endl);
- d_question.qname=shorter;
+ if (backend == backends.end()) {
+ if (d_negcache_ttl != 0U) {
+ DLOG(g_log << Logger::Error << "add neg cache entry:" << shorter << endl);
+ d_question.qname = shorter;
addNegCache(d_question);
}
+
continue;
- } else if(d_cache_ttl) {
- DLOG(g_log<<Logger::Error<<"add pos cache entry: "<<sd->qname<<endl);
+ }
+
+ if (d_cache_ttl != 0) {
+ DLOG(g_log << Logger::Error << "add pos cache entry: " << soaData->qname << endl);
+
d_question.qtype = QType::SOA;
- d_question.qname = sd->qname;
+ d_question.qname = soaData->qname;
d_question.zoneId = zoneId;
- DNSZoneRecord rr;
- rr.dr.d_name = sd->qname;
- rr.dr.d_type = QType::SOA;
- rr.dr.setContent(makeSOAContent(*sd));
- rr.dr.d_ttl = sd->ttl;
- rr.domain_id = sd->domain_id;
+ DNSZoneRecord resourceRecord;
+ resourceRecord.dr.d_name = soaData->qname;
+ resourceRecord.dr.d_type = QType::SOA;
+ resourceRecord.dr.setContent(makeSOAContent(*soaData));
+ resourceRecord.dr.d_ttl = soaData->ttl;
+ resourceRecord.domain_id = soaData->domain_id;
- addCache(d_question, {rr});
+ addCache(d_question, {resourceRecord});
}
}
-found:
- if(found == (qtype == QType::DS) || target != shorter) {
- DLOG(g_log<<Logger::Error<<"found: "<<sd->qname<<endl);
+ if (foundTarget(target, shorter, qtype, soaData, found)) {
return true;
- } else {
- DLOG(g_log<<Logger::Error<<"chasing next: "<<sd->qname<<endl);
- found = true;
}
- } while(shorter.chopOff());
+ found = true;
+ }
+
return found;
}
-bool UeberBackend::getSOAUncached(const DNSName &domain, SOAData &sd)
+bool UeberBackend::getSOAUncached(const DNSName& domain, SOAData& soaData)
{
- d_question.qtype=QType::SOA;
- d_question.qname=domain;
- d_question.zoneId=-1;
+ d_question.qtype = QType::SOA;
+ d_question.qname = domain;
+ d_question.zoneId = -1;
- for(auto backend : backends)
- if(backend->getSOA(domain, sd)) {
- if(domain != sd.qname) {
- throw PDNSException("getSOA() returned an SOA for the wrong zone. Question: '"+domain.toLogString()+"', answer: '"+sd.qname.toLogString()+"'");
+ for (auto& backend : backends) {
+ if (backend->getSOA(domain, soaData)) {
+ if (domain != soaData.qname) {
+ throw PDNSException("getSOA() returned an SOA for the wrong zone. Question: '" + domain.toLogString() + "', answer: '" + soaData.qname.toLogString() + "'");
}
- if(d_cache_ttl) {
- DNSZoneRecord rr;
- rr.dr.d_name = sd.qname;
- rr.dr.d_type = QType::SOA;
- rr.dr.setContent(makeSOAContent(sd));
- rr.dr.d_ttl = sd.ttl;
- rr.domain_id = sd.domain_id;
-
- addCache(d_question, {rr});
-
+ if (d_cache_ttl != 0U) {
+ DNSZoneRecord zoneRecord;
+ zoneRecord.dr.d_name = soaData.qname;
+ zoneRecord.dr.d_type = QType::SOA;
+ zoneRecord.dr.setContent(makeSOAContent(soaData));
+ zoneRecord.dr.d_ttl = soaData.ttl;
+ zoneRecord.domain_id = soaData.domain_id;
+
+ addCache(d_question, {zoneRecord});
}
return true;
}
+ }
- if(d_negcache_ttl)
+ if (d_negcache_ttl != 0U) {
addNegCache(d_question);
+ }
return false;
}
-bool UeberBackend::superMasterAdd(const AutoPrimary &primary)
+bool UeberBackend::autoPrimaryAdd(const AutoPrimary& primary)
{
- for(auto backend : backends)
- if(backend->superMasterAdd(primary))
+ for (auto& backend : backends) {
+ if (backend->autoPrimaryAdd(primary)) {
return true;
+ }
+ }
return false;
}
-bool UeberBackend::autoPrimaryRemove(const AutoPrimary &primary)
+bool UeberBackend::autoPrimaryRemove(const AutoPrimary& primary)
{
- for(auto backend : backends)
- if(backend->autoPrimaryRemove(primary))
+ for (auto& backend : backends) {
+ if (backend->autoPrimaryRemove(primary)) {
return true;
+ }
+ }
return false;
}
bool UeberBackend::autoPrimariesList(std::vector<AutoPrimary>& primaries)
{
- for(auto backend : backends)
- if(backend->autoPrimariesList(primaries))
- return true;
- return false;
+ for (auto& backend : backends) {
+ if (backend->autoPrimariesList(primaries)) {
+ return true;
+ }
+ }
+ return false;
}
-bool UeberBackend::superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db)
+bool UeberBackend::autoPrimaryBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** dnsBackend)
{
- for(auto backend : backends)
- if(backend->superMasterBackend(ip, domain, nsset, nameserver, account, db))
+ for (auto& backend : backends) {
+ if (backend->autoPrimaryBackend(ip, domain, nsset, nameserver, account, dnsBackend)) {
return true;
+ }
+ }
return false;
}
-UeberBackend::UeberBackend(const string &pname)
+UeberBackend::UeberBackend(const string& pname)
{
{
d_instances.lock()->push_back(this); // report to the static list of ourself
}
- d_negcached=false;
- d_cached=false;
d_cache_ttl = ::arg().asNum("query-cache-ttl");
d_negcache_ttl = ::arg().asNum("negquery-cache-ttl");
- d_qtype = 0;
- d_stale = false;
-
- backends=BackendMakers().all(pname=="key-only");
-}
-static void del(DNSBackend* d)
-{
- delete d;
-}
-
-void UeberBackend::cleanup()
-{
- {
- auto instances = d_instances.lock();
- remove(instances->begin(), instances->end(), this);
- instances->resize(instances->size()-1);
- }
-
- for_each(backends.begin(),backends.end(),del);
+ backends = BackendMakers().all(pname == "key-only");
}
// returns -1 for miss, 0 for negative match, 1 for hit
-int UeberBackend::cacheHas(const Question &q, vector<DNSZoneRecord> &rrs)
+enum UeberBackend::CacheResult UeberBackend::cacheHas(const Question& question, vector<DNSZoneRecord>& resourceRecords) const
{
extern AuthQueryCache QC;
- if(!d_cache_ttl && ! d_negcache_ttl) {
- return -1;
+ if (d_cache_ttl == 0 && d_negcache_ttl == 0) {
+ return CacheResult::Miss;
}
- rrs.clear();
+ resourceRecords.clear();
// g_log<<Logger::Warning<<"looking up: '"<<q.qname+"'|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
- bool ret=QC.getEntry(q.qname, q.qtype, rrs, q.zoneId); // think about lowercasing here
- if(!ret) {
- return -1;
+ bool ret = QC.getEntry(question.qname, question.qtype, resourceRecords, question.zoneId); // think about lowercasing here
+ if (!ret) {
+ return CacheResult::Miss;
}
- if(rrs.empty()) // negatively cached
- return 0;
-
- return 1;
+ if (resourceRecords.empty()) { // negatively cached
+ return CacheResult::NegativeMatch;
+ }
+
+ return CacheResult::Hit;
}
-void UeberBackend::addNegCache(const Question &q)
+void UeberBackend::addNegCache(const Question& question) const
{
extern AuthQueryCache QC;
- if(!d_negcache_ttl)
+ if (d_negcache_ttl == 0) {
return;
+ }
// we should also not be storing negative answers if a pipebackend does scopeMask, but we can't pass a negative scopeMask in an empty set!
- QC.insert(q.qname, q.qtype, vector<DNSZoneRecord>(), d_negcache_ttl, q.zoneId);
+ QC.insert(question.qname, question.qtype, vector<DNSZoneRecord>(), d_negcache_ttl, question.zoneId);
}
-void UeberBackend::addCache(const Question &q, vector<DNSZoneRecord> &&rrs)
+void UeberBackend::addCache(const Question& question, vector<DNSZoneRecord>&& rrs) const
{
extern AuthQueryCache QC;
- if(!d_cache_ttl)
+ if (d_cache_ttl == 0) {
return;
+ }
- for(const auto& rr : rrs) {
- if (rr.scopeMask)
- return;
+ for (const auto& resourceRecord : rrs) {
+ if (resourceRecord.scopeMask != 0) {
+ return;
+ }
}
- QC.insert(q.qname, q.qtype, std::move(rrs), d_cache_ttl, q.zoneId);
+ QC.insert(question.qname, question.qtype, std::move(rrs), d_cache_ttl, question.zoneId);
}
-void UeberBackend::alsoNotifies(const DNSName &domain, set<string> *ips)
+void UeberBackend::alsoNotifies(const DNSName& domain, set<string>* ips)
{
- for (auto & backend : backends)
- backend->alsoNotifies(domain,ips);
+ for (auto& backend : backends) {
+ backend->alsoNotifies(domain, ips);
+ }
}
UeberBackend::~UeberBackend()
{
- DLOG(g_log<<Logger::Error<<"UeberBackend destructor called, removing ourselves from instances, and deleting our backends"<<endl);
- cleanup();
+ DLOG(g_log << Logger::Error << "UeberBackend destructor called, removing ourselves from instances, and deleting our backends" << endl);
+
+ {
+ auto instances = d_instances.lock();
+ [[maybe_unused]] auto end = remove(instances->begin(), instances->end(), this);
+ instances->resize(instances->size() - 1);
+ }
+
+ backends.clear();
}
// this handle is more magic than most
-void UeberBackend::lookup(const QType &qtype,const DNSName &qname, int zoneId, DNSPacket *pkt_p)
+void UeberBackend::lookup(const QType& qtype, const DNSName& qname, int zoneId, DNSPacket* pkt_p)
{
- if(d_stale) {
- g_log<<Logger::Error<<"Stale ueberbackend received question, signalling that we want to be recycled"<<endl;
+ if (d_stale) {
+ g_log << Logger::Error << "Stale ueberbackend received question, signalling that we want to be recycled" << endl;
throw PDNSException("We are stale, please recycle");
}
- DLOG(g_log<<"UeberBackend received question for "<<qtype<<" of "<<qname<<endl);
+ DLOG(g_log << "UeberBackend received question for " << qtype << " of " << qname << endl);
if (!d_go) {
- g_log<<Logger::Error<<"UeberBackend is blocked, waiting for 'go'"<<endl;
+ g_log << Logger::Error << "UeberBackend is blocked, waiting for 'go'" << endl;
std::unique_lock<std::mutex> l(d_mut);
- d_cond.wait(l, []{ return d_go == true; });
- g_log<<Logger::Error<<"Broadcast received, unblocked"<<endl;
+ d_cond.wait(l, [] { return d_go; });
+ g_log << Logger::Error << "Broadcast received, unblocked" << endl;
}
- d_qtype=qtype.getCode();
+ d_qtype = qtype.getCode();
- d_handle.i=0;
- d_handle.qtype=s_doANYLookupsOnly ? QType::ANY : qtype;
- d_handle.qname=qname;
- d_handle.zoneId=zoneId;
- d_handle.pkt_p=pkt_p;
+ d_handle.i = 0;
+ d_handle.qtype = s_doANYLookupsOnly ? QType::ANY : qtype;
+ d_handle.qname = qname;
+ d_handle.zoneId = zoneId;
+ d_handle.pkt_p = pkt_p;
- if(!backends.size()) {
- g_log<<Logger::Error<<"No database backends available - unable to answer questions."<<endl;
- d_stale=true; // please recycle us!
+ if (backends.empty()) {
+ g_log << Logger::Error << "No database backends available - unable to answer questions." << endl;
+ d_stale = true; // please recycle us!
throw PDNSException("We are stale, please recycle");
}
+
+ d_question.qtype = d_handle.qtype;
+ d_question.qname = qname;
+ d_question.zoneId = d_handle.zoneId;
+
+ auto cacheResult = cacheHas(d_question, d_answers);
+ if (cacheResult == CacheResult::Miss) { // nothing
+ // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): uncached"<<endl;
+ d_negcached = d_cached = false;
+ d_answers.clear();
+ (d_handle.d_hinterBackend = backends[d_handle.i++].get())->lookup(d_handle.qtype, d_handle.qname, d_handle.zoneId, d_handle.pkt_p);
+ ++(*s_backendQueries);
+ }
+ else if (cacheResult == CacheResult::NegativeMatch) {
+ // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): NEGcached"<<endl;
+ d_negcached = true;
+ d_cached = false;
+ d_answers.clear();
+ }
else {
- d_question.qtype=d_handle.qtype;
- d_question.qname=qname;
- d_question.zoneId=d_handle.zoneId;
-
- int cstat=cacheHas(d_question, d_answers);
- if(cstat<0) { // nothing
- // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): uncached"<<endl;
- d_negcached=d_cached=false;
- d_answers.clear();
- (d_handle.d_hinterBackend=backends[d_handle.i++])->lookup(d_handle.qtype, d_handle.qname, d_handle.zoneId, d_handle.pkt_p);
- ++(*s_backendQueries);
- }
- else if(cstat==0) {
- // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): NEGcached"<<endl;
- d_negcached=true;
- d_cached=false;
- d_answers.clear();
- }
- else {
- // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): CACHED"<<endl;
- d_negcached=false;
- d_cached=true;
- d_cachehandleiter = d_answers.begin();
- }
+ // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): CACHED"<<endl;
+ d_negcached = false;
+ d_cached = true;
+ d_cachehandleiter = d_answers.begin();
}
- d_handle.parent=this;
+ d_handle.parent = this;
}
void UeberBackend::getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled)
{
- for (auto & backend : backends)
- {
+ for (auto& backend : backends) {
backend->getAllDomains(domains, getSerial, include_disabled);
}
}
-bool UeberBackend::get(DNSZoneRecord &rr)
+bool UeberBackend::get(DNSZoneRecord& resourceRecord)
{
// cout<<"UeberBackend::get(DNSZoneRecord) called"<<endl;
- if(d_negcached) {
- return false;
+ if (d_negcached) {
+ return false;
}
- if(d_cached) {
- while(d_cachehandleiter != d_answers.end()) {
- rr=*d_cachehandleiter++;;
- if((d_qtype == QType::ANY || rr.dr.d_type == d_qtype)) {
+ if (d_cached) {
+ while (d_cachehandleiter != d_answers.end()) {
+ resourceRecord = *d_cachehandleiter++;
+ if ((d_qtype == QType::ANY || resourceRecord.dr.d_type == d_qtype)) {
return true;
}
}
return false;
}
- while(d_handle.get(rr)) {
- rr.dr.d_place=DNSResourceRecord::ANSWER;
- d_answers.push_back(rr);
- if((d_qtype == QType::ANY || rr.dr.d_type == d_qtype)) {
+ while (d_handle.get(resourceRecord)) {
+ resourceRecord.dr.d_place = DNSResourceRecord::ANSWER;
+ d_answers.push_back(resourceRecord);
+ if ((d_qtype == QType::ANY || resourceRecord.dr.d_type == d_qtype)) {
return true;
}
}
// cout<<"end of ueberbackend get, seeing if we should cache"<<endl;
- if(d_answers.empty()) {
+ if (d_answers.empty()) {
// cout<<"adding negcache"<<endl;
addNegCache(d_question);
}
//
bool UeberBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
{
- for (auto* b : backends) {
- if (b->setTSIGKey(name, algorithm, content)) {
+ for (auto& backend : backends) {
+ if (backend->setTSIGKey(name, algorithm, content)) {
return true;
}
}
algorithm.clear();
content.clear();
- for (auto* b : backends) {
- if (b->getTSIGKey(name, algorithm, content)) {
+ for (auto& backend : backends) {
+ if (backend->getTSIGKey(name, algorithm, content)) {
break;
}
}
{
keys.clear();
- for (auto* b : backends) {
- if (b->getTSIGKeys(keys)) {
+ for (auto& backend : backends) {
+ if (backend->getTSIGKeys(keys)) {
return true;
}
}
bool UeberBackend::deleteTSIGKey(const DNSName& name)
{
- for (auto* b : backends) {
- if (b->deleteTSIGKey(name)) {
+ for (auto& backend : backends) {
+ if (backend->deleteTSIGKey(name)) {
return true;
}
}
// API Search
//
-bool UeberBackend::searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result)
+bool UeberBackend::searchRecords(const string& pattern, size_t maxResults, vector<DNSResourceRecord>& result)
{
- bool rc = false;
- for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<DNSResourceRecord>::size_type>(maxResults) && i != backends.end(); ++i )
- if ((*i)->searchRecords(pattern, maxResults - result.size(), result)) rc = true;
- return rc;
+ bool ret = false;
+ for (auto backend = backends.begin(); result.size() < maxResults && backend != backends.end(); ++backend) {
+ if ((*backend)->searchRecords(pattern, maxResults - result.size(), result)) {
+ ret = true;
+ }
+ }
+ return ret;
}
-bool UeberBackend::searchComments(const string& pattern, int maxResults, vector<Comment>& result)
+bool UeberBackend::searchComments(const string& pattern, size_t maxResults, vector<Comment>& result)
{
- bool rc = false;
- for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<Comment>::size_type>(maxResults) && i != backends.end(); ++i )
- if ((*i)->searchComments(pattern, maxResults - result.size(), result)) rc = true;
- return rc;
+ bool ret = false;
+ for (auto backend = backends.begin(); result.size() < maxResults && backend != backends.end(); ++backend) {
+ if ((*backend)->searchComments(pattern, maxResults - result.size(), result)) {
+ ret = true;
+ }
+ }
+ return ret;
}
AtomicCounter UeberBackend::handle::instances(0);
{
// g_log<<Logger::Warning<<"Handle instances: "<<instances<<endl;
++instances;
- parent=nullptr;
- d_hinterBackend=nullptr;
- pkt_p=nullptr;
- i=0;
- zoneId = -1;
}
UeberBackend::handle::~handle()
--instances;
}
-bool UeberBackend::handle::get(DNSZoneRecord &r)
+bool UeberBackend::handle::get(DNSZoneRecord& record)
{
- DLOG(g_log << "Ueber get() was called for a "<<qtype<<" record" << endl);
- bool isMore=false;
- while(d_hinterBackend && !(isMore=d_hinterBackend->get(r))) { // this backend out of answers
- if(i<parent->backends.size()) {
- DLOG(g_log<<"Backend #"<<i<<" of "<<parent->backends.size()
- <<" out of answers, taking next"<<endl);
-
- d_hinterBackend=parent->backends[i++];
- d_hinterBackend->lookup(qtype,qname,zoneId,pkt_p);
+ DLOG(g_log << "Ueber get() was called for a " << qtype << " record" << endl);
+ bool isMore = false;
+ while (d_hinterBackend != nullptr && !(isMore = d_hinterBackend->get(record))) { // this backend out of answers
+ if (i < parent->backends.size()) {
+ DLOG(g_log << "Backend #" << i << " of " << parent->backends.size()
+ << " out of answers, taking next" << endl);
+
+ d_hinterBackend = parent->backends[i++].get();
+ d_hinterBackend->lookup(qtype, qname, zoneId, pkt_p);
++(*s_backendQueries);
}
- else
+ else {
break;
+ }
- DLOG(g_log<<"Now asking backend #"<<i<<endl);
+ DLOG(g_log << "Now asking backend #" << i << endl);
}
- if(!isMore && i==parent->backends.size()) {
- DLOG(g_log<<"UeberBackend reached end of backends"<<endl);
+ if (!isMore && i == parent->backends.size()) {
+ DLOG(g_log << "UeberBackend reached end of backends" << endl);
return false;
}
- DLOG(g_log<<"Found an answering backend - will not try another one"<<endl);
- i=parent->backends.size(); // don't go on to the next backend
+ DLOG(g_log << "Found an answering backend - will not try another one" << endl);
+ i = parent->backends.size(); // don't go on to the next backend
return true;
}
/** This is a very magic backend that allows us to load modules dynamically,
and query them in order. This is persistent over all UeberBackend instantiations
- across multiple threads.
+ across multiple threads.
The UeberBackend is transparent for exceptions, which should fall straight through.
*/
class UeberBackend : public boost::noncopyable
{
public:
- UeberBackend(const string &pname="default");
+ UeberBackend(const string& pname = "default");
~UeberBackend();
- bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db);
+ bool autoPrimaryBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** dnsBackend);
- bool superMasterAdd(const AutoPrimary &primary);
+ bool autoPrimaryAdd(const AutoPrimary& primary);
bool autoPrimaryRemove(const struct AutoPrimary& primary);
bool autoPrimariesList(std::vector<AutoPrimary>& primaries);
/** Tracks all created UeberBackend instances for us. We use this vector to notify
- existing threads of new modules
+ existing threads of new modules
*/
- static LockGuarded<vector<UeberBackend *>> d_instances;
+ static LockGuarded<vector<UeberBackend*>> d_instances;
- static bool loadmodule(const string &name);
+ static bool loadmodule(const string& name);
static bool loadModules(const vector<string>& modules, const string& path);
- static void go(void);
+ static void go();
/** This contains all registered backends. The DynListener modifies this list for us when
new modules are loaded */
- vector<DNSBackend*> backends;
-
- void cleanup();
+ vector<std::unique_ptr<DNSBackend>> backends;
//! the very magic handle for UeberBackend questions
class handle
{
public:
- bool get(DNSZoneRecord &dr);
+ bool get(DNSZoneRecord& record);
handle();
~handle();
//! The UeberBackend class where this handle belongs to
- UeberBackend *parent;
+ UeberBackend* parent{nullptr};
//! The current real backend, which is answering questions
- DNSBackend *d_hinterBackend;
+ DNSBackend* d_hinterBackend{nullptr};
//! DNSPacket who asked this question
- DNSPacket* pkt_p;
+ DNSPacket* pkt_p{nullptr};
DNSName qname;
//! Index of the current backend within the backends vector
- unsigned int i;
+ unsigned int i{0};
QType qtype;
- int zoneId;
+ int zoneId{-1};
private:
-
static AtomicCounter instances;
};
- void lookup(const QType &, const DNSName &qdomain, int zoneId, DNSPacket *pkt_p=nullptr);
+ void lookup(const QType& qtype, const DNSName& qname, int zoneId, DNSPacket* pkt_p = nullptr);
/** Determines if we are authoritative for a zone, and at what level */
- bool getAuth(const DNSName &target, const QType &qtype, SOAData* sd, bool cachedOk=true);
+ 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 &sd);
- bool get(DNSZoneRecord &r);
+ bool getSOAUncached(const DNSName& domain, SOAData& soaData);
+ bool get(DNSZoneRecord& resourceRecord);
void getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled);
- void getUnfreshSlaveInfos(vector<DomainInfo>* domains);
- void getUpdatedMasters(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes);
- bool getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial=true);
- bool createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account);
-
+ void getUnfreshSecondaryInfos(vector<DomainInfo>* domains);
+ void getUpdatedPrimaries(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes);
+ bool getDomainInfo(const DNSName& domain, DomainInfo& domainInfo, bool getSerial = true);
+ bool createDomain(const DNSName& domain, DomainInfo::DomainKind kind, const vector<ComboAddress>& primaries, const string& account);
+
bool doesDNSSEC();
- bool addDomainKey(const DNSName& name, const DNSBackend::KeyData& key, int64_t& id);
+ bool addDomainKey(const DNSName& name, const DNSBackend::KeyData& key, int64_t& keyID);
bool getDomainKeys(const DNSName& name, std::vector<DNSBackend::KeyData>& keys);
- bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta);
+ bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta);
bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta);
bool getDomainMetadata(const DNSName& name, const std::string& kind, std::string& meta);
bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta);
bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::string& meta);
- bool removeDomainKey(const DNSName& name, unsigned int id);
- bool activateDomainKey(const DNSName& name, unsigned int id);
- bool deactivateDomainKey(const DNSName& name, unsigned int id);
- bool publishDomainKey(const DNSName& name, unsigned int id);
- bool unpublishDomainKey(const DNSName& name, unsigned int id);
+ bool removeDomainKey(const DNSName& name, unsigned int keyID);
+ bool activateDomainKey(const DNSName& name, unsigned int keyID);
+ bool deactivateDomainKey(const DNSName& name, unsigned int keyID);
+ bool publishDomainKey(const DNSName& name, unsigned int keyID);
+ bool unpublishDomainKey(const DNSName& name, unsigned int keyID);
- void alsoNotifies(const DNSName &domain, set<string> *ips);
- void rediscover(string* status=0);
+ void alsoNotifies(const DNSName& domain, set<string>* ips);
+ void rediscover(string* status = nullptr);
void reload();
bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content);
bool getTSIGKeys(std::vector<struct TSIGKey>& keys);
bool deleteTSIGKey(const DNSName& name);
- bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result);
- bool searchComments(const string &pattern, int maxResults, vector<Comment>& result);
+ bool searchRecords(const string& pattern, vector<DNSResourceRecord>::size_type maxResults, vector<DNSResourceRecord>& result);
+ bool searchComments(const string& pattern, size_t maxResults, vector<Comment>& result);
void updateZoneCache();
DNSName qname;
int zoneId;
QType qtype;
- }d_question;
+ } d_question;
unsigned int d_cache_ttl, d_negcache_ttl;
- uint16_t d_qtype;
+ uint16_t d_qtype{0};
- bool d_negcached;
- bool d_cached;
+ bool d_negcached{false};
+ bool d_cached{false};
static AtomicCounter* s_backendQueries;
static bool d_go;
- bool d_stale;
+ bool d_stale{false};
static bool s_doANYLookupsOnly;
- int cacheHas(const Question &q, vector<DNSZoneRecord> &rrs);
- void addNegCache(const Question &q);
- void addCache(const Question &q, vector<DNSZoneRecord>&& rrs);
+ enum CacheResult
+ {
+ Miss = -1,
+ NegativeMatch = 0,
+ Hit = 1,
+ };
+
+ CacheResult cacheHas(const Question& question, vector<DNSZoneRecord>& resourceRecords) const;
+ void addNegCache(const Question& question) const;
+ void addCache(const Question& question, vector<DNSZoneRecord>&& rrs) const;
+
+ bool fillSOAFromZoneRecord(DNSName& shorter, int zoneId, SOAData* soaData);
+ CacheResult fillSOAFromCache(SOAData* soaData, DNSName& shorter);
};
/** Helper to build a record content as needed. */
static inline string makeRecordContent(const QType& qtype, const string& content, bool noDot) {
// noDot: for backend storage, pass true. for API users, pass false.
- auto drc = DNSRecordContent::mastermake(qtype.getCode(), QClass::IN, content);
+ auto drc = DNSRecordContent::make(qtype.getCode(), QClass::IN, content);
return drc->getZoneRepresentation(noDot);
}
static Json::object getZoneInfo(const DomainInfo& di, DNSSECKeeper* dk) {
string zoneId = apiZoneNameToId(di.zone);
- vector<string> masters;
- masters.reserve(di.masters.size());
- for(const auto& m : di.masters) {
- masters.push_back(m.toStringWithPortExcept(53));
+ vector<string> primaries;
+ primaries.reserve(di.primaries.size());
+ for (const auto& m : di.primaries) {
+ primaries.push_back(m.toStringWithPortExcept(53));
}
auto obj = Json::object{
{"kind", di.getKindString()},
{"catalog", (!di.catalog.empty() ? di.catalog.toString() : "")},
{"account", di.account},
- {"masters", std::move(masters)},
+ {"masters", std::move(primaries)},
{"serial", (double)di.serial},
{"notified_serial", (double)di.notified_serial},
{"last_check", (double)di.last_check}};
doc["api_rectify"] = (api_rectify == "1");
// TSIG
- vector<string> tsig_master, tsig_slave;
- di.backend->getDomainMetadata(zonename, "TSIG-ALLOW-AXFR", tsig_master);
- di.backend->getDomainMetadata(zonename, "AXFR-MASTER-TSIG", tsig_slave);
+ vector<string> tsig_primary, tsig_secondary;
+ di.backend->getDomainMetadata(zonename, "TSIG-ALLOW-AXFR", tsig_primary);
+ di.backend->getDomainMetadata(zonename, "AXFR-MASTER-TSIG", tsig_secondary);
- Json::array tsig_master_keys;
- for (const auto& keyname : tsig_master) {
- tsig_master_keys.push_back(apiZoneNameToId(DNSName(keyname)));
+ Json::array tsig_primary_keys;
+ for (const auto& keyname : tsig_primary) {
+ tsig_primary_keys.push_back(apiZoneNameToId(DNSName(keyname)));
}
- doc["master_tsig_key_ids"] = tsig_master_keys;
+ doc["master_tsig_key_ids"] = tsig_primary_keys;
- Json::array tsig_slave_keys;
- for (const auto& keyname : tsig_slave) {
- tsig_slave_keys.push_back(apiZoneNameToId(DNSName(keyname)));
+ Json::array tsig_secondary_keys;
+ for (const auto& keyname : tsig_secondary) {
+ tsig_secondary_keys.push_back(apiZoneNameToId(DNSName(keyname)));
}
- doc["slave_tsig_key_ids"] = tsig_slave_keys;
+ doc["slave_tsig_key_ids"] = tsig_secondary_keys;
if (shouldDoRRSets(req)) {
vector<DNSResourceRecord> records;
return api_rectify == "1";
}
-static void extractDomainInfoFromDocument(const Json& document, boost::optional<DomainInfo::DomainKind>& kind, boost::optional<vector<ComboAddress>>& masters, boost::optional<DNSName>& catalog, boost::optional<string>& account)
+static void extractDomainInfoFromDocument(const Json& document, boost::optional<DomainInfo::DomainKind>& kind, boost::optional<vector<ComboAddress>>& primaries, boost::optional<DNSName>& catalog, boost::optional<string>& account)
{
if (document["kind"].is_string()) {
kind = DomainInfo::stringToKind(stringFromJson(document, "kind"));
}
if (document["masters"].is_array()) {
- masters = vector<ComboAddress>();
+ primaries = vector<ComboAddress>();
for(const auto& value : document["masters"].array_items()) {
- string master = value.string_value();
- if (master.empty())
- throw ApiException("Master can not be an empty string");
+ string primary = value.string_value();
+ if (primary.empty())
+ throw ApiException("Primary can not be an empty string");
try {
- masters->emplace_back(master, 53);
+ primaries->emplace_back(primary, 53);
} catch (const PDNSException &e) {
- throw ApiException("Master (" + master + ") is not an IP address: " + e.reason);
+ throw ApiException("Primary (" + primary + ") is not an IP address: " + e.reason);
}
}
} else {
- masters = boost::none;
+ primaries = boost::none;
}
if (document["catalog"].is_string()) {
// Must be called within backend transaction.
static void updateDomainSettingsFromDocument(UeberBackend& B, DomainInfo& di, const DNSName& zonename, const Json& document, bool zoneWasModified) {
boost::optional<DomainInfo::DomainKind> kind;
- boost::optional<vector<ComboAddress>> masters;
+ boost::optional<vector<ComboAddress>> primaries;
boost::optional<DNSName> catalog;
boost::optional<string> account;
- extractDomainInfoFromDocument(document, kind, masters, catalog, account);
+ extractDomainInfoFromDocument(document, kind, primaries, catalog, account);
if (kind) {
di.backend->setKind(zonename, *kind);
di.kind = *kind;
}
- if (masters) {
- di.backend->setMasters(zonename, *masters);
+ if (primaries) {
+ di.backend->setPrimaries(zonename, *primaries);
}
if (catalog) {
di.backend->setCatalog(zonename, *catalog);
vector<string> metadata;
extractJsonTSIGKeyIds(B, document["master_tsig_key_ids"], metadata);
if (!di.backend->setDomainMetadata(zonename, "TSIG-ALLOW-AXFR", metadata)) {
- throw HttpInternalServerErrorException("Unable to set new TSIG master keys for zone '" + zonename.toLogString() + "'");
+ throw HttpInternalServerErrorException("Unable to set new TSIG primary keys for zone '" + zonename.toLogString() + "'");
}
}
if (!document["slave_tsig_key_ids"].is_null()) {
vector<string> metadata;
extractJsonTSIGKeyIds(B, document["slave_tsig_key_ids"], metadata);
if (!di.backend->setDomainMetadata(zonename, "AXFR-MASTER-TSIG", metadata)) {
- throw HttpInternalServerErrorException("Unable to set new TSIG slave keys for zone '" + zonename.toLogString() + "'");
+ throw HttpInternalServerErrorException("Unable to set new TSIG secondary keys for zone '" + zonename.toLogString() + "'");
}
}
}
if (primary.ip=="" or primary.nameserver=="") {
throw ApiException("ip and nameserver fields must be filled");
}
- if (!B.superMasterAdd(primary))
+ if (!B.autoPrimaryAdd(primary))
throw HttpInternalServerErrorException("Cannot find backend with autoprimary feature");
resp->body = "";
resp->status = 201;
}
boost::optional<DomainInfo::DomainKind> kind;
- boost::optional<vector<ComboAddress>> masters;
+ boost::optional<vector<ComboAddress>> primaries;
boost::optional<DNSName> catalog;
boost::optional<string> account;
- extractDomainInfoFromDocument(document, kind, masters, catalog, account);
+ extractDomainInfoFromDocument(document, kind, primaries, catalog, account);
// validate 'kind' is set
if (!kind) {
}
auto nameservers = document["nameservers"];
- if (!nameservers.is_null() && !nameservers.is_array() && zonekind != DomainInfo::Slave && zonekind != DomainInfo::Consumer) {
+ if (!nameservers.is_null() && !nameservers.is_array() && zonekind != DomainInfo::Secondary && zonekind != DomainInfo::Consumer) {
throw ApiException("Nameservers is not a list");
}
autorr.auth = true;
autorr.ttl = ::arg().asNum("default-ttl");
- if (!have_soa && zonekind != DomainInfo::Slave && zonekind != DomainInfo::Consumer) {
+ if (!have_soa && zonekind != DomainInfo::Secondary && zonekind != DomainInfo::Consumer) {
// synthesize a SOA record so the zone "really" exists
string soa = ::arg()["default-soa-content"];
boost::replace_all(soa, "@", zonename.toStringNoDot());
}
// no going back after this
- if(!B.createDomain(zonename, kind.get_value_or(DomainInfo::Native), masters.get_value_or(vector<ComboAddress>()), account.get_value_or(""))) {
+ if (!B.createDomain(zonename, kind.get_value_or(DomainInfo::Native), primaries.get_value_or(vector<ComboAddress>()), account.get_value_or(""))) {
throw ApiException("Creating domain '"+zonename.toString()+"' failed: backend refused");
}
updateDomainSettingsFromDocument(B, di, zonename, document, !new_records.empty());
- if (!catalog && kind == DomainInfo::Master) {
+ if (!catalog && kind == DomainInfo::Primary) {
auto defaultCatalog = ::arg()["default-catalog-zone"];
if (!defaultCatalog.empty()) {
di.backend->setCatalog(zonename, DNSName(defaultCatalog));
}
}
- if (!haveSoa && newKind != DomainInfo::Slave && newKind != DomainInfo::Consumer) {
+ if (!haveSoa && newKind != DomainInfo::Secondary && newKind != DomainInfo::Consumer) {
// Require SOA if this is a primary zone.
throw ApiException("Must give SOA record for zone when replacing all RR sets");
}
di.backend->feedComment(c);
}
- if (!haveSoa && (newKind == DomainInfo::Slave || newKind == DomainInfo::Consumer)) {
+ if (!haveSoa && (newKind == DomainInfo::Secondary || newKind == DomainInfo::Consumer)) {
di.backend->setStale(di.id);
}
} else {
throw HttpNotFoundException();
}
- if(di.masters.empty())
- throw ApiException("Domain '"+zonename.toString()+"' is not a slave domain (or has no master defined)");
+ if (di.primaries.empty())
+ throw ApiException("Domain '" + zonename.toString() + "' is not a secondary domain (or has no primary defined)");
- shuffle(di.masters.begin(), di.masters.end(), pdns::dns_random_engine());
- Communicator.addSuckRequest(zonename, di.masters.front(), SuckRequest::Api);
- resp->setSuccessResult("Added retrieval request for '"+zonename.toString()+"' from master "+di.masters.front().toLogString());
+ shuffle(di.primaries.begin(), di.primaries.end(), pdns::dns_random_engine());
+ Communicator.addSuckRequest(zonename, di.primaries.front(), SuckRequest::Api);
+ resp->setSuccessResult("Added retrieval request for '" + zonename.toString() + "' from primary " + di.primaries.front().toLogString());
}
static void apiServerZoneNotify(HttpRequest* req, HttpResponse* resp) {
string sMax = req->getvars["max"];
string sObjectType = req->getvars["object_type"];
- int maxEnts = 100;
- int ents = 0;
+ size_t maxEnts = 100;
+ size_t ents = 0;
// the following types of data can be searched for using the api
enum class ObjectType
cout<<"BEGIN TRANSACTION;"<<endl;
}
-static void emitDomain(const DNSName& domain, const vector<ComboAddress> *masters = nullptr) {
+static void emitDomain(const DNSName& domain, const vector<ComboAddress>* primaries = nullptr)
+{
string iDomain = domain.toStringRootDot();
- if(!::arg().mustDo("slave")) {
+ if (!::arg().mustDo("secondary")) {
cout<<"insert into domains (name,type) values ("<<toLower(sqlstr(iDomain))<<",'NATIVE');"<<endl;
}
else
{
string mstrs;
- if (masters != nullptr && ! masters->empty()) {
- for(const auto& mstr : *masters) {
+ if (primaries != nullptr && !primaries->empty()) {
+ for (const auto& mstr : *primaries) {
mstrs.append(mstr.toStringWithPortExcept(53));
mstrs.append(1, ' ');
}
::arg().setSwitch("gmysql","Output in format suitable for default gmysqlbackend")="no";
::arg().setSwitch("gsqlite","Output in format suitable for default gsqlitebackend")="no";
::arg().setSwitch("verbose","Verbose comments on operation")="no";
- ::arg().setSwitch("slave","Keep BIND slaves as slaves. Only works with named-conf.")="no";
+ ::arg().setSwitch("secondary", "Keep BIND secondaries as secondaries. Only works with named-conf.") = "no";
::arg().setSwitch("json-comments","Parse json={} field for disabled & comments")="no";
::arg().setSwitch("transactions","If target SQL supports it, use transactions")="no";
::arg().setSwitch("on-error-resume-next","Continue after errors")="no";
try {
startNewTransaction();
- emitDomain(domain.name, &(domain.masters));
+ emitDomain(domain.name, &(domain.primaries));
ZoneParserTNG zpt(domain.filename, domain.name, BP.getDirectory());
zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
while (zpt.get(dnsResourceRecord)) {
std::shared_ptr<DNSRecordContent> drc;
try {
- drc = DNSRecordContent::mastermake(dnsResourceRecord.qtype, QClass::IN, dnsResourceRecord.content);
+ drc = DNSRecordContent::make(dnsResourceRecord.qtype, QClass::IN, dnsResourceRecord.content);
}
catch (const PDNSException& pe) {
std::string err = "Bad record content in record for '" + dnsResourceRecord.qname.toStringNoDot() + "'|" + dnsResourceRecord.qtype.toString() + ": " + pe.reason;
data = r.json()
print("status for axfr-retrieve:", data)
self.assertEqual(data['result'], u'Added retrieval request for \'' + payload['name'] +
- '\' from master 127.0.0.2')
+ '\' from primary 127.0.0.2')
def test_notify_master_zone(self):
name, payload, data = self.create_zone(kind='Master')
dnspython==2.1.0
-nose>=1.3.7
+pytest
Twisted>0.15.0
requests>=2.18.4
git+https://github.com/PowerDNS/xfrserver.git@0.3
set -x
fi
-ignore="-I test_GSSTSIG.py"
+ignore="--ignore=test_GSSTSIG.py"
if [ "${WITHKERBEROS}" = "YES" ]; then
ignore=""
(cd kerberos-server && sudo docker compose up --detach --build)
fi
-nosetests --with-xunit $ignore $@
+pytest --junitxml=pytest.xml $ignore $@
ret=$?
if [ "${WITHKERBEROS}" = "YES" ]; then
launch=gsqlite3 bind
gsqlite3-database=configs/auth/powerdns.sqlite
gsqlite3-dnssec
-slave
-slave-cycle-interval=1
+secondary
+xfr-cycle-interval=1
query-cache-ttl=20
negquery-cache-ttl=60
"""
@classmethod
def setUpClass(cls):
super(TestIXFR, cls).setUpClass()
- os.system("$PDNSUTIL --config-dir=configs/auth create-slave-zone example. 127.0.0.1:%s" % (xfrServerPort,))
+ os.system("$PDNSUTIL --config-dir=configs/auth create-secondary-zone example. 127.0.0.1:%s" % (xfrServerPort,))
os.system("$PDNSUTIL --config-dir=configs/auth set-meta example. IXFR 1")
def waitUntilCorrectSerialIsLoaded(self, serial, timeout=10):
launch=gsqlite3 bind
gsqlite3-database=configs/auth/powerdns.sqlite
gsqlite3-dnssec
-slave
+secondary
cache-ttl=0
query-cache-ttl=0
domain-metadata-cache-ttl=0
negquery-cache-ttl=0
-slave-cycle-interval=1
+xfr-cycle-interval=1
#loglevel=9
#axfr-fetch-timeout=20
"""
@classmethod
def setUpClass(cls):
super(XFRIncompleteAuthTest, cls).setUpClass()
- os.system("$PDNSUTIL --config-dir=configs/auth create-slave-zone zone.rpz. 127.0.0.1:%s" % (badxfrServerPort,))
+ os.system("$PDNSUTIL --config-dir=configs/auth create-secondary-zone zone.rpz. 127.0.0.1:%s" % (badxfrServerPort,))
os.system("$PDNSUTIL --config-dir=configs/auth set-meta zone.rpz. IXFR 1")
def waitUntilCorrectSerialIsLoaded(self, serial, timeout=20):
import os.path
import base64
+import dns
import json
import requests
import socket
'latency-avg10000', 'latency-avg1000000', 'latency-tcp-avg100', 'latency-tcp-avg1000',
'latency-tcp-avg10000', 'latency-tcp-avg1000000', 'latency-dot-avg100', 'latency-dot-avg1000',
'latency-dot-avg10000', 'latency-dot-avg1000000', 'latency-doh-avg100', 'latency-doh-avg1000',
- 'latency-doh-avg10000', 'latency-doh-avg1000000', 'uptime', 'real-memory-usage', 'noncompliant-queries',
+ 'latency-doh-avg10000', 'latency-doh-avg1000000', 'latency-doq-avg100', 'latency-doq-avg1000',
+ 'latency-doq-avg10000', 'latency-doq-avg1000000','uptime', 'real-memory-usage', 'noncompliant-queries',
'noncompliant-responses', 'rdqueries', 'empty-queries', 'cache-hits',
'cache-misses', 'cpu-iowait', 'cpu-steal', 'cpu-sys-msec', 'cpu-user-msec', 'fd-usage', 'dyn-blocked',
'dyn-block-nmg-size', 'rule-servfail', 'rule-truncated', 'security-status',
for key in ['blocks']:
self.assertTrue(content[key] >= 0)
+ def testServersLocalhostRings(self):
+ """
+ API: /api/v1/servers/localhost/rings
+ """
+ headers = {'x-api-key': self._webServerAPIKey}
+ url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/rings'
+ expectedValues = ['age', 'id', 'name', 'requestor', 'size', 'qtype', 'protocol', 'rd']
+ expectedResponseValues = expectedValues + ['latency', 'rcode', 'tc', 'aa', 'answers', 'backend']
+ r = requests.get(url, headers=headers, timeout=self._webTimeout)
+ self.assertTrue(r)
+ self.assertEqual(r.status_code, 200)
+ self.assertTrue(r.json())
+ content = r.json()
+ self.assertIn('queries', content)
+ self.assertIn('responses', content)
+ self.assertEqual(len(content['queries']), 0)
+ self.assertEqual(len(content['responses']), 0)
+
+ name = 'simple.api.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN')
+ response = dns.message.make_response(query)
+ rrset = dns.rrset.from_text(name,
+ 3600,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '127.0.0.1')
+ response.answer.append(rrset)
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (receivedQuery, receivedResponse) = sender(query, response)
+ self.assertTrue(receivedQuery)
+ self.assertTrue(receivedResponse)
+ receivedQuery.id = query.id
+ self.assertEqual(query, receivedQuery)
+ self.assertEqual(response, receivedResponse)
+
+ r = requests.get(url, headers=headers, timeout=self._webTimeout)
+ self.assertTrue(r)
+ self.assertEqual(r.status_code, 200)
+ self.assertTrue(r.json())
+ content = r.json()
+ self.assertIn('queries', content)
+ self.assertIn('responses', content)
+ self.assertEqual(len(content['queries']), 2)
+ self.assertEqual(len(content['responses']), 2)
+ for entry in content['queries']:
+ for value in expectedValues:
+ self.assertIn(value, entry)
+ for entry in content['responses']:
+ for value in expectedResponseValues:
+ self.assertIn(value, entry)
+
class TestAPIServerDown(APITestsBase):
__test__ = True
_config_template = """
--- /dev/null
+#!/usr/bin/env python
+import extendederrors
+import dns
+from dnsdisttests import DNSDistTest, pickAvailablePort
+
+class TestBasics(DNSDistTest):
+
+ _config_template = """
+ newServer{address="127.0.0.1:%s"}
+ pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
+ getPool(""):setCache(pc)
+
+ local ffi = require("ffi")
+ function ffiAction(dq)
+ local extraText = 'Synthesized from Lua'
+ ffi.C.dnsdist_ffi_dnsquestion_set_extended_dns_error(dq, 29, extraText, #extraText)
+ local str = "192.0.2.2"
+ local buf = ffi.new("char[?]", #str + 1)
+ ffi.copy(buf, str)
+ ffi.C.dnsdist_ffi_dnsquestion_set_result(dq, buf, #str)
+ return DNSAction.Spoof
+ end
+
+ addAction("self-answered.ede.tests.powerdns.com.", SpoofAction("192.0.2.1"))
+ addAction("self-answered-ffi.ede.tests.powerdns.com.", LuaFFIAction(ffiAction))
+ addSelfAnsweredResponseAction("self-answered.ede.tests.powerdns.com.", SetExtendedDNSErrorResponseAction(42, "my self-answered extended error status"))
+ addAction(AllRule(), SetExtendedDNSErrorAction(16, "my extended error status"))
+
+ """
+
+ def testExtendedErrorNoEDNS(self):
+ """
+ EDE: No EDNS
+ """
+ name = 'no-edns.ede.tests.powerdns.com.'
+ # no EDNS
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+ response = dns.message.make_response(query)
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '127.0.0.1')
+
+ response.answer.append(rrset)
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (receivedQuery, receivedResponse) = sender(query, response)
+ receivedQuery.id = query.id
+ self.assertEqual(query, receivedQuery)
+ self.checkResponseNoEDNS(response, receivedResponse)
+
+ def testExtendedErrorBackendResponse(self):
+ """
+ EDE: Backend response
+ """
+ name = 'backend-response.ede.tests.powerdns.com.'
+ ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+
+ backendResponse = dns.message.make_response(query)
+ backendResponse.use_edns(edns=True, payload=4096, options=[])
+ 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])
+ 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
+ """
+ name = 'backend-response-existing-ede.ede.tests.powerdns.com.'
+ ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+
+ backendResponse = dns.message.make_response(query)
+ backendEDE = extendederrors.ExtendedErrorOption(3, b'Stale answer')
+ backendResponse.use_edns(edns=True, payload=4096, options=[backendEDE])
+ 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])
+ 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 testExtendedErrorSelfAnswered(self):
+ """
+ EDE: Self-answered
+ """
+ name = 'self-answered.ede.tests.powerdns.com.'
+ ede = extendederrors.ExtendedErrorOption(42, b'my self-answered extended error status')
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+ # dnsdist sets RA = RD for self-generated responses
+ query.flags &= ~dns.flags.RD
+
+ expectedResponse = dns.message.make_response(query)
+ expectedResponse.use_edns(edns=True, payload=1232, options=[ede])
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.1')
+ expectedResponse.answer.append(rrset)
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.checkMessageEDNS(expectedResponse, receivedResponse)
+
+ def testExtendedErrorLuaFFI(self):
+ """
+ EDE: Self-answered via Lua FFI
+ """
+ name = 'self-answered-ffi.ede.tests.powerdns.com.'
+ ede = extendederrors.ExtendedErrorOption(29, b'Synthesized from Lua')
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+ # dnsdist sets RA = RD for self-generated responses
+ query.flags &= ~dns.flags.RD
+
+ expectedResponse = dns.message.make_response(query)
+ expectedResponse.use_edns(edns=True, payload=1232, options=[ede])
+ rrset = dns.rrset.from_text(name,
+ 60,
+ dns.rdataclass.IN,
+ dns.rdatatype.A,
+ '192.0.2.2')
+ expectedResponse.answer.append(rrset)
+
+ for method in ("sendUDPQuery", "sendTCPQuery"):
+ sender = getattr(self, method)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False)
+ self.checkMessageEDNS(expectedResponse, receivedResponse)
self.assertTrue(receivedResponse)
self.assertEqual(expectedResponse, receivedResponse)
+class TestRmRules(DNSDistTest):
+ _consoleKey = DNSDistTest.generateConsoleKey()
+ _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+ _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+ _config_template = """
+ setKey("%s")
+ controlSocket("127.0.0.1:%s")
+ newServer{address="127.0.0.1:%s"}
+ addAction(AllRule(), SpoofAction("192.0.2.1"), {name='myFirstRule', uuid='090736ca-2fb6-41e7-a836-58efaca3d71e'})
+ addAction(AllRule(), SpoofAction("192.0.2.1"), {name='mySecondRule'})
+ addResponseAction(AllRule(), AllowResponseAction(), {name='myFirstResponseRule', uuid='745a03b5-89e0-4eee-a6bf-c9700b0d31f0'})
+ addResponseAction(AllRule(), AllowResponseAction(), {name='mySecondResponseRule'})
+ """
+
+ def testRmRules(self):
+ """
+ Advanced: Remove rules
+ """
+ lines = self.sendConsoleCommand("showRules({showUUIDs=true})").splitlines()
+ self.assertEqual(len(lines), 3)
+ self.assertIn('myFirstRule', lines[1])
+ self.assertIn('mySecondRule', lines[2])
+ self.assertIn('090736ca-2fb6-41e7-a836-58efaca3d71e', lines[1])
+
+ lines = self.sendConsoleCommand("showResponseRules({showUUIDs=true})").splitlines()
+ self.assertEqual(len(lines), 3)
+ self.assertIn('myFirstResponseRule', lines[1])
+ self.assertIn('mySecondResponseRule', lines[2])
+ self.assertIn('745a03b5-89e0-4eee-a6bf-c9700b0d31f0', lines[1])
+
+ self.sendConsoleCommand("rmRule('090736ca-2fb6-41e7-a836-58efaca3d71e')")
+ self.sendConsoleCommand("rmRule('mySecondRule')")
+ lines = self.sendConsoleCommand("showRules({showUUIDs=true})").splitlines()
+ self.assertEqual(len(lines), 1)
+
+ self.sendConsoleCommand("rmResponseRule('745a03b5-89e0-4eee-a6bf-c9700b0d31f0')")
+ self.sendConsoleCommand("rmResponseRule('mySecondResponseRule')")
+ lines = self.sendConsoleCommand("showResponseRules({showUUIDs=true})").splitlines()
+ self.assertEqual(len(lines), 1)
+
class TestAdvancedContinueAction(DNSDistTest):
_config_template = """
""",
3: """
$ORIGIN example.
-@ 86400 SOA foo bar 3 2 3 4 5
+@ 86400 SOA foo bar 3 1500 3 4 5
@ 4242 NS ns1.example.
@ 4242 NS ns2.example.
ns1.example. 4242 A 192.0.2.1
def tearDownClass(cls):
cls.tearDownIXFRDist()
- def waitUntilCorrectSerialIsLoaded(self, serial, timeout=10):
+ def waitUntilCorrectSerialIsLoaded(self, serial, timeout=10, notify=False):
global xfrServer
xfrServer.moveToSerial(serial)
+ if notify:
+ notif = dns.message.make_query('example.', 'SOA')
+ notif.set_opcode(dns.opcode.NOTIFY)
+ notify_response = self.sendUDPQuery(notif)
+ assert notify_response.rcode() == dns.rcode.NOERROR
+
def get_current_serial():
query = dns.message.make_query('example.', 'SOA')
response_message = self.sendUDPQuery(query)
self.checkIXFR(2,3)
self.checkIXFR(1,3)
- self.waitUntilCorrectSerialIsLoaded(4)
+ self.waitUntilCorrectSerialIsLoaded(serial=4, timeout=10, notify=True)
self.checkFullZone(4)
self.checkIXFR(3,4)
self.checkIXFR(2,4)
"ixfrdist_unknown_domain_inqueries_total",
"ixfrdist_sys_msec", "ixfrdist_user_msec",
"ixfrdist_real_memory_usage",
- "ixfrdist_fd_usage"]
+ "ixfrdist_fd_usage",
+ "ixfrdist_notimp"]
metric_domain_stats = ["ixfrdist_soa_serial", "ixfrdist_soa_checks_total",
"ixfrdist_soa_checks_failed_total",
"ixfrdist_soa_inqueries_total",
{
$RUNWRAPPER $PDNS --daemon=no --local-port=$port --config-dir=. --module-dir=../regression-tests/modules \
--config-name=gsqlite3-master --socket-dir=./ --no-shuffle \
- --master=yes --local-address=127.0.0.1 \
+ --primary=yes --local-address=127.0.0.1 \
--query-local-address=127.0.0.1 --cache-ttl=$cachettl --dname-processing --allow-axfr-ips= &
}
$RUNWRAPPER $PDNS --daemon=no --local-port=$slaveport --config-dir=. --module-dir=../regression-tests/modules \
--config-name=gsqlite3-slave --socket-dir=./ --no-shuffle --local-address=127.0.0.2 \
- --slave --retrieval-threads=4 --slave=yes --superslave=yes --query-local-address=127.0.0.2 \
- --slave-cycle-interval=300 --allow-unsigned-notify=no --allow-unsigned-supermaster=no &
+ --secondary --retrieval-threads=4 --autosecondary=yes --query-local-address=127.0.0.2 \
+ --xfr-cycle-interval=300 --allow-unsigned-notify=no --allow-unsigned-autoprimary=no &
}
check_process ()
{
$RUNWRAPPER $PDNS --daemon=no --local-port=$port --config-dir=. --module-dir=../regression-tests/modules \
--config-name=gsqlite3-master --socket-dir=./ --no-shuffle \
- --master=yes --local-address=127.0.0.1 \
+ --primary=yes --local-address=127.0.0.1 \
--query-local-address=127.0.0.1 --cache-ttl=$cachettl --dname-processing --allow-axfr-ips= &
}
$RUNWRAPPER $PDNS --daemon=no --local-port=$slaveport --config-dir=. --module-dir=../regression-tests/modules \
--config-name=gsqlite3-slave --socket-dir=./ --no-shuffle --local-address=127.0.0.2 \
- --slave --retrieval-threads=4 --slave=yes --superslave=yes --query-local-address=127.0.0.2 \
- --slave-cycle-interval=300 --dname-processing &
+ --secondary --retrieval-threads=4 --autosecondary=yes --query-local-address=127.0.0.2 \
+ --xfr-cycle-interval=300 --dname-processing &
}
check_process ()
_config_template = """
dnssec=validate
aggressive-nsec-cache-size=10000
+ nsec3-max-iterations=150
webserver=yes
webserver-port=%d
webserver-address=127.0.0.1
except subprocess.CalledProcessError as e:
raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
- params = "1 0 100 AABBCCDDEEFF112233"
+ params = "1 0 50 AABBCCDDEEFF112233"
if zone == "optout.example":
- params = "1 1 100 AABBCCDDEEFF112233"
+ params = "1 1 50 AABBCCDDEEFF112233"
pdnsutilCmd = [os.environ['PDNSUTIL'],
'--config-dir=%s' % confdir,
Reply to question for qname='www3.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 www3.example.net. IN CNAME [ttl] www2.example.net.
-0 www2.example.net. IN A [ttl] 192.0.2.2
+0 www3.example.net. [ttl] IN CNAME www2.example.net.
+0 www2.example.net. [ttl] IN A 192.0.2.2
Reply to question for qname='android.marvin.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 android.marvin.example.net. IN A [ttl] 192.0.2.5
+0 android.marvin.example.net. [ttl] IN A 192.0.2.5
Reply to question for qname='www5.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 www5.example.net. IN A [ttl] 192.0.2.25
+0 www5.example.net. [ttl] IN A 192.0.2.25
echo "==> defpol-with-ttl.example.net should use the default policy's TTL and not the zone one"
$SDIG $nameserver 5301 defpol-with-ttl.example.net a recurse 2>&1
echo "==> defpol-with-ttl-capped.example.net should use the default policy's TTL, but capped to maxTTL"
-$SDIG $nameserver 5301 defpol-with-ttl-capped.example.net a recurse 2>&1 | sed 's/\(0\tdefault.example.net.\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\115/'
+$SDIG $nameserver 5301 defpol-with-ttl-capped.example.net a recurse 2>&1 | sed 's/\(0\tdefault.example.net.\t\)\([0-9]\+\)/\115/'
echo "==> defpol-without-ttl.example.net should use the zone's TTL"
-$SDIG $nameserver 5301 defpol-without-ttl.example.net a recurse 2>&1 | sed 's/\(0\tdefault.example.net.\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\115/'
+$SDIG $nameserver 5301 defpol-without-ttl.example.net a recurse 2>&1 | sed 's/\(0\tdefault.example.net.\t\)\([0-9]\+\)/\115/'
echo "==> defpol-without-ttl-capped.example.net should use the zone's TTL but capped to maxTTL"
-$SDIG $nameserver 5301 defpol-without-ttl-capped.example.net a recurse 2>&1 | sed 's/\(0\tdefault.example.net.\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\115/'
+$SDIG $nameserver 5301 defpol-without-ttl-capped.example.net a recurse 2>&1 | sed 's/\(0\tdefault.example.net.\t\)\([0-9]\+\)/\115/'
echo "==> unsupported.example.net has an unsupported target, should be ignored from the RPZ zone"
$SDIG $nameserver 5301 unsupported.example.net a recurse 2>&1
echo "==> unsupported2.example.net has an unsupported target, should be ignored from the RPZ zone"
==> srv.arthur.example.net RPZ passthru
Reply to question for qname='srv.arthur.example.net.', qtype=SRV
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 srv.arthur.example.net. IN SRV 15 0 100 389 server2.example.net.
+0 srv.arthur.example.net. 15 IN SRV 0 100 389 server2.example.net.
==> www.example.net RPZ local data to www2.example.net
Reply to question for qname='www.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 www.example.net. IN CNAME 7200 www2.example.net.
-0 www2.example.net. IN A 15 192.0.2.2
+0 www.example.net. 7200 IN CNAME www2.example.net.
+0 www2.example.net. 15 IN A 192.0.2.2
==> www4.example.net RPZ IP trigger action, dropped
==> trillian.example.net NXDOMAIN
Reply to question for qname='trillian.example.net.', qtype=A
==> www.trillian.example.net has no RPZ policy attached, so lookup should succeed
Reply to question for qname='www.trillian.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 www.trillian.example.net. IN CNAME 15 www3.arthur.example.net.
-0 www3.arthur.example.net. IN A 15 192.0.2.6
+0 www.trillian.example.net. 15 IN CNAME www3.arthur.example.net.
+0 www3.arthur.example.net. 15 IN A 192.0.2.6
==> www.hijackme.example.net is served on ns.hijackme.example.net, which should be NXDOMAIN
Reply to question for qname='www.hijackme.example.net.', qtype=A
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
==> capped-ttl.example.net TTL exceeds the maximum TTL for the zone
Reply to question for qname='capped-ttl.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 capped-ttl.example.net. IN A 5 192.0.2.35
+0 capped-ttl.example.net. 5 IN A 192.0.2.35
==> defpol-with-ttl.example.net should use the default policy's TTL and not the zone one
Reply to question for qname='defpol-with-ttl.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 defpol-with-ttl.example.net. IN CNAME 10 default.example.net.
-0 default.example.net. IN A 15 192.0.2.42
+0 defpol-with-ttl.example.net. 10 IN CNAME default.example.net.
+0 default.example.net. 15 IN A 192.0.2.42
==> defpol-with-ttl-capped.example.net should use the default policy's TTL, but capped to maxTTL
Reply to question for qname='defpol-with-ttl-capped.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 defpol-with-ttl-capped.example.net. IN CNAME 20 default.example.net.
-0 default.example.net. IN A 15 192.0.2.42
+0 defpol-with-ttl-capped.example.net. 20 IN CNAME default.example.net.
+0 default.example.net. 15 IN A 192.0.2.42
==> defpol-without-ttl.example.net should use the zone's TTL
Reply to question for qname='defpol-without-ttl.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 defpol-without-ttl.example.net. IN CNAME 7200 default.example.net.
-0 default.example.net. IN A 15 192.0.2.42
+0 defpol-without-ttl.example.net. 7200 IN CNAME default.example.net.
+0 default.example.net. 15 IN A 192.0.2.42
==> defpol-without-ttl-capped.example.net should use the zone's TTL but capped to maxTTL
Reply to question for qname='defpol-without-ttl-capped.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 defpol-without-ttl-capped.example.net. IN CNAME 50 default.example.net.
-0 default.example.net. IN A 15 192.0.2.42
+0 defpol-without-ttl-capped.example.net. 50 IN CNAME default.example.net.
+0 default.example.net. 15 IN A 192.0.2.42
==> unsupported.example.net has an unsupported target, should be ignored from the RPZ zone
Reply to question for qname='unsupported.example.net.', qtype=A
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-1 example.net. IN SOA 15 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+1 example.net. 15 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
==> unsupported2.example.net has an unsupported target, should be ignored from the RPZ zone
Reply to question for qname='unsupported2.example.net.', qtype=A
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-1 example.net. IN SOA 15 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+1 example.net. 15 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
==> not-rpz.example.net is _not_ an RPZ target and should be processed
Reply to question for qname='not-rpz.example.net.', qtype=A
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 not-rpz.example.net. IN CNAME 5 rpz-not.com.
-1 . IN SOA 15 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+0 not-rpz.example.net. 5 IN CNAME rpz-not.com.
+1 . 15 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
==> echo-me.wildcard-target.example.net is an RPZ wildcard target
Reply to question for qname='echo-me.wildcard-target.example.net.', qtype=A
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 echo-me.wildcard-target.example.net. IN CNAME 7200 echo-me.wildcard-target.example.net.walled-garden.example.net.
-1 example.net. IN SOA 15 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+0 echo-me.wildcard-target.example.net. 7200 IN CNAME echo-me.wildcard-target.example.net.walled-garden.example.net.
+1 example.net. 15 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
-cleandig service.box.answer-cname-in-local.example.net. A | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig service.box.answer-cname-in-local.example.net. A | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 pfs.global.box.answer-cname-in-local.example.net. IN CNAME 3600 vip-reunion.pfsbox.answer-cname-in-local.example.net.
-0 service.box.answer-cname-in-local.example.net. IN CNAME 3600 pfs.global.box.answer-cname-in-local.example.net.
-0 vip-reunion.pfsbox.answer-cname-in-local.example.net. IN A 3600 10.1.1.1
+0 pfs.global.box.answer-cname-in-local.example.net. 3600 IN CNAME vip-reunion.pfsbox.answer-cname-in-local.example.net.
+0 service.box.answer-cname-in-local.example.net. 3600 IN CNAME pfs.global.box.answer-cname-in-local.example.net.
+0 vip-reunion.pfsbox.answer-cname-in-local.example.net. 3600 IN A 10.1.1.1
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='service.box.answer-cname-in-local.example.net.', qtype=A
-cleandig host1.something.auth-zone.example.net. A | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig host1.something.auth-zone.example.net. AAAA | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig host1.something.auth-zone.example.net. A | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig host1.something.auth-zone.example.net. AAAA | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 host1.auth-zone.example.net. IN A 3600 127.0.0.55
-0 host1.something.auth-zone.example.net. IN CNAME 3600 host1.auth-zone.example.net.
+0 host1.auth-zone.example.net. 3600 IN A 127.0.0.55
+0 host1.something.auth-zone.example.net. 3600 IN CNAME host1.auth-zone.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='host1.something.auth-zone.example.net.', qtype=A
-0 host1.auth-zone.example.net. IN AAAA 3600 2001:db8::1:45ba
-0 host1.something.auth-zone.example.net. IN CNAME 3600 host1.auth-zone.example.net.
+0 host1.auth-zone.example.net. 3600 IN AAAA 2001:db8::1:45ba
+0 host1.something.auth-zone.example.net. 3600 IN CNAME host1.auth-zone.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='host1.something.auth-zone.example.net.', qtype=AAAA
-cleandig www.france.auth-zone.example.net. A | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig france.auth-zone.example.net. A | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www.france.auth-zone.example.net. A | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig france.auth-zone.example.net. A | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 www.france.auth-zone.example.net. IN A 3600 192.0.2.23
+0 www.france.auth-zone.example.net. 3600 IN A 192.0.2.23
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www.france.auth-zone.example.net.', qtype=A
-0 france.auth-zone.example.net. IN A 3600 192.0.2.223
+0 france.auth-zone.example.net. 3600 IN A 192.0.2.223
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='france.auth-zone.example.net.', qtype=A
-cleandig host1.auth-zone.example.net. A | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig host1.auth-zone.example.net. AAAA | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig host2.auth-zone.example.net. A | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig host3.auth-zone.example.net. A | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig you-are.wild.auth-zone.example.net. TXT | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig host1.auth-zone.example.net. A | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig host1.auth-zone.example.net. AAAA | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig host2.auth-zone.example.net. A | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig host3.auth-zone.example.net. A | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig you-are.wild.auth-zone.example.net. TXT | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
# Non-existing QTYPE at the apex
-cleandig auth-zone.example.net. TXT | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig auth-zone.example.net. TXT | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 host1.auth-zone.example.net. IN A 3600 127.0.0.55
+0 host1.auth-zone.example.net. 3600 IN A 127.0.0.55
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='host1.auth-zone.example.net.', qtype=A
-0 host1.auth-zone.example.net. IN AAAA 3600 2001:db8::1:45ba
+0 host1.auth-zone.example.net. 3600 IN AAAA 2001:db8::1:45ba
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='host1.auth-zone.example.net.', qtype=AAAA
-0 host1.another-auth-zone.example.net. IN A 3600 127.0.0.56
-0 host2.auth-zone.example.net. IN CNAME 3600 host1.another-auth-zone.example.net.
+0 host1.another-auth-zone.example.net. 3600 IN A 127.0.0.56
+0 host2.auth-zone.example.net. 3600 IN CNAME host1.another-auth-zone.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='host2.auth-zone.example.net.', qtype=A
-0 host1.not-auth-zone.example.net. IN A 3600 127.0.0.57
-0 host3.auth-zone.example.net. IN CNAME 3600 host1.not-auth-zone.example.net.
+0 host1.not-auth-zone.example.net. 3600 IN A 127.0.0.57
+0 host3.auth-zone.example.net. 3600 IN CNAME host1.not-auth-zone.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='host3.auth-zone.example.net.', qtype=A
-0 you-are.wild.auth-zone.example.net. IN TXT 3600 "Hi there!"
+0 you-are.wild.auth-zone.example.net. 3600 IN TXT "Hi there!"
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='you-are.wild.auth-zone.example.net.', qtype=TXT
-1 auth-zone.example.net. IN SOA 3600 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+1 auth-zone.example.net. 3600 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='auth-zone.example.net.', qtype=TXT
#!/bin/bash
$SDIG $nameserver 5302 www.arthur.example.net a recurse
sleep 3
-$SDIG $nameserver 5302 www.arthur.example.net a recurse | sed 's/\(.*\tIN\tA\t\)\(11\)/\112/'
+$SDIG $nameserver 5302 www.arthur.example.net a recurse | sed 's/\(.*\t\)\(11\tIN\)/\112\tIN/'
Reply to question for qname='www.arthur.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 www.arthur.example.net. IN A 15 192.0.2.2
+0 www.arthur.example.net. 15 IN A 192.0.2.2
Reply to question for qname='www.arthur.example.net.', qtype=A
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
-0 www.arthur.example.net. IN A 12 192.0.2.2
+0 www.arthur.example.net. 12 IN A 192.0.2.2
#!/bin/sh
-cleandig www-a.prefect.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www-a.prefect.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 www-a.prefect.example.net. IN CNAME 3600 www-a-2.prefect.example.net.
-1 prefect.example.net. IN SOA 3600 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+0 www-a.prefect.example.net. 3600 IN CNAME www-a-2.prefect.example.net.
+1 prefect.example.net. 3600 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www-a.prefect.example.net.', qtype=A
#!/bin/sh
-cleandig www.trillian.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www.trillian.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 www.trillian.example.net. IN CNAME 3600 www3.arthur.example.net.
-0 www3.arthur.example.net. IN A 3600 192.0.2.6
+0 www.trillian.example.net. 3600 IN CNAME www3.arthur.example.net.
+0 www3.arthur.example.net. 3600 IN A 192.0.2.6
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www.trillian.example.net.', qtype=A
#!/bin/sh
-cleandig www-a.prefect.example.net cname | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www-a.prefect.example.net cname | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 www-a.prefect.example.net. IN CNAME 3600 www-a-2.prefect.example.net.
+0 www-a.prefect.example.net. 3600 IN CNAME www-a-2.prefect.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www-a.prefect.example.net.', qtype=CNAME
#!/bin/sh
-cleandig www-d.prefect.example.net cname | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www-d.prefect.example.net cname | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 www-d.prefect.example.net. IN CNAME 3600 www.arthur.example.net.
+0 www-d.prefect.example.net. 3600 IN CNAME www.arthur.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www-d.prefect.example.net.', qtype=CNAME
#!/bin/sh
. vars
rm -f configs/$PREFIX.17/drop-1
-cleandig a.www.1.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig a.www.1.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 8
touch configs/$PREFIX.17/drop-1
-cleandig b.www.1.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig b.www.1.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 5
-cleandig c.www.1.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig c.www.1.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 5
-cleandig d.www.1.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig d.www.1.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 5
-cleandig e.www.1.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig e.www.1.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 a.www.1.ghost.example.net. IN A 3600 192.0.2.7
+0 a.www.1.ghost.example.net. 3600 IN A 192.0.2.7
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='a.www.1.ghost.example.net.', qtype=A
-0 b.www.1.ghost.example.net. IN A 3600 192.0.2.7
+0 b.www.1.ghost.example.net. 3600 IN A 192.0.2.7
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='b.www.1.ghost.example.net.', qtype=A
-0 c.www.1.ghost.example.net. IN A 3600 192.0.2.7
+0 c.www.1.ghost.example.net. 3600 IN A 192.0.2.7
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='c.www.1.ghost.example.net.', qtype=A
-1 ghost.example.net. IN SOA 3600 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+1 ghost.example.net. 3600 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='d.www.1.ghost.example.net.', qtype=A
-1 ghost.example.net. IN SOA 3600 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+1 ghost.example.net. 3600 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='e.www.1.ghost.example.net.', qtype=A
#!/bin/sh
. vars
rm -f configs/$PREFIX.17/drop-2
-cleandig a.www.2.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig a.www.2.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 8
touch configs/$PREFIX.17/drop-2
-cleandig b.www.2.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig b.www.2.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 5
-cleandig c.www.2.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig c.www.2.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 5
-cleandig d.www.2.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig d.www.2.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 5
-cleandig e.www.2.ghost.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig e.www.2.ghost.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 a.www.2.ghost.example.net. IN A 3600 192.0.2.8
+0 a.www.2.ghost.example.net. 3600 IN A 192.0.2.8
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='a.www.2.ghost.example.net.', qtype=A
-0 b.www.2.ghost.example.net. IN A 3600 192.0.2.8
+0 b.www.2.ghost.example.net. 3600 IN A 192.0.2.8
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='b.www.2.ghost.example.net.', qtype=A
-0 c.www.2.ghost.example.net. IN A 3600 192.0.2.8
+0 c.www.2.ghost.example.net. 3600 IN A 192.0.2.8
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='c.www.2.ghost.example.net.', qtype=A
-1 ghost.example.net. IN SOA 3600 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+1 ghost.example.net. 3600 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='d.www.2.ghost.example.net.', qtype=A
-1 ghost.example.net. IN SOA 3600 ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
+1 ghost.example.net. 3600 IN SOA ns.example.net. hostmaster.example.net. 1 3600 1800 1209600 300
Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='e.www.2.ghost.example.net.', qtype=A
#!/bin/sh
. vars
-cleandig hijacker.example.net ns | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig www.hijackme.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig hijacker.example.net ns | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig www.hijackme.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
sleep 5
\ No newline at end of file
-0 hijacker.example.net. IN NS 3600 ns.hijackme.example.net.
+0 hijacker.example.net. 3600 IN NS ns.hijackme.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='hijacker.example.net.', qtype=NS
-0 www.hijackme.example.net. IN A 3600 192.0.2.20
+0 www.hijackme.example.net. 3600 IN A 192.0.2.20
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www.hijackme.example.net.', qtype=A
#!/bin/sh
-cleandig www.marvin.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www.marvin.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 android.marvin.example.net. IN A 3600 192.0.2.5
-0 www.marvin.example.net. IN CNAME 3600 android.marvin.example.net.
+0 android.marvin.example.net. 3600 IN A 192.0.2.5
+0 www.marvin.example.net. 3600 IN CNAME android.marvin.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www.marvin.example.net.', qtype=A
#!/bin/sh
-cleandig www.ford.example.net A | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www.ford.example.net A | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
#!/bin/sh
-cleandig www.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 www.example.net. IN A 3600 192.0.2.1
+0 www.example.net. 3600 IN A 192.0.2.1
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www.example.net.', qtype=A
#!/bin/sh
-cleandig www-d.prefect.example.net a | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig www-d.prefect.example.net a | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 www-d.prefect.example.net. IN CNAME 3600 www.arthur.example.net.
-0 www.arthur.example.net. IN A 3600 192.0.2.2
+0 www-d.prefect.example.net. 3600 IN CNAME www.arthur.example.net.
+0 www.arthur.example.net. 3600 IN A 192.0.2.2
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='www-d.prefect.example.net.', qtype=A
#!/bin/sh
-cleandig srv.arthur.example.net srv | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig rp.arthur.example.net rp | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
-cleandig type1234.arthur.example.net TYPE1234 | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig srv.arthur.example.net srv | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig rp.arthur.example.net rp | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
+cleandig type1234.arthur.example.net TYPE1234 | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 srv.arthur.example.net. IN SRV 3600 0 100 389 server2.example.net.
+0 srv.arthur.example.net. 3600 IN SRV 0 100 389 server2.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='srv.arthur.example.net.', qtype=SRV
-0 rp.arthur.example.net. IN RP 3600 ahu.ds9a.nl. counter.arthur.example.net.
+0 rp.arthur.example.net. 3600 IN RP ahu.ds9a.nl. counter.arthur.example.net.
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='rp.arthur.example.net.', qtype=RP
-0 type1234.arthur.example.net. IN TYPE1234 3600 \# 2 4142
+0 type1234.arthur.example.net. 3600 IN TYPE1234 \# 2 4142
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='type1234.arthur.example.net.', qtype=TYPE1234
#!/bin/sh
-cleandig big.arthur.example.net txt | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig big.arthur.example.net txt | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
#!/bin/sh
-cleandig weirdtxt.example.net txt | sed 's/\(.*\tIN\t[A-Z0-9]\+\t\)\([0-9]\+\)/\13600/'
+cleandig weirdtxt.example.net txt | sed 's/\(.*\t\)\([0-9]\+\tIN\)/\13600\tIN/'
-0 weirdtxt.example.net. IN TXT 3600 "x\014x"
+0 weirdtxt.example.net. 3600 IN TXT "x\014x"
Rcode: 0 (No Error), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0
Reply to question for qname='weirdtxt.example.net.', qtype=TXT
fi
if [ "$zone" = "tsig.com" ]; then
$PDNSUTIL --config-dir=. --config-name=bind import-tsig-key test $ALGORITHM $KEY
- $PDNSUTIL --config-dir=. --config-name=bind activate-tsig-key tsig.com test master
+ $PDNSUTIL --config-dir=. --config-name=bind activate-tsig-key tsig.com test primary
fi
done
port=$((port+100))
$RUNWRAPPER $PDNS2 --daemon=no --local-port=$port --socket-dir=./ \
- --no-shuffle --launch=bind --bind-config=./named-slave.conf --slave \
+ --no-shuffle --launch=bind --bind-config=./named-slave.conf --secondary \
--retrieval-threads=1 --config-name=bind-slave \
--dnsupdate=yes \
--cache-ttl=$cachettl --no-config --dname-processing --bind-dnssec-db=./dnssec-slave.sqlite3 \
echo "INSERT INTO domains (name, type, master) VALUES('$zone','SLAVE','127.0.0.1:$port');" | $ISQL -b
if [ "$zone" = "tsig.com" ]; then
../pdns/pdnssec --config-dir=. --config-name=godbc2 import-tsig-key test $ALGORITHM $KEY
- ../pdns/pdnssec --config-dir=. --config-name=godbc2 activate-tsig-key tsig.com test slave
+ ../pdns/pdnssec --config-dir=. --config-name=godbc2 activate-tsig-key tsig.com test secondary
fi
if [ "$zone" = "stest.com" ]; then
if [[ $skipreasons != *nolua* ]]; then
$RUNWRAPPER $PDNS2 --daemon=no --local-port=$port --config-dir=. \
--config-name=godbc2 --socket-dir=./ --no-shuffle \
- --slave --retrieval-threads=4 \
- --slave-cycle-interval=300 --dname-processing &
+ --secondary --retrieval-threads=4 \
+ --xfr-cycle-interval=300 --dname-processing &
echo 'waiting for zones to be slaved'
set +e
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-master-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-slaves-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-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-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
godbc-info-consumer-members-query=select id, name, options, master from domains where type='SLAVE' and catalog=?
godbc-search-records-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE name LIKE ? OR content LIKE ? LIMIT ?
godbc-set-domain-metadata-query=insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?
godbc-set-tsig-key-query=replace into tsigkeys (name,algorithm,secret) values(?,?,?)
-godbc-supermaster-query=select account from supermasters where ip=? and nameserver=?
+godbc-autoprimary-query=select account from supermasters where ip=? and nameserver=?
godbc-unpublish-domain-key-query=update cryptokeys set published=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?
godbc-update-account-query=update domains set account=? where name=?
godbc-update-kind-query=update domains set type=? where name=?
godbc-update-lastcheck-query=update domains set last_check=? where id=?
-godbc-update-master-query=update domains set master=? where name=?
+godbc-update-primary-query=update domains set master=? where name=?
godbc-update-ordername-and-auth-query=update records set ordername=?,auth=? where domain_id=? and name=? and disabled=0
godbc-update-ordername-and-auth-type-query=update records set ordername=?,auth=? where domain_id=? and name=? and type=? and disabled=0
godbc-update-serial-query=update domains set notified_serial=? where id=?
"$GPGSQL2DB"
if [ "$zone" = "tsig.com" ]; then
$PDNSUTIL --config-dir=. --config-name=gpgsql2 import-tsig-key test $ALGORITHM $KEY
- $PDNSUTIL --config-dir=. --config-name=gpgsql2 activate-tsig-key tsig.com test slave
+ $PDNSUTIL --config-dir=. --config-name=gpgsql2 activate-tsig-key tsig.com test secondary
fi
if [ "$zone" = "stest.com" ]; then
if [[ $skipreasons != *nolua* ]]; then
$RUNWRAPPER $PDNS2 --daemon=no --local-port=$port --config-dir=. \
--config-name=gpgsql2 --socket-dir=./ --no-shuffle \
- --slave --retrieval-threads=4 \
- --slave-cycle-interval=300 --dname-processing &
+ --secondary --retrieval-threads=4 \
+ --xfr-cycle-interval=300 --dname-processing &
echo 'waiting for zones to be slaved'
loopcount=0
fi
if [ "$zone" = "tsig.com" ]; then
$PDNSUTIL --config-dir=. --config-name=$backend import-tsig-key test $ALGORITHM $KEY
- $PDNSUTIL --config-dir=. --config-name=$backend activate-tsig-key tsig.com test master
+ $PDNSUTIL --config-dir=. --config-name=$backend activate-tsig-key tsig.com test primary
fi
done
sqlite3 pdns.sqlite32 "INSERT INTO domains (name, type, master) VALUES('$zone','SLAVE','127.0.0.1:$port');"
if [ "$zone" = "tsig.com" ]; then
$PDNSUTIL --config-dir=. --config-name=gsqlite32 import-tsig-key test $ALGORITHM $KEY
- $PDNSUTIL --config-dir=. --config-name=gsqlite32 activate-tsig-key tsig.com test slave
+ $PDNSUTIL --config-dir=. --config-name=gsqlite32 activate-tsig-key tsig.com test secondary
fi
if [ "$zone" = "stest.com" ]; then
if [[ $skipreasons != *nolua* ]]; then
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 master
+ $PDNSUTIL --config-dir=. --config-name=lmdb activate-tsig-key tsig.com test primary
fi
done
@task
def apt_fresh(c):
- c.sudo('sed -i \'s/azure\.//\' /etc/apt/sources.list')
c.sudo('apt-get update')
c.sudo('apt-get -y --allow-downgrades dist-upgrade')
c.run('git clone https://git.code.sf.net/p/ed448goldilocks/code /tmp/libdecaf')
with c.cd('/tmp/libdecaf'):
c.run('git checkout 41f349')
- c.run(f'CC=clang-{clang_version} CXX=clang-{clang_version} '
+ c.run(f'CC={get_c_compiler()} CXX={get_cxx_compiler()} '
'cmake -B build '
'-DCMAKE_INSTALL_PREFIX=/usr/local '
'-DCMAKE_INSTALL_LIBDIR=lib '
@task
def install_auth_build_deps(c):
c.sudo('apt-get install -y --no-install-recommends ' + ' '.join(all_build_deps + git_build_deps + auth_build_deps))
- install_libdecaf(c, 'pdns-auth')
+ if os.getenv('DECAF_SUPPORT', 'no') == 'yes':
+ install_libdecaf(c, 'pdns-auth')
def is_coverage_enabled():
sanitizers = os.getenv('SANITIZERS')
return False
return os.getenv('COVERAGE') == 'yes'
+def get_coverage():
+ return '--enable-coverage=clang' if is_coverage_enabled() else ''
+
@task
def install_coverage_deps(c):
if is_coverage_enabled():
# FIXME we may want to start a background recursor here to make ALIAS tests more robust
setup_authbind(c)
- # Copy libdecaf out
- c.sudo('mkdir -p /usr/local/lib')
- c.sudo('cp /opt/pdns-auth/libdecaf/libdecaf.so* /usr/local/lib/.')
+ if os.getenv('DECAF_SUPPORT', 'no') == 'yes':
+ # Copy libdecaf out
+ c.sudo('mkdir -p /usr/local/lib')
+ c.sudo('cp /opt/pdns-auth/libdecaf/libdecaf.so* /usr/local/lib/.')
@task
def install_rec_bulk_deps(c): # FIXME: rename this, we do way more than apt-get
def get_sanitizers():
- sanitizers = os.getenv('SANITIZERS')
+ sanitizers = os.getenv('SANITIZERS', '')
if sanitizers != '':
sanitizers = sanitizers.split('+')
sanitizers = ['--enable-' + sanitizer for sanitizer in sanitizers]
sanitizers = ' '.join(sanitizers)
return sanitizers
+def get_unit_tests(auth=False):
+ if os.getenv('UNIT_TESTS') != 'yes':
+ return ''
+ return '--enable-unit-tests --enable-backend-unit-tests' if auth else '--enable-unit-tests'
+
+def get_build_concurrency(default=8):
+ return os.getenv('CONCURRENCY', default)
+
+def get_fuzzing_targets():
+ return '--enable-fuzz-targets' if os.getenv('FUZZING_TARGETS') == 'yes' else ''
+
+def is_compiler_clang():
+ compiler = os.getenv('COMPILER', 'clang')
+ return compiler == 'clang'
+
+def get_c_compiler():
+ return f'clang-{clang_version}' if is_compiler_clang() else 'gcc'
+
+def get_cxx_compiler():
+ return f'clang++-{clang_version}' if is_compiler_clang() else 'g++'
+
+def get_optimizations():
+ optimizations = os.getenv('OPTIMIZATIONS', 'yes')
+ return '-O1' if optimizations == 'yes' else '-O0'
def get_cflags():
return " ".join([
- "-O1",
+ get_optimizations(),
"-Werror=vla",
"-Werror=shadow",
"-Wformat=2",
"-Werror=format-security",
- "-Werror=string-plus-int",
+ "-Werror=string-plus-int" if is_compiler_clang() else '',
])
])
-def get_base_configure_cmd():
+def get_base_configure_cmd(additional_c_flags='', additional_cxx_flags='', enable_systemd=True, enable_sodium=True):
+ cflags = " ".join([get_cflags(), additional_c_flags])
+ cxxflags = " ".join([get_cxxflags(), additional_cxx_flags])
return " ".join([
- f'CFLAGS="{get_cflags()}"',
- f'CXXFLAGS="{get_cxxflags()}"',
+ f'CFLAGS="{cflags}"',
+ f'CXXFLAGS="{cxxflags}"',
'./configure',
- f"CC='clang-{clang_version}'",
- f"CXX='clang++-{clang_version}'",
+ f"CC='{get_c_compiler()}'",
+ f"CXX='{get_cxx_compiler()}'",
"--enable-option-checking=fatal",
- "--enable-systemd",
- "--with-libsodium",
+ "--enable-systemd" if enable_systemd else '',
+ "--with-libsodium" if enable_sodium else '',
"--enable-fortify-source=auto",
"--enable-auto-var-init=pattern",
+ get_coverage(),
+ get_sanitizers()
])
@task
def ci_auth_configure(c):
- sanitizers = get_sanitizers()
-
- unittests = os.getenv('UNIT_TESTS')
- if unittests == 'yes':
- unittests = '--enable-unit-tests --enable-backend-unit-tests'
- else:
- unittests = ''
-
- fuzz_targets = os.getenv('FUZZING_TARGETS')
- fuzz_targets = '--enable-fuzz-targets' if fuzz_targets == 'yes' else ''
- coverage = '--enable-coverage=clang' if is_coverage_enabled() else ''
-
+ unittests = get_unit_tests(True)
+ fuzz_targets = get_fuzzing_targets()
modules = " ".join([
"bind",
"geoip",
"LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
f"--with-modules='{modules}'",
"--enable-tools",
+ "--enable-dns-over-tls",
"--enable-experimental-pkcs11",
"--enable-experimental-gss-tsig",
"--enable-remotebackend-zeromq",
"--with-lmdb=/usr",
- "--with-libdecaf",
+ "--with-libdecaf" if os.getenv('DECAF_SUPPORT', 'no') == 'yes' else '',
"--prefix=/opt/pdns-auth",
"--enable-ixfrdist",
- sanitizers,
unittests,
- fuzz_targets,
- coverage,
+ fuzz_targets
])
res = c.run(configure_cmd, warn=True)
if res.exited != 0:
@task
def ci_rec_configure(c):
- sanitizers = get_sanitizers()
-
- unittests = os.getenv('UNIT_TESTS')
- unittests = '--enable-unit-tests' if unittests == 'yes' else ''
- coverage = '--enable-coverage=clang' if is_coverage_enabled() else ''
+ unittests = get_unit_tests()
configure_cmd = " ".join([
get_base_configure_cmd(),
"--with-libcap",
"--with-net-snmp",
"--enable-dns-over-tls",
- sanitizers,
unittests,
- coverage,
])
res = c.run(configure_cmd, warn=True)
if res.exited != 0:
--with-libcap \
--with-net-snmp \
--with-nghttp2 \
- --with-re2 '
+ --with-re2'
else:
features_set = '--disable-dnstap \
--disable-dnscrypt \
--without-lmdb \
--without-net-snmp \
--without-nghttp2 \
- --without-re2 '
+ --without-re2'
additional_flags = '-DDISABLE_COMPLETION \
-DDISABLE_DELAY_PIPE \
-DDISABLE_DYNBLOCKS \
-DDISABLE_HASHED_CREDENTIALS \
-DDISABLE_FALSE_SHARING_PADDING \
-DDISABLE_NPN'
- unittests = ' --enable-unit-tests' if os.getenv('UNIT_TESTS') == 'yes' else ''
- fuzztargets = '--enable-fuzz-targets' if os.getenv('FUZZING_TARGETS') == 'yes' else ''
- sanitizers = ' '.join('--enable-'+x for x in os.getenv('SANITIZERS').split('+')) if os.getenv('SANITIZERS') != '' else ''
- coverage = '--enable-coverage=clang' if is_coverage_enabled() else ''
- cflags = get_cflags()
- cxxflags = " ".join([get_cxxflags(), additional_flags])
- res = c.run(f'''CFLAGS="%s" \
- CXXFLAGS="%s" \
- AR=llvm-ar-{clang_version} \
- RANLIB=llvm-ranlib-{clang_version} \
- ./configure \
- CC='clang-{clang_version}' \
- CXX='clang++-{clang_version}' \
- --enable-option-checking=fatal \
- --enable-fortify-source=auto \
- --enable-auto-var-init=pattern \
- --enable-lto=thin \
- --prefix=/opt/dnsdist %s %s %s %s %s''' % (cflags, cxxflags, features_set, sanitizers, unittests, fuzztargets, coverage), warn=True)
+ unittests = get_unit_tests()
+ fuzztargets = get_fuzzing_targets()
+ tools = f'''AR=llvm-ar-{clang_version} RANLIB=llvm-ranlib-{clang_version}''' if is_compiler_clang() else ''
+ configure_cmd = " ".join([
+ tools,
+ get_base_configure_cmd(additional_c_flags='', additional_cxx_flags=additional_flags, enable_systemd=False, enable_sodium=False),
+ features_set,
+ unittests,
+ fuzztargets,
+ ' --enable-lto=thin',
+ '--prefix=/opt/dnsdist'
+ ])
+
+ res = c.run(configure_cmd, warn=True)
if res.exited != 0:
c.run('cat config.log')
raise UnexpectedExit(res)
@task
def ci_auth_make(c):
- c.run('make -j8 -k V=1')
+ c.run(f'make -j{get_build_concurrency()} -k V=1')
@task
def ci_auth_make_bear(c):
- # Needed for clang-tidy -line-filter vs project structure shenanigans
- with c.cd('pdns'):
- c.run('bear --append -- make -j8 -k V=1 -C ..')
+ c.run(f'bear --append -- make -j{get_build_concurrency()} -k V=1')
@task
def ci_rec_make(c):
- c.run('make -j8 -k V=1')
+ c.run(f'make -j{get_build_concurrency()} -k V=1')
@task
def ci_rec_make_bear(c):
# Assumed to be running under ./pdns/recursordist/
- c.run('bear --append -- make -j8 -k V=1')
+ c.run(f'bear --append -- make -j{get_build_concurrency()} -k V=1')
@task
def ci_dnsdist_make(c):
- c.run('make -j4 -k V=1')
+ c.run(f'make -j{get_build_concurrency(4)} -k V=1')
@task
def ci_dnsdist_make_bear(c):
# Assumed to be running under ./pdns/dnsdistdist/
- c.run('bear --append -- make -j4 -k V=1')
+ c.run(f'bear --append -- make -j{get_build_concurrency(4)} -k V=1')
@task
def ci_auth_install_remotebackend_test_deps(c):