diff --git a/.ci-operator.yaml b/.ci-operator.yaml deleted file mode 100644 index 1d88a59fdf..0000000000 --- a/.ci-operator.yaml +++ /dev/null @@ -1,4 +0,0 @@ -build_root_image: - name: release - namespace: openshift - tag: rhel-9-release-golang-1.26-openshift-5.0 diff --git a/.circleci/config.yml b/.circleci/config.yml index 117ac3f412..8e098fbbd6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,8 +21,8 @@ integrationDefaults: &integrationDefaults image: default working_directory: ~/go/src/${CIRCLE_PROJECT_USERNAME}/coredns environment: - - K8S_VERSION: v1.29.4 - - KIND_VERSION: v0.25.0 + - K8S_VERSION: v1.34.0 + - KIND_VERSION: v0.30.0 - KUBECONFIG: /home/circleci/.kube/kind-config-kind setupKubernetes: &setupKubernetes diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index 167f5636c6..0000000000 --- a/.codecov.yml +++ /dev/null @@ -1,8 +0,0 @@ -coverage: - status: - project: - default: - target: 50% - threshold: null - patch: false - changes: false diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..1ff16c577e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +* +!coredns diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index c9397fc8ae..5b487e773b 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -25,7 +25,7 @@ jobs: fuzz-seconds: 600 dry-run: false - name: Upload Crash - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 40fb9d991c..8377012c77 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,15 +27,17 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 + uses: github/codeql-action/autobuild@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 diff --git a/.github/workflows/depsreview.yml b/.github/workflows/depsreview.yml index 0fde6f5acd..e71bd2454a 100644 --- a/.github/workflows/depsreview.yml +++ b/.github/workflows/depsreview.yml @@ -9,6 +9,8 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: 'Dependency Review' - uses: actions/dependency-review-action@56339e523c0409420f6c2c9a2f4292bbb3c07dd3 + uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0c1089b9ff..1597cdbca3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -16,19 +16,22 @@ jobs: docker-release: runs-on: ubuntu-latest env: - DOCKER_LOGIN: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} RELEASE: ${{ github.event.inputs.release || github.event.release.tag_name }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Build Docker Images run: make VERSION=${RELEASE:1} DOCKER=coredns -f Makefile.docker release - name: Show Docker Images run: docker images - name: Docker login - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PASSWORD }} - name: Publish Docker Images run: make VERSION=${RELEASE:1} DOCKER=coredns -f Makefile.docker docker-push + env: + DOCKER_LOGIN: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} diff --git a/.github/workflows/go.coverage.yml b/.github/workflows/go.coverage.yml deleted file mode 100644 index 3ca781feb1..0000000000 --- a/.github/workflows/go.coverage.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Go Coverage -on: [pull_request] -permissions: - contents: read - -jobs: - test: - name: Coverage - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Setup Go Version - run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV - - - name: Install Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 - with: - go-version: ${{ env.GO_VERSION }} - id: go - - - name: Build - run: go build -v ./... - - - name: Test With Coverage - run: | - go install github.com/fatih/faillint@c56e3ec6dbfc933bbeb884fd31f2bcd41f712657 # v1.15.0 - for d in request core coremain plugin test; do \ - ( cd $d; go test -coverprofile=cover.out -covermode=atomic -race ./...; [ -f cover.out ] && cat cover.out >> ../coverage.txt ); \ - done - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 diff --git a/.github/workflows/go.test.yml b/.github/workflows/go.test.yml index 77023ebae6..6c92813df1 100644 --- a/.github/workflows/go.test.yml +++ b/.github/workflows/go.test.yml @@ -1,5 +1,9 @@ name: Go Tests -on: [push, pull_request] +on: + push: + branches: + - master + pull_request: permissions: contents: read @@ -9,21 +13,45 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Install Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: .go-version + id: go + + - name: Build + run: go build -v ./... + + - name: Test + run: | + ( cd request; go test -race ./... ) + ( cd core; go test -race ./... ) + ( cd coremain; go test -race ./... ) - - name: Setup Go Version - run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV + test-windows: + name: Test Windows + runs-on: windows-latest + steps: + - name: Check out code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Install Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version id: go - name: Build run: go build -v ./... - name: Test + shell: bash run: | ( cd request; go test -race ./... ) ( cd core; go test -race ./... ) @@ -34,15 +62,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Setup Go Version - run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Install Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version id: go - name: Build @@ -56,15 +83,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Setup Go Version - run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Install Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version id: go - name: Build @@ -80,7 +106,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Install dependencies run: sudo apt-get install make curl diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 5186cc2b7f..7eaed130e0 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -11,15 +11,13 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: Setup Go Version - run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV - - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - go-version: ${{ env.GO_VERSION }} + persist-credentials: false + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: .go-version - name: golangci-lint - uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 + uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee # v9.2.1 with: - version: v2.4.0 - - name: modernize - run: go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@2e31135b736b96cd609904370c71563ce5447826 -diff -test ./... # v0.20.0 + version: v2.11.4 diff --git a/.github/workflows/make.doc.yml b/.github/workflows/make.doc.yml index b9ea1eda5b..dc359db7ed 100644 --- a/.github/workflows/make.doc.yml +++ b/.github/workflows/make.doc.yml @@ -12,35 +12,28 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + pull-requests: write steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Setup Go Version - run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: .go-version - name: Update Docs run: | bash -x -e ./.github/fixup_file_mtime.sh make -f Makefile.doc - - name: Set up Git - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git config user.name "coredns[bot]" - git config user.email "bot@bot.coredns.io" - git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git - - - name: Commit and push changes - run: | - git add . - if output=$(git status --porcelain) && [ ! -z "$output" ]; then - git commit -s -m 'auto make -f Makefile.doc' - git push - fi + - name: Create Pull Request + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 + with: + commit-message: 'auto make -f Makefile.doc' + title: 'Update generated documentation' + body: 'Automated doc generation via `make -f Makefile.doc`' + branch: bot/make-doc + committer: 'coredns[bot] ' + author: 'coredns[bot] ' + signoff: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5af5fa91a4..ee19eddd2d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,14 +18,17 @@ jobs: contents: write steps: - name: Check out code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.event.inputs.commit }} + persist-credentials: false - name: Set up info + env: + INPUT_COMMIT: ${{ github.event.inputs.commit }} run: | set -x -e VERSION=$(make -f Makefile.release version) - COMMIT=$(git rev-parse --quiet --verify ${{ github.event.inputs.commit }}) + COMMIT=$(git rev-parse --quiet --verify "${INPUT_COMMIT}") if [[ "$(git tag -l v${VERSION})" == "v${VERSION}" ]]; then echo "v${VERSION} already released" exit 1 @@ -36,19 +39,24 @@ jobs: - name: Build release binary run: make -f Makefile.release release - name: Build release binary sha256 - run: (cd release; for asset in `ls -A *tgz`; do sha256sum $asset > $asset.sha256; done) + run: (cd release; for asset in `ls -A *.tgz *.zip`; do sha256sum $asset > $asset.sha256; done) - name: Remove hidden section - run: sed '/+++/,//d' notes/coredns-${{ steps.info.outputs.version}}.md > release.md + env: + VERSION: ${{ steps.info.outputs.version }} + run: sed '/+++/,//d' "notes/coredns-${VERSION}.md" > release.md - name: Log release info + env: + COMMIT: ${{ steps.info.outputs.commit }} + VERSION: ${{ steps.info.outputs.version }} run: | set -x -e git log -1 - echo ${{ steps.info.outputs.commit }} - echo ${{ steps.info.outputs.version }} + echo "${COMMIT}" + echo "${VERSION}" cat release.md - sha256sum release/*.tgz + sha256sum release/*.tgz release/*.zip - name: Draft release - uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 with: body_path: release.md name: v${{ steps.info.outputs.version }} @@ -57,4 +65,6 @@ jobs: files: | release/*.tgz release/*.tgz.sha256 + release/*.zip + release/*.zip.sha256 draft: true diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index ad933ddc67..05e4f1c79a 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -23,7 +23,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -43,7 +43,7 @@ jobs: # Upload the results as artifacts (optional). - name: "Upload artifact" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: SARIF file path: results.sarif @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 + uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: sarif_file: results.sarif diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index aba566ba76..146ca4d828 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,7 +13,7 @@ jobs: pull-requests: write # for actions/stale to close stale PRs runs-on: ubuntu-latest steps: - - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0 + - uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0 with: stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days' stale-pr-message: 'This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days' diff --git a/.github/workflows/trivy-scan.yaml b/.github/workflows/trivy-scan.yaml deleted file mode 100644 index 8cf1c6e406..0000000000 --- a/.github/workflows/trivy-scan.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: Trivy Nightly Scan -on: - schedule: - - cron: '0 2 * * 5' # Run at 2AM UTC on every Friday - -permissions: read-all -jobs: - nightly-scan: - name: Trivy Scan nightly - strategy: - fail-fast: false - matrix: - # It will test for only the latest version as older version is not maintained - versions: [latest] - permissions: - security-events: write # for github/codeql-action/upload-sarif to upload SARIF results - - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # master - with: - image-ref: 'docker.io/coredns/coredns:${{ matrix.versions }}' - severity: 'CRITICAL,HIGH' - format: 'sarif' - output: 'trivy-results.sarif' - - - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 - with: - sarif_file: 'trivy-results.sarif' diff --git a/.github/workflows/verify-make-gen.yml b/.github/workflows/verify-make-gen.yml new file mode 100644 index 0000000000..0a2fee556f --- /dev/null +++ b/.github/workflows/verify-make-gen.yml @@ -0,0 +1,38 @@ +name: Verify Generated Files +on: + push: + branches: + - master + pull_request: +permissions: + contents: read + +jobs: + verify-generate: + name: Verify make gen + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: .go-version + - name: Run make gen + run: make gen + - name: Check for uncommitted changes + run: | + UNTRACKED=$(git ls-files --others --exclude-standard) + if [ -n "$UNTRACKED" ]; then + echo "ERROR: make gen produced untracked files:" + echo "$UNTRACKED" + echo "" + echo "Run 'make gen' and commit the result." + exit 1 + fi + if ! git diff --exit-code; then + echo "" + echo "ERROR: Generated files are out of date." + echo "Run 'make gen' and commit the result." + exit 1 + fi diff --git a/.github/workflows/yamllint.yml b/.github/workflows/yamllint.yml index 7f05d86ee3..0eb8bd9391 100644 --- a/.github/workflows/yamllint.yml +++ b/.github/workflows/yamllint.yml @@ -8,12 +8,12 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout' - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: 'Yamllint' - uses: karancode/yamllint-github-action@4052d365f09b8d34eb552c363d1141fd60e2aeb2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - yamllint_file_or_dir: '.' - yamllint_strict: false - yamllint_comment: true - env: - GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false + - name: 'Setup uv' + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + - name: 'Yamllint' + run: | + uvx --from 'yamllint==1.38.0' yamllint . + echo "yamllint passed" diff --git a/.gitignore b/.gitignore index be6fd2f04b..1778df6591 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ -query.log -Corefile -*.swp -/coredns +# only add build artifacts concerning coredns - no editor related files +coredns coredns.exe Corefile -/build/ +build/ release/ diff --git a/.golangci.yml b/.golangci.yml index 26b005c169..29eec3fe09 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -10,9 +10,12 @@ linters: - canonicalheader - copyloopvar - durationcheck + - godoclint + - gosec - govet - ineffassign - intrange + - modernize - nakedret - nolintlint - perfsprint @@ -20,6 +23,7 @@ linters: - protogetter - staticcheck - thelper + - revive - unconvert - unused - usetesting @@ -37,6 +41,7 @@ linters: - path: _test\.go linters: - perfsprint + - gosec settings: govet: enable: diff --git a/Dockerfile b/Dockerfile index 5202e8b7b4..140a30340e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,14 @@ ARG DEBIAN_IMAGE=debian:stable-slim ARG BASE=gcr.io/distroless/static-debian12:nonroot -FROM --platform=$BUILDPLATFORM ${DEBIAN_IMAGE} AS build -SHELL [ "/bin/sh", "-ec" ] -RUN export DEBCONF_NONINTERACTIVE_SEEN=true \ - DEBIAN_FRONTEND=noninteractive \ - DEBIAN_PRIORITY=critical \ - TERM=linux ; \ - apt-get -qq update ; \ - apt-get -qq upgrade ; \ - apt-get -qq --no-install-recommends install ca-certificates libcap2-bin; \ - apt-get clean +FROM --platform=$BUILDPLATFORM ${DEBIAN_IMAGE} AS build +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get -qq update \ + && apt-get -qq --no-install-recommends install libcap2-bin COPY coredns /coredns RUN setcap cap_net_bind_service=+ep /coredns -FROM --platform=$TARGETPLATFORM ${BASE} -COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +FROM ${BASE} COPY --from=build /coredns /coredns USER nonroot:nonroot # Reset the working directory inherited from the base image back to the expected default: diff --git a/Dockerfile.ocp b/Dockerfile.ocp deleted file mode 100644 index d7ceeed0f7..0000000000 --- a/Dockerfile.ocp +++ /dev/null @@ -1,13 +0,0 @@ -FROM registry.ci.openshift.org/ocp/builder:rhel-9-golang-1.26-openshift-5.0 AS builder -WORKDIR /go/src/github.com/coredns/coredns -COPY . . -RUN GO111MODULE=on GOFLAGS=-mod=vendor go build -o coredns . - -FROM registry.ci.openshift.org/ocp/5.0:base-rhel9 -COPY --from=builder /go/src/github.com/coredns/coredns/coredns /usr/bin/ - -ENTRYPOINT ["/usr/bin/coredns"] - -LABEL io.k8s.display-name="CoreDNS" \ - io.k8s.description="CoreDNS delivers the DNS and Discovery Service for a Kubernetes cluster." \ - maintainer="dev@lists.openshift.redhat.com" diff --git a/Dockerfile.openshift b/Dockerfile.openshift deleted file mode 100644 index d4f5ab3c3d..0000000000 --- a/Dockerfile.openshift +++ /dev/null @@ -1,13 +0,0 @@ -FROM registry.svc.ci.openshift.org/openshift/release:golang-1.12 AS builder -WORKDIR /go/src/github.com/coredns/coredns -COPY . . -RUN GO111MODULE=on GOFLAGS=-mod=vendor go build -o coredns . - -FROM registry.svc.ci.openshift.org/openshift/origin-v4.0:base -COPY --from=builder /go/src/github.com/coredns/coredns/coredns /usr/bin/ - -ENTRYPOINT ["/usr/bin/coredns"] - -LABEL io.k8s.display-name="CoreDNS" \ - io.k8s.description="CoreDNS delivers the DNS and Discovery Service for a Kubernetes cluster." \ - maintainer="dev@lists.openshift.redhat.com" diff --git a/Makefile b/Makefile index e3d1418c93..3e30b74f50 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,13 @@ BINARY:=coredns SYSTEM:= CHECKS:=check BUILDOPTS?=-v +GOTAGS?=grpcnotrace GOPATH?=$(HOME)/go MAKEPWD:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) CGO_ENABLED?=0 GOLANG_VERSION ?= $(shell cat .go-version) +STRIP_FLAGS?=-s -w +LDFLAGS?=-ldflags="$(STRIP_FLAGS) -X github.com/coredns/coredns/coremain.GitCommit=$(GITCOMMIT)" export GOSUMDB = sum.golang.org export GOTOOLCHAIN = local @@ -17,7 +20,7 @@ all: coredns .PHONY: coredns coredns: $(CHECKS) - CGO_ENABLED=$(CGO_ENABLED) $(SYSTEM) go build $(BUILDOPTS) -ldflags="-s -w -X github.com/coredns/coredns/coremain.GitCommit=$(GITCOMMIT)" -o $(BINARY) + CGO_ENABLED=$(CGO_ENABLED) $(SYSTEM) go build $(BUILDOPTS) -tags="$(GOTAGS)" $(LDFLAGS) -o $(BINARY) .PHONY: check check: core/plugin/zplugin.go core/dnsserver/zdirectives.go @@ -40,13 +43,6 @@ clean: go clean rm -f coredns -.PHONY: dep-ensure -dep-ensure: - dep version || go get -u github.com/golang/dep/cmd/dep - dep ensure -v - dep prune -v - find vendor -name '*_test.go' -delete - .PHONY: test test: check GOFLAGS=-mod=vendor go test -count=1 ./... diff --git a/Makefile.doc b/Makefile.doc index 2adc143a34..8f5748d39e 100644 --- a/Makefile.doc +++ b/Makefile.doc @@ -3,7 +3,7 @@ # updated before doing a release. The Debian package, for instance, looks at these pages # and will install them on your system. -MMARK_VERSION:=2.2.4 +MMARK_VERSION:=2.2.47 PLUGINS:=$(wildcard plugin/*/README.md) READMES:=$(subst plugin/,,$(PLUGINS)) READMES:=$(subst /README.md,,$(READMES)) @@ -23,26 +23,39 @@ MMARK := $(FIRST_GOPATH)/bin/mmark -man MMARK_URL := https://github.com/mmarkdown/mmark/releases/download/v$(MMARK_VERSION)/mmark_$(MMARK_VERSION)_$(GO_BUILD_PLATFORM).tgz +# SHA-256 checksums for mmark v2.2.47 release tarballs. +# See: https://github.com/mmarkdown/mmark/releases/tag/v2.2.47 +MMARK_SHA256_darwin_amd64 := 941e963489e328c9da188629688438f9f3e93b6a4895c6ef943d55fbbfa84a3c +MMARK_SHA256_darwin_arm64 := 641cbc566edec29dd989ac15432b7f007be54ebc163cf6d98cd1d3df295ef9c4 +MMARK_SHA256_linux_amd64 := e0585cc9628c562e0f1be36e45221e84c6fc84957c999168ce4ba35594264ff2 +MMARK_SHA256_linux_arm := f6e1059c032b9ec0a74da40d8e901968d0bb41d92a160ef4782febbbf298d22d +MMARK_SHA256_linux_arm64 := 9a3c9b2e525b5addf97f968ec28829947520f628fdf4850134be784e220149ca +MMARK_SHA256_windows_amd64 := 9c73231e4427651d1f7911d4a9014aa2d87e735aac9c93e4e400061bc1de6714 +MMARK_SHA256 := $(MMARK_SHA256_$(GO_BUILD_PLATFORM)) + .PHONY: mmark mmark: $(MMARK_BIN) $(MMARK_BIN): $(eval MMARK_TMP := $(shell mktemp -d)) - curl -s -L $(MMARK_URL) | tar -xvzf - -C $(MMARK_TMP) + curl -s -L -o $(MMARK_TMP)/mmark.tgz $(MMARK_URL) + @if [ -z "$(MMARK_SHA256)" ]; then \ + echo "error: no known checksum for platform $(GO_BUILD_PLATFORM)" >&2; exit 1; \ + fi + @echo "$(MMARK_SHA256) $(MMARK_TMP)/mmark.tgz" | shasum -a 256 -c - + tar -xzf $(MMARK_TMP)/mmark.tgz -C $(MMARK_TMP) mkdir -p $(FIRST_GOPATH)/bin cp $(MMARK_TMP)/mmark $(FIRST_GOPATH)/bin/mmark rm -r $(MMARK_TMP) man/coredns.1: coredns.1.md - @/bin/echo -e '%%%\n title = "coredns 1"\n' \ - 'area = "CoreDNS"\n workgroup = "CoreDNS"\n%%%\n\n' > $@.header + @printf '%%%%%%\n title = "coredns 1"\n area = "CoreDNS"\n workgroup = "CoreDNS"\n%%%%%%\n\n' > $@.header @cat $@.header $< > $@.md && rm $@.header - @sed -i -e "s/@@PLUGINS@@/$(PLUGINS)/" $@.md + @sed -e "s/@@PLUGINS@@/$(PLUGINS)/" $@.md > $@.md.tmp && mv $@.md.tmp $@.md $(MMARK) $@.md > $@ && rm $@.md man/corefile.5: corefile.5.md - @/bin/echo -e '%%%\n title = "corefile 5"\n' \ - 'area = "CoreDNS"\n workgroup = "CoreDNS"\n%%%\n\n' > $@.header + @printf '%%%%%%\n title = "corefile 5"\n area = "CoreDNS"\n workgroup = "CoreDNS"\n%%%%%%\n\n' > $@.header @cat $@.header $< > $@.md && rm $@.header $(MMARK) $@.md > $@ && rm $@.md @@ -53,10 +66,9 @@ plugins: done man/coredns-%.7: plugin/%/README.md - @/bin/echo -e "%%%\n title = \"`basename $@ | sed s\/\.7\/\/` 7\"\n" \ - 'area = "CoreDNS"\n workgroup = "CoreDNS Plugins"\n%%%\n\n' > $@.header + @printf '%%%%%%\n title = "%s 7"\n area = "CoreDNS"\n workgroup = "CoreDNS Plugins"\n%%%%%%\n\n' "`basename $@ | sed s/\.7//`" > $@.header @cat $@.header $< > $@.md && rm $@.header - @sed -i '/^# .*/d' $@.md + @sed -e '/^# .*/d' $@.md > $@.md.tmp && mv $@.md.tmp $@.md $(MMARK) $@.md > $@ && rm $@.md PHONY: clean diff --git a/Makefile.docker b/Makefile.docker index eb7e8ae07b..3f33cf0019 100644 --- a/Makefile.docker +++ b/Makefile.docker @@ -32,7 +32,7 @@ DOCKER:= NAME:=coredns GITHUB:=https://github.com/coredns/coredns/releases/download # mips is not in LINUX_ARCH because it's not supported by docker manifest. Keep this list in sync with the one in Makefile.release -LINUX_ARCH:=amd64 arm arm64 mips64le ppc64le s390x riscv64 +LINUX_ARCH:=amd64 arm arm64 mips64le ppc64le s390x riscv64 loong64 DOCKER_IMAGE_NAME:=$(DOCKER)/$(NAME) DOCKER_IMAGE_LIST_VERSIONED:=$(shell echo $(LINUX_ARCH) | sed -e "s~mips64le ~~g" | sed -e "s~[^ ]*~$(DOCKER_IMAGE_NAME):&\-$(VERSION)~g") @@ -87,6 +87,9 @@ else if [ "$${arch}" = "riscv64" ]; then \ DOCKER_ARGS="--build-arg=DEBIAN_IMAGE=debian:unstable-slim --build-arg=BASE=ghcr.io/go-riscv/distroless/static-unstable:nonroot"; \ fi; \ + if [ "$${arch}" = "loong64" ]; then \ + DOCKER_ARGS="--build-arg=DEBIAN_IMAGE=ghcr.io/loong64/debian:trixie-slim --build-arg=BASE=ghcr.io/loong64/debian:trixie-slim"; \ + fi; \ DOCKER_BUILDKIT=1 docker build --platform=$${arch} -t $(DOCKER_IMAGE_NAME):$${arch}-$(VERSION) $${DOCKER_ARGS} build/docker/$${arch} ;\ done endif diff --git a/Makefile.release b/Makefile.release index bc4108fd50..8eb24b4208 100644 --- a/Makefile.release +++ b/Makefile.release @@ -51,7 +51,7 @@ endif NAME:=coredns VERSION:=$(shell grep 'CoreVersion' coremain/version.go | awk '{ print $$3 }' | tr -d '"') GITHUB:=coredns -LINUX_ARCH:=amd64 arm arm64 mips64le ppc64le s390x mips riscv64 +LINUX_ARCH:=amd64 arm arm64 mips64le ppc64le s390x mips riscv64 loong64 GOLANG_VERSION ?= $(shell cat .go-version) export GOSUMDB = sum.golang.org @@ -85,6 +85,7 @@ tar: tar -zcf release/$(NAME)_$(VERSION)_darwin_amd64.tgz -C build/darwin/amd64 $(NAME) tar -zcf release/$(NAME)_$(VERSION)_darwin_arm64.tgz -C build/darwin/arm64 $(NAME) tar -zcf release/$(NAME)_$(VERSION)_windows_amd64.tgz -C build/windows/amd64 $(NAME).exe + zip -j release/$(NAME)_$(VERSION)_windows_amd64.zip build/windows/amd64/$(NAME).exe for arch in $(LINUX_ARCH); do \ tar -zcf release/$(NAME)_$(VERSION)_linux_$$arch.tgz -C build/linux/$$arch $(NAME) ;\ done @@ -97,15 +98,15 @@ else @echo Releasing: $(VERSION) @$(eval RELEASE:=$(shell curl -s -d '{"tag_name": "v$(VERSION)", "name": "v$(VERSION)"}' -H "Authorization: token ${GITHUB_ACCESS_TOKEN}" "https://api.github.com/repos/$(GITHUB)/$(NAME)/releases" | grep -m 1 '"id"' | tr -cd '[[:digit:]]')) @echo ReleaseID: $(RELEASE) - @( cd release; for asset in `ls -A *tgz`; do \ + @( cd release; for asset in `ls -A *.tgz *.zip`; do \ echo $$asset; \ curl -o /dev/null -X POST \ - -H "Content-Type: application/gzip" \ + -H "Content-Type: application/octet-stream" \ -H "Authorization: token ${GITHUB_ACCESS_TOKEN}" \ --data-binary "@$$asset" \ "https://uploads.github.com/repos/$(GITHUB)/$(NAME)/releases/$(RELEASE)/assets?name=$${asset}" ; \ done ) - @( cd release; for asset in `ls -A *tgz`; do \ + @( cd release; for asset in `ls -A *.tgz *.zip`; do \ sha256sum $$asset > $$asset.sha256; \ done ) @( cd release; for asset in `ls -A *sha256`; do \ diff --git a/README.md b/README.md index 9d60143042..00f3819be7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ ![CodeQL](https://github.com/coredns/coredns/actions/workflows/codeql-analysis.yml/badge.svg) ![Go Tests](https://github.com/coredns/coredns/actions/workflows/go.test.yml/badge.svg) [![CircleCI](https://circleci.com/gh/coredns/coredns.svg?style=shield)](https://circleci.com/gh/coredns/coredns) -[![Code Coverage](https://img.shields.io/codecov/c/github/coredns/coredns/master.svg)](https://codecov.io/github/coredns/coredns?branch=master) [![Docker Pulls](https://img.shields.io/docker/pulls/coredns/coredns.svg)](https://hub.docker.com/r/coredns/coredns) [![Go Report Card](https://goreportcard.com/badge/github.com/coredns/coredns)](https://goreportcard.com/report/coredns/coredns) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1250/badge)](https://bestpractices.coreinfrastructure.org/projects/1250) @@ -23,6 +22,7 @@ CoreDNS can listen for DNS requests coming in over: * UDP/TCP (go'old DNS). * TLS - DoT ([RFC 7858](https://tools.ietf.org/html/rfc7858)). * DNS over HTTP/2 - DoH ([RFC 8484](https://tools.ietf.org/html/rfc8484)). +* DNS over HTTP/3 - DoH3 * DNS over QUIC - DoQ ([RFC 9250](https://tools.ietf.org/html/rfc9250)). * [gRPC](https://grpc.io) (not a standard). @@ -57,7 +57,7 @@ out-of-tree plugins. To compile CoreDNS, we assume you have a working Go setup. See various tutorials if you don’t have that already configured. -First, make sure your golang version is 1.24.0 or higher as `go mod` support and other api is needed. +First, make sure your golang version is 1.25.0 or higher as `go mod` support and other api is needed. See [here](https://github.com/golang/go/wiki/Modules) for `go mod` details. Then, check out the project and run `make` to compile the binary: @@ -79,11 +79,33 @@ setup a Go environment, you could build CoreDNS easily: ``` docker run --rm -i -t \ -v $PWD:/go/src/github.com/coredns/coredns -w /go/src/github.com/coredns/coredns \ - golang:1.24 sh -c 'GOFLAGS="-buildvcs=false" make gen && GOFLAGS="-buildvcs=false" make' + golang:1.25 sh -c 'GOFLAGS="-buildvcs=false" make gen && GOFLAGS="-buildvcs=false" make' ``` The above command alone will have `coredns` binary generated. +## Quick Start + +Create a minimal Corefile: + +```bash +cat > Corefile < /label add: plugin/$1 - - | - /approve -> /lgtm - - | - /wai -> /label add: works as intended - - | - /release: (.*) -> /exec: /opt/bin/release-coredns $1 -``` - -2. Run `git add OWNERS` (or `git checkout --theirs OWNERS` when resolving - conflicts). -3. Commit as part of `UPSTREAM: : openshift: restore automation metadata` - so the OWNERS/automation files travel together and reviewers have a single - place to look. - -Historical context: this file originated in commits like `a82419240` and was -last reviewed by @Miciah and @alebedev87. Keeping the instructions in Markdown -instead of raw patch form makes it easier to see what the carry reintroduces -without having to consult the archived rebase report. diff --git a/carry_consolidation/dependabot_policy.md b/carry_consolidation/dependabot_policy.md deleted file mode 100644 index 23cb40460f..0000000000 --- a/carry_consolidation/dependabot_policy.md +++ /dev/null @@ -1,5 +0,0 @@ -## Dependabot policy for downstream fork - -- Upstream CoreDNS keeps `.github/dependabot.yml`. Downstream OpenShift policy disables Dependabot entirely. -- During rebase, delete `.github/dependabot.yml` in the carry commit and avoid reintroducing it. -- No replacement configuration is required; document the disablement in commit message for clarity. diff --git a/carry_consolidation/gitignore.patch b/carry_consolidation/gitignore.patch deleted file mode 100644 index b12cfc7abf..0000000000 --- a/carry_consolidation/gitignore.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/.gitignore b/.gitignore -index 5a6dd1245..bd3896f72 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -1,7 +1,7 @@ --# only add build artifacts concerning coredns - no editor related files --coredns --coredns.exe --Corefile --build/ --release/ --vendor/ -+query.log -+Corefile -+*.swp -+/coredns -+coredns.exe -+/build/ -+release/ diff --git a/carry_consolidation/make_test_policy.md b/carry_consolidation/make_test_policy.md deleted file mode 100644 index 0dd17b7f41..0000000000 --- a/carry_consolidation/make_test_policy.md +++ /dev/null @@ -1,14 +0,0 @@ -## Downstream `make test` target - -- Keep a single `test` target that the OpenShift ci-operator calls. -- Target must depend on `check` to regenerate `zplugin.go`/`zdirectives.go`. -- Use module-aware testing with vendored deps: - -```make -.PHONY: test -test: check - GOFLAGS=-mod=vendor go test -count=1 ./... -``` - -- Avoid per-package subshell loops; Go 1.24 handles parallelization itself. -- Ensure CI jobs set `GOFLAGS=-mod=vendor` (either via environment or within the target as shown). diff --git a/carry_consolidation/makefile.patch b/carry_consolidation/makefile.patch deleted file mode 100644 index c1bce71a27..0000000000 --- a/carry_consolidation/makefile.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/Makefile b/Makefile -index 6d8cd9189..98a5bc3d3 100644 ---- a/Makefile -+++ b/Makefile -@@ - .PHONY: test --test: check -- ( cd request ; go test -v -race ./... ) -- ( cd core ; go test -v -race ./... ) -- ( cd coremain ; go test -v -race ./... ) -- ( cd test ; go test -v -race ./... ) -- ( cd plugin ; go test -v -race ./... ) -+test: check -+ GOFLAGS=-mod=vendor go test -count=1 ./... diff --git a/carry_consolidation/ocp_dnsnameresolver.md b/carry_consolidation/ocp_dnsnameresolver.md index 599f73d147..3a5119e8be 100644 --- a/carry_consolidation/ocp_dnsnameresolver.md +++ b/carry_consolidation/ocp_dnsnameresolver.md @@ -1,13 +1,12 @@ ## ocp_dnsnameresolver carry instructions -Downstream keeps the external `ocp_dnsnameresolver` plugin. Upstream v1.13.1 does not ship it, so we must reapply the carry after the merge. +Downstream keeps the external `ocp_dnsnameresolver` plugin. Upstream v1.14.4 does not ship it, so we must reapply the carry after the merge. ### Files to edit - `plugin.cfg`: add `ocp_dnsnameresolver:github.com/openshift/coredns-ocp-dnsnameresolver` before `cache`. - `core/plugin/zplugin.go` and `core/dnsserver/zdirectives.go`: regenerated outputs that pick up the plugin entry. - `go.mod` / `go.sum`: add the released module version for `github.com/openshift/coredns-ocp-dnsnameresolver`. - `vendor/modules.txt` and `vendor/github.com/openshift/coredns-ocp-dnsnameresolver/**`: repopulated via `go mod vendor`. -- Drop the temporary `replace` directive once the plugin release is tagged (track in action plan). ### Commands 1. Ensure the desired plugin version is set in `go.mod` (`go get github.com/openshift/coredns-ocp-dnsnameresolver@`). @@ -18,6 +17,10 @@ Downstream keeps the external `ocp_dnsnameresolver` plugin. Upstream v1.13.1 doe ### Ordering requirement `ocp_dnsnameresolver` must remain immediately before `cache` in `plugin.cfg`; the generator preserves this ordering in the generated files. +### k8s dependency note (v1.14.4 rebase) +The `ocp_dnsnameresolver` plugin at `01fb3d1` requires k8s v0.36.2 (there is no k8s v0.35.x release of the plugin). +Go MVS pulls CoreDNS k8s deps from v0.35.4 to v0.36.2. This is acceptable — k8s v0.36.2 is backwards-compatible. + ### Validation - `GOFLAGS=-mod=vendor go test ./plugin/...` to ensure registrations compile. -- Execute the targeted plugin smoke tests from the prototype branch once the module tag is published. +- `GOFLAGS=-mod=vendor go test -count=1 ./...` for full test suite. diff --git a/carry_consolidation/vendor_workflow.md b/carry_consolidation/vendor_workflow.md deleted file mode 100644 index f1a52e78ec..0000000000 --- a/carry_consolidation/vendor_workflow.md +++ /dev/null @@ -1,17 +0,0 @@ -## Downstream vendoring strategy - -We continue to vendor dependencies so downstream builds do not rely on network access. - -### Regenerating vendor after the rebase -1. Ensure `go.mod` and `go.sum` reflect the desired dependency set (run `go mod tidy` if needed once conflicts are resolved). -2. Run `GOFLAGS=-mod=vendor go mod vendor` (or export `GOFLAGS=-mod=vendor` globally) to repopulate `vendor/`. -3. Re-apply the downstream ginkgo shim (`vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go`) if it is dropped by `go mod vendor`. -4. Stage the entire `vendor/` tree along with `go.mod` / `go.sum` updates in a single carry commit. - -### Build tooling expectations -- Dockerfiles (`Dockerfile.openshift`, `Dockerfile.openshift.rhel7`, etc.) must keep `GO111MODULE=on` and `GOFLAGS=-mod=vendor` so container builds consume the vendored tree. -- Any CI/Make targets that compile CoreDNS should set `GOFLAGS=-mod=vendor` (unless the buildroot already enforces it). - -### .gitignore adjustments -- Keep vendor tracked by removing the upstream `vendor/` ignore entry; see `carry_consolidation/gitignore.patch`. -- Ignore build outputs only: `query.log`, `Corefile`, `*.swp`, `/coredns`, `coredns.exe`, `/build/`, `release/`. diff --git a/core/dnsserver/config.go b/core/dnsserver/config.go index 168120795d..c46b2fb77a 100644 --- a/core/dnsserver/config.go +++ b/core/dnsserver/config.go @@ -10,6 +10,8 @@ import ( "github.com/coredns/caddy" "github.com/coredns/coredns/plugin" "github.com/coredns/coredns/request" + + "github.com/pires/go-proxyproto" ) // Config configuration for a single server. @@ -66,6 +68,43 @@ type Config struct { // This is nil if not specified, allowing for a default to be used. MaxQUICWorkerPoolSize *int + // ProxyProtoConnPolicy is the function that will be used to + // configure the PROXY protocol settings on listeners. + // If nil, PROXY protocol is disabled. + ProxyProtoConnPolicy proxyproto.ConnPolicyFunc + + // ProxyProtoUDPSessionTrackingTTL enables per-UDP-session source address + // caching on the PacketConn listener when set to a positive duration. + // The first datagram of a Cloudflare Spectrum PPv2 session (which contains + // only the PROXY Protocol header and no DNS payload) is used to populate a + // short-lived cache keyed by the Spectrum-side remote address. Subsequent + // datagrams from the same remote address that carry no PROXY Protocol header + // are associated with the cached real client address for up to this duration + // (refreshed on each matching packet). A zero or negative value disables + // session tracking. Has no effect unless ProxyProtoConnPolicy is also set. + ProxyProtoUDPSessionTrackingTTL time.Duration + + // ProxyProtoUDPSessionTrackingMaxSessions is the maximum number of concurrent + // UDP sessions held in the LRU cache. Zero means use the default (udpSessionMaxEntries). + // Has no effect unless ProxyProtoUDPSessionTrackingTTL is positive. + ProxyProtoUDPSessionTrackingMaxSessions int + + // MaxGRPCStreams defines the maximum number of concurrent streams per gRPC connection. + // This is nil if not specified, allowing for a default to be used. + MaxGRPCStreams *int + + // MaxGRPCConnections defines the maximum number of concurrent gRPC connections. + // This is nil if not specified, allowing for a default to be used. + MaxGRPCConnections *int + + // MaxHTTPSConnections defines the maximum number of concurrent HTTPS connections. + // This is nil if not specified, allowing for a default to be used. + MaxHTTPSConnections *int + + // MaxHTTPS3Streams defines the maximum number of concurrent QUIC streams for HTTPS3. + // This is nil if not specified, allowing for a default to be used. + MaxHTTPS3Streams *int + // Timeouts for TCP, TLS and HTTPS servers. ReadTimeout time.Duration WriteTimeout time.Duration diff --git a/core/dnsserver/https.go b/core/dnsserver/https.go index 437c561f2b..2430f20a79 100644 --- a/core/dnsserver/https.go +++ b/core/dnsserver/https.go @@ -17,6 +17,9 @@ type DoHWriter struct { // request is the HTTP request we're currently handling. request *http.Request + // tsigStatus stores the TSIG verification result for the request. + tsigStatus error + // Msg is a response to be written to the client. Msg *dns.Msg } @@ -58,9 +61,9 @@ func (d *DoHWriter) Close() error { return nil } -// TsigStatus no-op implementation. +// TsigStatus returns the TSIG verification status for this request. func (d *DoHWriter) TsigStatus() error { - return nil + return d.tsigStatus } // TsigTimersOnly no-op implementation. diff --git a/core/dnsserver/onstartup.go b/core/dnsserver/onstartup.go index 90a270badc..6b84d6b8d5 100644 --- a/core/dnsserver/onstartup.go +++ b/core/dnsserver/onstartup.go @@ -35,23 +35,23 @@ func startUpZones(protocol, addr string, zones map[string][]*Config) string { var sb strings.Builder for _, zone := range keys { if !checkZoneSyntax(zone) { - sb.WriteString(fmt.Sprintf("Warning: Domain %q does not follow RFC1035 preferred syntax\n", zone)) + fmt.Fprintf(&sb, "Warning: Domain %q does not follow RFC1035 preferred syntax\n", zone) } // split addr into protocol, IP and Port _, ip, port, err := SplitProtocolHostPort(addr) if err != nil { // this should not happen, but we need to take care of it anyway - sb.WriteString(fmt.Sprintln(protocol + zone + ":" + addr)) + fmt.Fprintln(&sb, protocol+zone+":"+addr) continue } if ip == "" { - sb.WriteString(fmt.Sprintln(protocol + zone + ":" + port)) + fmt.Fprintln(&sb, protocol+zone+":"+port) continue } // if the server is listening on a specific address let's make it visible in the log, // so one can differentiate between all active listeners - sb.WriteString(fmt.Sprintln(protocol + zone + ":" + port + " on " + ip)) + fmt.Fprintln(&sb, protocol+zone+":"+port+" on "+ip) } return sb.String() } diff --git a/core/dnsserver/quic.go b/core/dnsserver/quic.go index f7cde74a81..029f892063 100644 --- a/core/dnsserver/quic.go +++ b/core/dnsserver/quic.go @@ -1,6 +1,7 @@ package dnsserver import ( + "crypto/tls" "encoding/binary" "errors" "net" @@ -13,7 +14,9 @@ type DoQWriter struct { localAddr net.Addr remoteAddr net.Addr stream *quic.Stream + conn *quic.Conn Msg *dns.Msg + tsigStatus error } func (w *DoQWriter) Write(b []byte) (int, error) { @@ -53,16 +56,29 @@ func (w *DoQWriter) Close() error { // AddPrefix adds a 2-byte prefix with the DNS message length. func AddPrefix(b []byte) (m []byte) { m = make([]byte, 2+len(b)) - binary.BigEndian.PutUint16(m, uint16(len(b))) + binary.BigEndian.PutUint16(m, uint16(len(b))) // #nosec G115 -- DNS message length fits in uint16 copy(m[2:], b) return m } // These methods implement the dns.ResponseWriter interface from Go DNS. -func (w *DoQWriter) TsigStatus() error { return nil } -func (w *DoQWriter) TsigTimersOnly(b bool) {} -func (w *DoQWriter) Hijack() {} -func (w *DoQWriter) LocalAddr() net.Addr { return w.localAddr } -func (w *DoQWriter) RemoteAddr() net.Addr { return w.remoteAddr } -func (w *DoQWriter) Network() string { return "" } + +func (w *DoQWriter) TsigStatus() error { return w.tsigStatus } +func (w *DoQWriter) TsigTimersOnly(_b bool) {} +func (w *DoQWriter) Hijack() {} +func (w *DoQWriter) LocalAddr() net.Addr { return w.localAddr } +func (w *DoQWriter) RemoteAddr() net.Addr { return w.remoteAddr } +func (w *DoQWriter) Network() string { return "" } + +// ConnectionState implements the dns.ConnectionStater interface, exposing the +// TLS state of the underlying QUIC connection (e.g. for plugins that need to +// read the SNI ServerName). Mirrors the DoT behavior already provided by the +// miekg/dns response writer. +func (w *DoQWriter) ConnectionState() *tls.ConnectionState { + if w.conn == nil { + return nil + } + state := w.conn.ConnectionState().TLS + return &state +} diff --git a/core/dnsserver/quic_test.go b/core/dnsserver/quic_test.go index 7e73019066..276a0607c6 100644 --- a/core/dnsserver/quic_test.go +++ b/core/dnsserver/quic_test.go @@ -48,3 +48,11 @@ func TestDoQWriter_ResponseWriterMethods(t *testing.T) { t.Errorf("RemoteAddr() = %v, want %v", addr, remoteAddr) } } + +func TestDoQWriter_ConnectionStateNilConn(t *testing.T) { + writer := &DoQWriter{} + + if state := writer.ConnectionState(); state != nil { + t.Errorf("ConnectionState() = %v, want nil when conn is unset", state) + } +} diff --git a/core/dnsserver/register.go b/core/dnsserver/register.go index f289ceaa51..3c7610b837 100644 --- a/core/dnsserver/register.go +++ b/core/dnsserver/register.go @@ -30,7 +30,7 @@ func init() { }) } -func newContext(i *caddy.Instance) caddy.Context { +func newContext(_i *caddy.Instance) caddy.Context { return &dnsContext{keysToConfigs: make(map[string]*Config)} } @@ -52,7 +52,7 @@ var _ caddy.Context = &dnsContext{} // InspectServerBlocks make sure that everything checks out before // executing directives and otherwise prepares the directives to // be parsed and executed. -func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) { +func (h *dnsContext) InspectServerBlocks(_sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) { // Normalize and check all the zone names and check for duplicates for ib, s := range serverBlocks { // Walk the s.Keys and expand any reverse address in their proper DNS in-addr zones. If the expansions leads for @@ -88,6 +88,8 @@ func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddy port = transport.GRPCPort case transport.HTTPS: port = transport.HTTPSPort + case transport.HTTPS3: + port = transport.HTTPSPort } } @@ -235,11 +237,13 @@ func (h *dnsContext) validateZonesAndListeningAddresses() error { akey := zoneAddr{Transport: conf.Transport, Zone: conf.Zone, Address: h, Port: conf.Port} var existZone, overlapZone *zoneAddr if len(conf.FilterFuncs) > 0 { - // This config has filters. Check for overlap with other (unfiltered) configs. - existZone, overlapZone = checker.check(akey) + // This config has filters (e.g. view plugin). It is allowed to + // share a zone/port with an unfiltered server block, so we only + // check without registering and skip the "already defined" error. + _, overlapZone = checker.check(akey) } else { - // This config has no filters. Check for overlap with other (unfiltered) configs, - // and register the zone to prevent subsequent zones from overlapping with it. + // This config has no filters. Check for overlap with other + // unfiltered configs and register the zone. existZone, overlapZone = checker.registerAndCheck(akey) } if existZone != nil { @@ -347,6 +351,13 @@ func makeServersForGroup(addr string, group []*Config) ([]caddy.Server, error) { return nil, err } servers = append(servers, s) + + case transport.HTTPS3: + s, err := NewServerHTTPS3(addr, group) + if err != nil { + return nil, err + } + servers = append(servers, s) } } return servers, nil diff --git a/core/dnsserver/server.go b/core/dnsserver/server.go index 3f7441dfcc..942520ace2 100644 --- a/core/dnsserver/server.go +++ b/core/dnsserver/server.go @@ -16,6 +16,7 @@ import ( "github.com/coredns/coredns/plugin/metrics/vars" "github.com/coredns/coredns/plugin/pkg/edns" "github.com/coredns/coredns/plugin/pkg/log" + cproxyproto "github.com/coredns/coredns/plugin/pkg/proxyproto" "github.com/coredns/coredns/plugin/pkg/rcode" "github.com/coredns/coredns/plugin/pkg/reuseport" "github.com/coredns/coredns/plugin/pkg/trace" @@ -24,6 +25,7 @@ import ( "github.com/miekg/dns" ot "github.com/opentracing/opentracing-go" + "github.com/pires/go-proxyproto" ) // Server represents an instance of a server, which serves @@ -37,6 +39,10 @@ type Server struct { ReadTimeout time.Duration // Read timeout for TCP WriteTimeout time.Duration // Write timeout for TCP + connPolicy proxyproto.ConnPolicyFunc // Proxy Protocol connection policy function + udpSessionTrackingTTL time.Duration // TTL for UDP PPv2 session tracking (0 = disabled) + udpSessionTrackingMaxSessions int // LRU cap for UDP session tracking (0 = default) + server [2]*dns.Server // 0 is a net.Listener, 1 is a net.PacketConn (a *UDPConn) in our case. m sync.Mutex // protects the servers @@ -123,6 +129,15 @@ func NewServer(addr string, group []*Config) (*Server, error) { } } site.pluginChain = stack + if site.ProxyProtoConnPolicy != nil { + s.connPolicy = site.ProxyProtoConnPolicy + } + if site.ProxyProtoUDPSessionTrackingTTL > 0 { + s.udpSessionTrackingTTL = site.ProxyProtoUDPSessionTrackingTTL + } + if site.ProxyProtoUDPSessionTrackingMaxSessions > 0 { + s.udpSessionTrackingMaxSessions = site.ProxyProtoUDPSessionTrackingMaxSessions + } } if !s.debug { @@ -181,6 +196,9 @@ func (s *Server) Listen() (net.Listener, error) { if err != nil { return nil, err } + if s.connPolicy != nil { + l = &proxyproto.Listener{Listener: l, ConnPolicy: s.connPolicy} + } return l, nil } @@ -195,7 +213,9 @@ func (s *Server) ListenPacket() (net.PacketConn, error) { if err != nil { return nil, err } - + if s.connPolicy != nil { + p = &cproxyproto.PacketConn{PacketConn: p, ConnPolicy: s.connPolicy, UDPSessionTrackingTTL: s.udpSessionTrackingTTL, UDPSessionTrackingMaxSessions: s.udpSessionTrackingMaxSessions} + } return p, nil } @@ -217,11 +237,9 @@ func (s *Server) Stop() error { continue } - wg.Add(1) - go func() { + wg.Go(func() { s1.ShutdownContext(ctx) - wg.Done() - }() + }) } s.m.Unlock() wg.Wait() @@ -396,7 +414,7 @@ func (s *Server) Tracer() ot.Tracer { } // errorFunc responds to an DNS request with an error. -func errorFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int) { +func errorFunc(_server string, w dns.ResponseWriter, r *dns.Msg, rc int) { state := request.Request{W: w, Req: r} answer := new(dns.Msg) diff --git a/core/dnsserver/server_grpc.go b/core/dnsserver/server_grpc.go index 3a4da752d2..42f54eaff6 100644 --- a/core/dnsserver/server_grpc.go +++ b/core/dnsserver/server_grpc.go @@ -15,17 +15,36 @@ import ( "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc" "github.com/miekg/dns" "github.com/opentracing/opentracing-go" + "github.com/pires/go-proxyproto" + "golang.org/x/net/netutil" "google.golang.org/grpc" "google.golang.org/grpc/peer" ) +const ( + // maxDNSMessageBytes is the maximum size of a DNS message on the wire. + maxDNSMessageBytes = dns.MaxMsgSize + + // maxProtobufPayloadBytes accounts for protobuf overhead. + // Field tag=1 (1 byte) + length varint for 65535 (3 bytes) = 4 bytes total + maxProtobufPayloadBytes = maxDNSMessageBytes + 4 + + // DefaultGRPCMaxStreams is the default maximum number of concurrent streams per connection. + DefaultGRPCMaxStreams = 256 + + // DefaultGRPCMaxConnections is the default maximum number of concurrent connections. + DefaultGRPCMaxConnections = 200 +) + // ServergRPC represents an instance of a DNS-over-gRPC server. type ServergRPC struct { *Server *pb.UnimplementedDnsServiceServer - grpcServer *grpc.Server - listenAddr net.Addr - tlsConfig *tls.Config + grpcServer *grpc.Server + listenAddr net.Addr + tlsConfig *tls.Config + maxStreams int + maxConnections int } // NewServergRPC returns a new CoreDNS GRPC server and compiles all plugin in to it. @@ -49,7 +68,22 @@ func NewServergRPC(addr string, group []*Config) (*ServergRPC, error) { tlsConfig.NextProtos = []string{"h2"} } - return &ServergRPC{Server: s, tlsConfig: tlsConfig}, nil + maxStreams := DefaultGRPCMaxStreams + if len(group) > 0 && group[0] != nil && group[0].MaxGRPCStreams != nil { + maxStreams = *group[0].MaxGRPCStreams + } + + maxConnections := DefaultGRPCMaxConnections + if len(group) > 0 && group[0] != nil && group[0].MaxGRPCConnections != nil { + maxConnections = *group[0].MaxGRPCConnections + } + + return &ServergRPC{ + Server: s, + tlsConfig: tlsConfig, + maxStreams: maxStreams, + maxConnections: maxConnections, + }, nil } // Compile-time check to ensure ServergRPC implements the caddy.GracefulServer interface @@ -61,26 +95,41 @@ func (s *ServergRPC) Serve(l net.Listener) error { s.listenAddr = l.Addr() s.m.Unlock() + serverOpts := []grpc.ServerOption{ + grpc.MaxRecvMsgSize(maxProtobufPayloadBytes), + grpc.MaxSendMsgSize(maxProtobufPayloadBytes), + } + + // Only set MaxConcurrentStreams if not unbounded (0) + if s.maxStreams > 0 { + serverOpts = append(serverOpts, grpc.MaxConcurrentStreams(uint32(s.maxStreams))) // #nosec G115 -- maxStreams is bounded + } + if s.Tracer() != nil { - onlyIfParent := func(parentSpanCtx opentracing.SpanContext, method string, req, resp any) bool { + onlyIfParent := func(parentSpanCtx opentracing.SpanContext, _method string, _req, _resp any) bool { return parentSpanCtx != nil } - intercept := otgrpc.OpenTracingServerInterceptor(s.Tracer(), otgrpc.IncludingSpans(onlyIfParent)) - s.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(intercept)) - } else { - s.grpcServer = grpc.NewServer() + serverOpts = append(serverOpts, grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(s.Tracer(), otgrpc.IncludingSpans(onlyIfParent)))) } + s.grpcServer = grpc.NewServer(serverOpts...) + pb.RegisterDnsServiceServer(s.grpcServer, s) if s.tlsConfig != nil { l = tls.NewListener(l, s.tlsConfig) } + + // Wrap listener to limit concurrent connections + if s.maxConnections > 0 { + l = netutil.LimitListener(l, s.maxConnections) + } + return s.grpcServer.Serve(l) } // ServePacket implements caddy.UDPServer interface. -func (s *ServergRPC) ServePacket(p net.PacketConn) error { return nil } +func (s *ServergRPC) ServePacket(_p net.PacketConn) error { return nil } // Listen implements caddy.TCPServer interface. func (s *ServergRPC) Listen() (net.Listener, error) { @@ -88,6 +137,9 @@ func (s *ServergRPC) Listen() (net.Listener, error) { if err != nil { return nil, err } + if s.connPolicy != nil { + l = &proxyproto.Listener{Listener: l, ConnPolicy: s.connPolicy} + } return l, nil } @@ -122,6 +174,9 @@ func (s *ServergRPC) Stop() (err error) { // any normal server. We use a custom responseWriter to pick up the bytes we need to write // back to the client as a protobuf. func (s *ServergRPC) Query(ctx context.Context, in *pb.DnsPacket) (*pb.DnsPacket, error) { + if len(in.GetMsg()) > dns.MaxMsgSize { + return nil, fmt.Errorf("dns message exceeds size limit: %d", len(in.GetMsg())) + } msg := new(dns.Msg) err := msg.Unpack(in.GetMsg()) if err != nil { @@ -140,6 +195,16 @@ func (s *ServergRPC) Query(ctx context.Context, in *pb.DnsPacket) (*pb.DnsPacket w := &gRPCresponse{localAddr: s.listenAddr, remoteAddr: a, Msg: msg} + if tsig := msg.IsTsig(); tsig != nil { + if s.tsigSecret == nil { + w.tsigStatus = dns.ErrSecret + } else if secret, ok := s.tsigSecret[tsig.Hdr.Name]; !ok { + w.tsigStatus = dns.ErrSecret + } else { + w.tsigStatus = dns.TsigVerify(in.GetMsg(), secret, "", false) + } + } + dnsCtx := context.WithValue(ctx, Key{}, s.Server) dnsCtx = context.WithValue(dnsCtx, LoopKey{}, 0) s.ServeDNS(dnsCtx, w, msg) @@ -164,6 +229,7 @@ type gRPCresponse struct { localAddr net.Addr remoteAddr net.Addr Msg *dns.Msg + tsigStatus error } // Write is the hack that makes this work. It does not actually write the message @@ -175,9 +241,10 @@ func (r *gRPCresponse) Write(b []byte) (int, error) { } // These methods implement the dns.ResponseWriter interface from Go DNS. + func (r *gRPCresponse) Close() error { return nil } -func (r *gRPCresponse) TsigStatus() error { return nil } -func (r *gRPCresponse) TsigTimersOnly(b bool) {} +func (r *gRPCresponse) TsigStatus() error { return r.tsigStatus } +func (r *gRPCresponse) TsigTimersOnly(_b bool) {} func (r *gRPCresponse) Hijack() {} func (r *gRPCresponse) LocalAddr() net.Addr { return r.localAddr } func (r *gRPCresponse) RemoteAddr() net.Addr { return r.remoteAddr } diff --git a/core/dnsserver/server_grpc_test.go b/core/dnsserver/server_grpc_test.go index 5dc72b55bd..3a74b1677a 100644 --- a/core/dnsserver/server_grpc_test.go +++ b/core/dnsserver/server_grpc_test.go @@ -3,8 +3,10 @@ package dnsserver import ( "context" "crypto/tls" + "errors" "net" "testing" + "time" "github.com/coredns/coredns/pb" "github.com/coredns/coredns/plugin/pkg/transport" @@ -69,6 +71,61 @@ func TestNewServergRPCWithTLS(t *testing.T) { } } +func TestNewServergRPCWithCustomLimits(t *testing.T) { + config := testConfig("grpc", testPlugin{}) + maxStreams := 50 + maxConnections := 100 + config.MaxGRPCStreams = &maxStreams + config.MaxGRPCConnections = &maxConnections + + server, err := NewServergRPC("127.0.0.1:0", []*Config{config}) + if err != nil { + t.Fatalf("NewServergRPC() with custom limits failed: %v", err) + } + + if server.maxStreams != maxStreams { + t.Errorf("Expected maxStreams = %d, got %d", maxStreams, server.maxStreams) + } + + if server.maxConnections != maxConnections { + t.Errorf("Expected maxConnections = %d, got %d", maxConnections, server.maxConnections) + } +} + +func TestNewServergRPCDefaults(t *testing.T) { + server, err := NewServergRPC("127.0.0.1:0", []*Config{testConfig("grpc", testPlugin{})}) + if err != nil { + t.Fatalf("NewServergRPC() failed: %v", err) + } + + if server.maxStreams != DefaultGRPCMaxStreams { + t.Errorf("Expected default maxStreams = %d, got %d", DefaultGRPCMaxStreams, server.maxStreams) + } + + if server.maxConnections != DefaultGRPCMaxConnections { + t.Errorf("Expected default maxConnections = %d, got %d", DefaultGRPCMaxConnections, server.maxConnections) + } +} + +func TestNewServergRPCZeroLimits(t *testing.T) { + config := testConfig("grpc", testPlugin{}) + zero := 0 + config.MaxGRPCStreams = &zero + config.MaxGRPCConnections = &zero + + server, err := NewServergRPC("127.0.0.1:0", []*Config{config}) + if err != nil { + t.Fatalf("NewServergRPC() with zero limits failed: %v", err) + } + + if server.maxStreams != 0 { + t.Errorf("Expected maxStreams = 0, got %d", server.maxStreams) + } + if server.maxConnections != 0 { + t.Errorf("Expected maxConnections = 0, got %d", server.maxConnections) + } +} + func TestServergRPC_Listen(t *testing.T) { server, err := NewServergRPC(transport.GRPC+"://127.0.0.1:0", []*Config{testConfig("grpc", testPlugin{})}) if err != nil { @@ -328,3 +385,236 @@ func TestGRPCResponse_WriteInvalidMessage(t *testing.T) { t.Error("Write() should return error for invalid DNS message") } } + +func TestServergRPC_Query_LargeMessage(t *testing.T) { + server, err := NewServergRPC("127.0.0.1:0", []*Config{testConfig("grpc", testPlugin{})}) + if err != nil { + t.Fatalf("NewServergRPC failed: %v", err) + } + + // Create oversized message (> dns.MaxMsgSize = 65535) + oversizedMsg := make([]byte, dns.MaxMsgSize+1) + dnsPacket := &pb.DnsPacket{Msg: oversizedMsg} + + tcpAddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:12345") + p := &peer.Peer{Addr: tcpAddr} + ctx := peer.NewContext(context.Background(), p) + + server.listenAddr = tcpAddr + + _, err = server.Query(ctx, dnsPacket) + if err == nil { + t.Error("Expected error for oversized message") + } + + expectedError := "dns message exceeds size limit: 65536" + if err.Error() != expectedError { + t.Errorf("Expected error '%s', got '%s'", expectedError, err.Error()) + } +} + +func TestServergRPC_Query_MaxSizeMessage(t *testing.T) { + server, err := NewServergRPC("127.0.0.1:0", []*Config{testConfig("grpc", testPlugin{})}) + if err != nil { + t.Fatalf("NewServergRPC failed: %v", err) + } + + // Create message exactly at the size limit (dns.MaxMsgSize = 65535) + msg := new(dns.Msg) + msg.SetQuestion("example.com.", dns.TypeA) + packed, err := msg.Pack() + if err != nil { + t.Fatalf("Failed to pack DNS message: %v", err) + } + + // Pad the message to exactly max size + if len(packed) > dns.MaxMsgSize { + t.Fatalf("Packed message is already larger than max size: %d", len(packed)) + } + + maxSizeMsg := make([]byte, dns.MaxMsgSize) + copy(maxSizeMsg, packed) + + dnsPacket := &pb.DnsPacket{Msg: maxSizeMsg} + + tcpAddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:12345") + p := &peer.Peer{Addr: tcpAddr} + ctx := peer.NewContext(context.Background(), p) + + server.listenAddr = tcpAddr + + // Should not return an error for exactly max size message + _, err = server.Query(ctx, dnsPacket) + if err != nil { + t.Errorf("Expected no error for max size message, got: %v", err) + } +} + +func TestGRPCResponseTsigStatusReturnsStoredStatus(t *testing.T) { + want := errors.New("bad tsig") + + r := &gRPCresponse{ + tsigStatus: want, + } + + if got := r.TsigStatus(); got != want { + t.Fatalf("TsigStatus() = %v, want %v", got, want) + } +} + +func TestServergRPC_Query_TSIGBadSigSetsTsigStatus(t *testing.T) { + const keyName = "tsig-key." + const clientSecret = "MTIzNDU2Nzg5MDEyMzQ1Ng==" + const serverSecret = "QUJDREVGR0hJSktMTU5PUA==" + + called := make(chan struct{}, 1) + + server, err := NewServergRPC("127.0.0.1:0", []*Config{ + testConfig("grpc", tsigStatusCheckPlugin{ + t: t, + called: called, + check: func(t *testing.T, got error) { + t.Helper() + if got == nil { + t.Fatal("TsigStatus() = nil, want non-nil for bad TSIG MAC") + } + if errors.Is(got, dns.ErrSecret) { + t.Fatalf("TsigStatus() = %v, want signature verification error, not ErrSecret", got) + } + if errors.Is(got, dns.ErrTime) { + t.Fatalf("TsigStatus() = %v, want signature verification error, not ErrTime", got) + } + }, + }), + }) + if err != nil { + t.Fatalf("NewServergRPC() failed: %v", err) + } + + server.tsigSecret = map[string]string{ + keyName: serverSecret, + } + + tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:12345") + if err != nil { + t.Fatalf("ResolveTCPAddr() failed: %v", err) + } + ctx := peer.NewContext(context.Background(), &peer.Peer{Addr: tcpAddr}) + server.listenAddr = tcpAddr + + wire := mustPackSignedTSIGQuery(t, keyName, clientSecret, time.Now().Unix()) + + _, err = server.Query(ctx, &pb.DnsPacket{Msg: wire}) + if err != nil { + t.Fatalf("Query() failed: %v", err) + } + + select { + case <-called: + default: + t.Fatal("ServeDNS() was not called") + } +} + +func TestServergRPC_Query_TSIGBadTimeSetsTsigStatus(t *testing.T) { + const keyName = "tsig-key." + const secret = "MTIzNDU2Nzg5MDEyMzQ1Ng==" + + called := make(chan struct{}, 1) + + server, err := NewServergRPC("127.0.0.1:0", []*Config{ + testConfig("grpc", tsigStatusCheckPlugin{ + t: t, + called: called, + check: func(t *testing.T, got error) { + t.Helper() + if !errors.Is(got, dns.ErrTime) { + t.Fatalf("TsigStatus() = %v, want %v", got, dns.ErrTime) + } + }, + }), + }) + if err != nil { + t.Fatalf("NewServergRPC() failed: %v", err) + } + + server.tsigSecret = map[string]string{ + keyName: secret, + } + + tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:12345") + if err != nil { + t.Fatalf("ResolveTCPAddr() failed: %v", err) + } + ctx := peer.NewContext(context.Background(), &peer.Peer{Addr: tcpAddr}) + server.listenAddr = tcpAddr + + wire := mustPackSignedTSIGQuery(t, keyName, secret, time.Now().Add(-10*time.Minute).Unix()) + + _, err = server.Query(ctx, &pb.DnsPacket{Msg: wire}) + if err != nil { + t.Fatalf("Query() failed: %v", err) + } + + select { + case <-called: + default: + t.Fatal("ServeDNS() was not called") + } +} + +func TestServergRPC_Query_TSIGValidLeavesTsigStatusNil(t *testing.T) { + const keyName = "tsig-key." + const secret = "MTIzNDU2Nzg5MDEyMzQ1Ng==" + + called := make(chan struct{}, 1) + + server, err := NewServergRPC("127.0.0.1:0", []*Config{ + testConfig("grpc", tsigStatusCheckPlugin{ + t: t, + called: called, + check: func(t *testing.T, got error) { + t.Helper() + if got != nil { + t.Fatalf("TsigStatus() = %v, want nil", got) + } + }, + }), + }) + if err != nil { + t.Fatalf("NewServergRPC() failed: %v", err) + } + + server.tsigSecret = map[string]string{ + keyName: secret, + } + + tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:12345") + if err != nil { + t.Fatalf("ResolveTCPAddr() failed: %v", err) + } + ctx := peer.NewContext(context.Background(), &peer.Peer{Addr: tcpAddr}) + server.listenAddr = tcpAddr + + wire := mustPackSignedTSIGQuery(t, keyName, secret, time.Now().Unix()) + + resp, err := server.Query(ctx, &pb.DnsPacket{Msg: wire}) + if err != nil { + t.Fatalf("Query() failed: %v", err) + } + + select { + case <-called: + default: + t.Fatal("ServeDNS() was not called") + } + + if len(resp.GetMsg()) == 0 { + t.Fatal("Query() returned empty message") + } + + respMsg := new(dns.Msg) + if err := respMsg.Unpack(resp.GetMsg()); err != nil { + t.Fatalf("Failed to unpack response message: %v", err) + } +} diff --git a/core/dnsserver/server_https.go b/core/dnsserver/server_https.go index cf84e8c35b..334d4cffbd 100644 --- a/core/dnsserver/server_https.go +++ b/core/dnsserver/server_https.go @@ -18,15 +18,25 @@ import ( "github.com/coredns/coredns/plugin/pkg/response" "github.com/coredns/coredns/plugin/pkg/reuseport" "github.com/coredns/coredns/plugin/pkg/transport" + + "github.com/miekg/dns" + "github.com/pires/go-proxyproto" + "golang.org/x/net/netutil" +) + +const ( + // DefaultHTTPSMaxConnections is the default maximum number of concurrent connections. + DefaultHTTPSMaxConnections = 200 ) // ServerHTTPS represents an instance of a DNS-over-HTTPS server. type ServerHTTPS struct { *Server - httpsServer *http.Server - listenAddr net.Addr - tlsConfig *tls.Config - validRequest func(*http.Request) bool + httpsServer *http.Server + listenAddr net.Addr + tlsConfig *tls.Config + validRequest func(*http.Request) bool + maxConnections int } // loggerAdapter is a simple adapter around CoreDNS logger made to implement io.Writer in order to log errors from HTTP server @@ -81,8 +91,17 @@ func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) { IdleTimeout: s.IdleTimeout, ErrorLog: stdlog.New(&loggerAdapter{}, "", 0), } + maxConnections := DefaultHTTPSMaxConnections + if len(group) > 0 && group[0] != nil && group[0].MaxHTTPSConnections != nil { + maxConnections = *group[0].MaxHTTPSConnections + } + sh := &ServerHTTPS{ - Server: s, tlsConfig: tlsConfig, httpsServer: srv, validRequest: validator, + Server: s, + tlsConfig: tlsConfig, + httpsServer: srv, + validRequest: validator, + maxConnections: maxConnections, } sh.httpsServer.Handler = sh @@ -98,14 +117,20 @@ func (s *ServerHTTPS) Serve(l net.Listener) error { s.listenAddr = l.Addr() s.m.Unlock() + // Wrap listener to limit concurrent connections (before TLS) + if s.maxConnections > 0 { + l = netutil.LimitListener(l, s.maxConnections) + } + if s.tlsConfig != nil { l = tls.NewListener(l, s.tlsConfig) } + return s.httpsServer.Serve(l) } // ServePacket implements caddy.UDPServer interface. -func (s *ServerHTTPS) ServePacket(p net.PacketConn) error { return nil } +func (s *ServerHTTPS) ServePacket(_p net.PacketConn) error { return nil } // Listen implements caddy.TCPServer interface. func (s *ServerHTTPS) Listen() (net.Listener, error) { @@ -113,6 +138,9 @@ func (s *ServerHTTPS) Listen() (net.Listener, error) { if err != nil { return nil, err } + if s.connPolicy != nil { + l = &proxyproto.Listener{Listener: l, ConnPolicy: s.connPolicy} + } return l, nil } @@ -142,6 +170,14 @@ func (s *ServerHTTPS) Stop() error { return nil } +// localAddr returns the per-connection local address, or s.listenAddr as fallback. +func (s *ServerHTTPS) localAddr(r *http.Request) net.Addr { + if addr, ok := r.Context().Value(http.LocalAddrContextKey).(net.Addr); ok { + return addr + } + return s.listenAddr +} + // ServeHTTP is the handler that gets the HTTP request and converts to the dns format, calls the plugin // chain, converts it back and write it to the client. func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -151,7 +187,7 @@ func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - msg, err := doh.RequestToMsg(r) + msg, raw, err := doh.RequestToMsgWire(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) s.countResponse(http.StatusBadRequest) @@ -162,11 +198,21 @@ func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) { h, p, _ := net.SplitHostPort(r.RemoteAddr) port, _ := strconv.Atoi(p) dw := &DoHWriter{ - laddr: s.listenAddr, + laddr: s.localAddr(r), raddr: &net.TCPAddr{IP: net.ParseIP(h), Port: port}, request: r, } + if tsig := msg.IsTsig(); tsig != nil { + if s.tsigSecret == nil { + dw.tsigStatus = dns.ErrSecret + } else if secret, ok := s.tsigSecret[tsig.Hdr.Name]; !ok { + dw.tsigStatus = dns.ErrSecret + } else { + dw.tsigStatus = dns.TsigVerify(raw, secret, "", false) + } + } + // We just call the normal chain handler - all error handling is done there. // We should expect a packet to be returned that we can send to the client. @@ -190,7 +236,7 @@ func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) { buf, _ := dw.Msg.Pack() mt, _ := response.Typify(dw.Msg, time.Now().UTC()) - age := dnsutil.MinimalTTL(dw.Msg, mt) + age := dnsutil.MinimalTTLWithMaximum(dw.Msg, mt, dnsutil.MaximumDefaultTTL) w.Header().Set("Content-Type", doh.MimeType) w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", uint32(age.Seconds()))) diff --git a/core/dnsserver/server_https3.go b/core/dnsserver/server_https3.go new file mode 100644 index 0000000000..b43fc7cd8b --- /dev/null +++ b/core/dnsserver/server_https3.go @@ -0,0 +1,232 @@ +package dnsserver + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "net/http" + "strconv" + "time" + + "github.com/coredns/caddy" + "github.com/coredns/coredns/plugin/metrics/vars" + "github.com/coredns/coredns/plugin/pkg/dnsutil" + "github.com/coredns/coredns/plugin/pkg/doh" + cproxyproto "github.com/coredns/coredns/plugin/pkg/proxyproto" + "github.com/coredns/coredns/plugin/pkg/response" + "github.com/coredns/coredns/plugin/pkg/reuseport" + "github.com/coredns/coredns/plugin/pkg/transport" + + "github.com/miekg/dns" + "github.com/quic-go/quic-go" + "github.com/quic-go/quic-go/http3" +) + +const ( + // DefaultHTTPS3MaxStreams is the default maximum number of concurrent QUIC streams per connection. + DefaultHTTPS3MaxStreams = 256 + // DefaultHTTPS3MaxHeaderBytes limits HTTP/3 header memory before requests reach the DoH handler. + DefaultHTTPS3MaxHeaderBytes = 16 << 10 // 16 KiB +) + +// ServerHTTPS3 represents a DNS-over-HTTP/3 server. +type ServerHTTPS3 struct { + *Server + httpsServer *http3.Server + listenAddr net.Addr + tlsConfig *tls.Config + quicConfig *quic.Config + validRequest func(*http.Request) bool + maxStreams int +} + +// NewServerHTTPS3 builds the HTTP/3 (DoH3) server. +func NewServerHTTPS3(addr string, group []*Config) (*ServerHTTPS3, error) { + s, err := NewServer(addr, group) + if err != nil { + return nil, err + } + + // Extract TLS config (CoreDNS guarantees it is consistent) + var tlsConfig *tls.Config + for _, z := range s.zones { + for _, conf := range z { + tlsConfig = conf.TLSConfig + } + } + if tlsConfig == nil { + return nil, fmt.Errorf("DoH3 requires TLS, no TLS config found") + } + + // HTTP/3 requires ALPN "h3" + tlsConfig.NextProtos = []string{"h3"} + + // Request validator + var validator func(*http.Request) bool + for _, z := range s.zones { + for _, conf := range z { + validator = conf.HTTPRequestValidateFunc + } + } + if validator == nil { + validator = func(r *http.Request) bool { return r.URL.Path == doh.Path } + } + + maxStreams := DefaultHTTPS3MaxStreams + if len(group) > 0 && group[0] != nil && group[0].MaxHTTPS3Streams != nil { + maxStreams = *group[0].MaxHTTPS3Streams + } + + // QUIC transport config with stream limits (0 means use QUIC default) + qconf := &quic.Config{ + MaxIdleTimeout: s.IdleTimeout, + Allow0RTT: true, + } + if maxStreams > 0 { + qconf.MaxIncomingStreams = int64(maxStreams) + qconf.MaxIncomingUniStreams = int64(maxStreams) + } + + h3srv := &http3.Server{ + Handler: nil, // set after constructing ServerHTTPS3 + TLSConfig: tlsConfig, + EnableDatagrams: true, + QUICConfig: qconf, + MaxHeaderBytes: DefaultHTTPS3MaxHeaderBytes, + // Logger: stdlog.New(&loggerAdapter{}, "", 0), TODO: Fix it + } + + sh := &ServerHTTPS3{ + Server: s, + tlsConfig: tlsConfig, + httpsServer: h3srv, + quicConfig: qconf, + validRequest: validator, + maxStreams: maxStreams, + } + + h3srv.Handler = sh + + return sh, nil +} + +var _ caddy.GracefulServer = &ServerHTTPS3{} + +// ListenPacket opens the UDP socket for QUIC. +func (s *ServerHTTPS3) ListenPacket() (net.PacketConn, error) { + p, err := reuseport.ListenPacket("udp", s.Addr[len(transport.HTTPS3+"://"):]) + if err != nil { + return nil, err + } + if s.connPolicy != nil { + p = &cproxyproto.PacketConn{PacketConn: p, ConnPolicy: s.connPolicy} + } + return p, nil +} + +// ServePacket starts serving QUIC+HTTP/3 on an existing UDP socket. +func (s *ServerHTTPS3) ServePacket(pc net.PacketConn) error { + s.m.Lock() + s.listenAddr = pc.LocalAddr() + s.m.Unlock() + // Serve HTTP/3 over QUIC + return s.httpsServer.Serve(pc) +} + +// Listen function not used in HTTP/3, but defined for compatibility +func (s *ServerHTTPS3) Listen() (net.Listener, error) { return nil, nil } +func (s *ServerHTTPS3) Serve(_l net.Listener) error { return nil } + +// OnStartupComplete lists the sites served by this server +// and any relevant information, assuming Quiet is false. +func (s *ServerHTTPS3) OnStartupComplete() { + if Quiet { + return + } + out := startUpZones(transport.HTTPS3+"://", s.Addr, s.zones) + if out != "" { + fmt.Print(out) + } +} + +// Stop graceful shutdown. It blocks until the server is totally stopped. +func (s *ServerHTTPS3) Stop() error { + s.m.Lock() + defer s.m.Unlock() + if s.httpsServer != nil { + return s.httpsServer.Shutdown(context.Background()) + } + return nil +} + +// Shutdown stops the server (non gracefully). +func (s *ServerHTTPS3) Shutdown() error { + if s.httpsServer != nil { + s.httpsServer.Shutdown(context.Background()) + } + return nil +} + +// ServeHTTP is the handler for the DoH3 requests +func (s *ServerHTTPS3) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if !s.validRequest(r) { + http.Error(w, "", http.StatusNotFound) + s.countResponse(http.StatusNotFound) + return + } + + msg, raw, err := doh.RequestToMsgWire(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + s.countResponse(http.StatusBadRequest) + return + } + + // from HTTP request → DNS writer + h, p, _ := net.SplitHostPort(r.RemoteAddr) + port, _ := strconv.Atoi(p) + dw := &DoHWriter{ + laddr: s.listenAddr, + raddr: &net.UDPAddr{IP: net.ParseIP(h), Port: port}, + request: r, + } + + if tsig := msg.IsTsig(); tsig != nil { + if s.tsigSecret == nil { + dw.tsigStatus = dns.ErrSecret + } else if secret, ok := s.tsigSecret[tsig.Hdr.Name]; !ok { + dw.tsigStatus = dns.ErrSecret + } else { + dw.tsigStatus = dns.TsigVerify(raw, secret, "", false) + } + } + + ctx := context.WithValue(r.Context(), Key{}, s.Server) + ctx = context.WithValue(ctx, LoopKey{}, 0) + ctx = context.WithValue(ctx, HTTPRequestKey{}, r) + + s.ServeDNS(ctx, dw, msg) + + if dw.Msg == nil { + http.Error(w, "No response", http.StatusInternalServerError) + s.countResponse(http.StatusInternalServerError) + return + } + + buf, _ := dw.Msg.Pack() + mt, _ := response.Typify(dw.Msg, time.Now().UTC()) + age := dnsutil.MinimalTTLWithMaximum(dw.Msg, mt, dnsutil.MaximumDefaultTTL) + + w.Header().Set("Content-Type", doh.MimeType) + w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", uint32(age.Seconds()))) + w.Header().Set("Content-Length", strconv.Itoa(len(buf))) + w.WriteHeader(http.StatusOK) + + s.countResponse(http.StatusOK) + w.Write(buf) +} + +func (s *ServerHTTPS3) countResponse(status int) { + vars.HTTPS3ResponsesCount.WithLabelValues(s.Addr, strconv.Itoa(status)).Inc() +} diff --git a/core/dnsserver/server_https3_test.go b/core/dnsserver/server_https3_test.go new file mode 100644 index 0000000000..8025c8ce1c --- /dev/null +++ b/core/dnsserver/server_https3_test.go @@ -0,0 +1,349 @@ +package dnsserver + +import ( + "bytes" + "crypto/tls" + "errors" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/coredns/coredns/plugin" + + "github.com/miekg/dns" +) + +const ( + testTSIGKeyNameHTTPS3 = "tsig-key." + testTSIGSecretHTTPS3 = "MTIzNA==" + testTSIGWrongSecretHTTPS3 = "NTY3OA==" +) + +func testServerHTTPS3(t *testing.T, path string, validator func(*http.Request) bool) *http.Response { + t.Helper() + c := Config{ + Zone: "example.com.", + Transport: "https", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + HTTPRequestValidateFunc: validator, + } + s, err := NewServerHTTPS3("127.0.0.1:443", []*Config{&c}) + if err != nil { + t.Log(err) + t.Fatal("could not create HTTPS3 server") + } + m := new(dns.Msg) + m.SetQuestion("example.org.", dns.TypeDNSKEY) + buf, err := m.Pack() + if err != nil { + t.Fatal(err) + } + + r := httptest.NewRequest(http.MethodPost, path, bytes.NewReader(buf)) + w := httptest.NewRecorder() + s.ServeHTTP(w, r) + + return w.Result() +} + +func TestCustomHTTP3RequestValidator(t *testing.T) { + testCases := map[string]struct { + path string + expected int + validator func(*http.Request) bool + }{ + "default": {"/dns-query", http.StatusOK, nil}, + "custom validator": {"/b10cada", http.StatusOK, validator}, + "no validator set": {"/adb10c", http.StatusNotFound, nil}, + "invalid path with validator": {"/helloworld", http.StatusNotFound, validator}, + } + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + res := testServerHTTPS3(t, tc.path, tc.validator) + if res.StatusCode != tc.expected { + t.Error("unexpected HTTP code", res.StatusCode) + } + res.Body.Close() + }) + } +} + +func TestNewServerHTTPS3WithCustomLimits(t *testing.T) { + maxStreams := 50 + c := Config{ + Zone: "example.com.", + Transport: "https3", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + MaxHTTPS3Streams: &maxStreams, + } + + server, err := NewServerHTTPS3("127.0.0.1:443", []*Config{&c}) + if err != nil { + t.Fatalf("NewServerHTTPS3() with custom limits failed: %v", err) + } + + if server.maxStreams != maxStreams { + t.Errorf("Expected maxStreams = %d, got %d", maxStreams, server.maxStreams) + } + + expectedMaxStreams := int64(maxStreams) + if server.quicConfig.MaxIncomingStreams != expectedMaxStreams { + t.Errorf("Expected quicConfig.MaxIncomingStreams = %d, got %d", expectedMaxStreams, server.quicConfig.MaxIncomingStreams) + } + + if server.quicConfig.MaxIncomingUniStreams != expectedMaxStreams { + t.Errorf("Expected quicConfig.MaxIncomingUniStreams = %d, got %d", expectedMaxStreams, server.quicConfig.MaxIncomingUniStreams) + } +} + +func TestNewServerHTTPS3Defaults(t *testing.T) { + c := Config{ + Zone: "example.com.", + Transport: "https3", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + } + + server, err := NewServerHTTPS3("127.0.0.1:443", []*Config{&c}) + if err != nil { + t.Fatalf("NewServerHTTPS3() failed: %v", err) + } + + if server.maxStreams != DefaultHTTPS3MaxStreams { + t.Errorf("Expected default maxStreams = %d, got %d", DefaultHTTPS3MaxStreams, server.maxStreams) + } + + expectedMaxStreams := int64(DefaultHTTPS3MaxStreams) + if server.quicConfig.MaxIncomingStreams != expectedMaxStreams { + t.Errorf("Expected default quicConfig.MaxIncomingStreams = %d, got %d", expectedMaxStreams, server.quicConfig.MaxIncomingStreams) + } +} + +func TestNewServerHTTPS3ZeroLimits(t *testing.T) { + zero := 0 + c := Config{ + Zone: "example.com.", + Transport: "https3", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + MaxHTTPS3Streams: &zero, + } + + server, err := NewServerHTTPS3("127.0.0.1:443", []*Config{&c}) + if err != nil { + t.Fatalf("NewServerHTTPS3() with zero limits failed: %v", err) + } + + if server.maxStreams != 0 { + t.Errorf("Expected maxStreams = 0, got %d", server.maxStreams) + } + // When maxStreams is 0, quicConfig should not set MaxIncomingStreams (uses QUIC default) + if server.quicConfig.MaxIncomingStreams != 0 { + t.Errorf("Expected quicConfig.MaxIncomingStreams = 0 (QUIC default), got %d", server.quicConfig.MaxIncomingStreams) + } +} + +func TestNewServerHTTPS3DefaultMaxHeaderBytes(t *testing.T) { + c := Config{ + Zone: "example.com.", + Transport: "https3", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + } + + server, err := NewServerHTTPS3("127.0.0.1:443", []*Config{&c}) + if err != nil { + t.Fatalf("NewServerHTTPS3() failed: %v", err) + } + + if server.httpsServer.MaxHeaderBytes != DefaultHTTPS3MaxHeaderBytes { + t.Errorf("expected MaxHeaderBytes = %d, got %d", + DefaultHTTPS3MaxHeaderBytes, + server.httpsServer.MaxHeaderBytes) + } +} + +func testConfigWithTSIGCheckPluginHTTPS3(t *testing.T, check func(*testing.T, error)) *Config { + t.Helper() + + c := &Config{ + Zone: "example.com.", + Transport: "https3", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + TsigSecret: map[string]string{ + testTSIGKeyNameHTTPS3: testTSIGSecretHTTPS3, + }, + } + c.AddPlugin(func(_next plugin.Handler) plugin.Handler { + return tsigStatusCheckPlugin{t: t, check: check} + }) + return c +} + +func testServerHTTPS3Msg(t *testing.T, cfg *Config, req *dns.Msg) *dns.Msg { + t.Helper() + + s, err := NewServerHTTPS3("127.0.0.1:443", []*Config{cfg}) + if err != nil { + t.Fatal("could not create HTTPS3 server:", err) + } + + buf, err := req.Pack() + if err != nil { + t.Fatal(err) + } + + r := httptest.NewRequest(http.MethodPost, "/dns-query", bytes.NewReader(buf)) + r.RemoteAddr = "127.0.0.1:12345" + w := httptest.NewRecorder() + + s.ServeHTTP(w, r) + + res := w.Result() + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + t.Fatalf("unexpected HTTP status: got %d", res.StatusCode) + } + + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + + m := new(dns.Msg) + if err := m.Unpack(body); err != nil { + t.Fatal(err) + } + return m +} + +func testServerHTTPS3Raw(t *testing.T, cfg *Config, buf []byte) *dns.Msg { + t.Helper() + + s, err := NewServerHTTPS3("127.0.0.1:443", []*Config{cfg}) + if err != nil { + t.Fatal("could not create HTTPS3 server:", err) + } + + r := httptest.NewRequest(http.MethodPost, "/dns-query", bytes.NewReader(buf)) + r.RemoteAddr = "127.0.0.1:12345" + w := httptest.NewRecorder() + + s.ServeHTTP(w, r) + + res := w.Result() + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + t.Fatalf("unexpected HTTP status: got %d", res.StatusCode) + } + + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + + m := new(dns.Msg) + if err := m.Unpack(body); err != nil { + t.Fatal(err) + } + return m +} + +func forgedTSIGMsgHTTPS3() *dns.Msg { + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + + m.Extra = append(m.Extra, &dns.TSIG{ + Hdr: dns.RR_Header{ + Name: "bogus-key.", + Rrtype: dns.TypeTSIG, + Class: dns.ClassANY, + Ttl: 0, + }, + Algorithm: dns.HmacSHA256, + TimeSigned: uint64(time.Now().Unix()), + Fudge: 300, + MACSize: 32, + MAC: strings.Repeat("00", 32), + OrigId: m.Id, + Error: dns.RcodeSuccess, + }) + return m +} + +func TestServeHTTP3RejectsUnsignedTSIGRequiredRequest(t *testing.T) { + cfg := testConfigWithTSIGCheckPluginHTTPS3(t, func(t *testing.T, err error) { + t.Helper() + if err != nil { + t.Fatalf("expected nil TsigStatus for unsigned request, got %v", err) + } + }) + + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + resp := testServerHTTPS3Msg(t, cfg, m) + + if resp.Rcode != dns.RcodeSuccess { + t.Fatalf("expected NOERROR response from plugin, got %s", dns.RcodeToString[resp.Rcode]) + } +} + +func TestServeHTTP3RejectsTSIGWithUnknownKey(t *testing.T) { + cfg := testConfigWithTSIGCheckPluginHTTPS3(t, func(t *testing.T, err error) { + t.Helper() + if !errors.Is(err, dns.ErrSecret) { + t.Fatalf("expected dns.ErrSecret for unknown TSIG key, got %v", err) + } + }) + + resp := testServerHTTPS3Msg(t, cfg, forgedTSIGMsgHTTPS3()) + if resp.Rcode != dns.RcodeSuccess { + t.Fatalf("expected NOERROR response from plugin, got %s", dns.RcodeToString[resp.Rcode]) + } +} + +func TestServeHTTP3RejectsTSIGWithBadMAC(t *testing.T) { + cfg := testConfigWithTSIGCheckPluginHTTPS3(t, func(t *testing.T, err error) { + t.Helper() + if err == nil { + t.Fatal("expected non-nil TsigStatus for bad TSIG MAC") + } + }) + + buf := mustPackSignedTSIGQuery(t, testTSIGKeyNameHTTPS3, testTSIGWrongSecretHTTPS3, time.Now().Unix()) + resp := testServerHTTPS3Raw(t, cfg, buf) + + if resp.Rcode != dns.RcodeSuccess { + t.Fatalf("expected NOERROR response from plugin, got %s", dns.RcodeToString[resp.Rcode]) + } +} + +func TestServeHTTP3AcceptsValidTSIG(t *testing.T) { + cfg := testConfigWithTSIGCheckPluginHTTPS3(t, func(t *testing.T, err error) { + t.Helper() + if err != nil { + t.Fatalf("expected nil TsigStatus for valid TSIG, got %v", err) + } + }) + + buf := mustPackSignedTSIGQuery(t, testTSIGKeyNameHTTPS3, testTSIGSecretHTTPS3, time.Now().Unix()) + resp := testServerHTTPS3Raw(t, cfg, buf) + + if resp.Rcode != dns.RcodeSuccess { + t.Fatalf("expected NOERROR response from plugin, got %s", dns.RcodeToString[resp.Rcode]) + } +} diff --git a/core/dnsserver/server_https_test.go b/core/dnsserver/server_https_test.go index 5d062e168e..525348aa9d 100644 --- a/core/dnsserver/server_https_test.go +++ b/core/dnsserver/server_https_test.go @@ -5,9 +5,11 @@ import ( "context" "crypto/tls" "io" + "net" "net/http" "net/http/httptest" "regexp" + "strings" "testing" "time" @@ -21,6 +23,12 @@ var ( validator = func(r *http.Request) bool { return validPath.MatchString(r.URL.Path) } ) +const ( + testTSIGKeyName = "tsig-key." + testTSIGSecret = "MTIzNA==" + testTSIGWrongSecret = "NTY3OA==" +) + func testServerHTTPS(t *testing.T, path string, validator func(*http.Request) bool) *http.Response { t.Helper() c := Config{ @@ -72,6 +80,67 @@ func TestCustomHTTPRequestValidator(t *testing.T) { } } +func TestNewServerHTTPSWithCustomLimits(t *testing.T) { + maxConnections := 100 + c := Config{ + Zone: "example.com.", + Transport: "https", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + MaxHTTPSConnections: &maxConnections, + } + + server, err := NewServerHTTPS("127.0.0.1:443", []*Config{&c}) + if err != nil { + t.Fatalf("NewServerHTTPS() with custom limits failed: %v", err) + } + + if server.maxConnections != maxConnections { + t.Errorf("Expected maxConnections = %d, got %d", maxConnections, server.maxConnections) + } +} + +func TestNewServerHTTPSDefaults(t *testing.T) { + c := Config{ + Zone: "example.com.", + Transport: "https", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + } + + server, err := NewServerHTTPS("127.0.0.1:443", []*Config{&c}) + if err != nil { + t.Fatalf("NewServerHTTPS() failed: %v", err) + } + + if server.maxConnections != DefaultHTTPSMaxConnections { + t.Errorf("Expected default maxConnections = %d, got %d", DefaultHTTPSMaxConnections, server.maxConnections) + } +} + +func TestNewServerHTTPSZeroLimits(t *testing.T) { + zero := 0 + c := Config{ + Zone: "example.com.", + Transport: "https", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + MaxHTTPSConnections: &zero, + } + + server, err := NewServerHTTPS("127.0.0.1:443", []*Config{&c}) + if err != nil { + t.Fatalf("NewServerHTTPS() with zero limits failed: %v", err) + } + + if server.maxConnections != 0 { + t.Errorf("Expected maxConnections = 0, got %d", server.maxConnections) + } +} + type contextCapturingPlugin struct { capturedContext context.Context contextCancelled bool @@ -102,7 +171,110 @@ func testConfigWithPlugin(p *contextCapturingPlugin) *Config { ListenHosts: []string{"127.0.0.1"}, Port: "443", } - c.AddPlugin(func(next plugin.Handler) plugin.Handler { return p }) + c.AddPlugin(func(_next plugin.Handler) plugin.Handler { return p }) + return c +} + +func TestDoHWriterLaddrFromConnContext(t *testing.T) { + capturer := &addrCapturingPlugin{} + cfg := testConfigWithHandler(capturer) + + s, err := NewServerHTTPS("127.0.0.1:443", []*Config{cfg}) + if err != nil { + t.Fatal("could not create HTTPS server:", err) + } + s.listenAddr = &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 443} + + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + buf, err := m.Pack() + if err != nil { + t.Fatal(err) + } + + // Simulate a PROXY protocol destination that differs from listenAddr. + ppDst := &net.TCPAddr{IP: net.ParseIP("10.0.0.1"), Port: 443} + + r := httptest.NewRequest(http.MethodPost, "/dns-query", io.NopCloser(bytes.NewReader(buf))) + ctx := context.WithValue(r.Context(), http.LocalAddrContextKey, ppDst) + r = r.WithContext(ctx) + w := httptest.NewRecorder() + + s.ServeHTTP(w, r) + + if !capturer.called { + t.Fatal("plugin was not called") + } + if capturer.localAddr == nil { + t.Fatal("DoHWriter.laddr is nil") + } + if capturer.localAddr.String() != ppDst.String() { + t.Errorf("expected laddr %s (PP destination), got %s", ppDst, capturer.localAddr) + } +} + +func TestDoHWriterLaddrFallback(t *testing.T) { + capturer := &addrCapturingPlugin{} + cfg := testConfigWithHandler(capturer) + + s, err := NewServerHTTPS("127.0.0.1:443", []*Config{cfg}) + if err != nil { + t.Fatal("could not create HTTPS server:", err) + } + s.listenAddr = &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 443} + + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + buf, err := m.Pack() + if err != nil { + t.Fatal(err) + } + + // No LocalAddrContextKey in context; should fall back to s.listenAddr. + r := httptest.NewRequest(http.MethodPost, "/dns-query", io.NopCloser(bytes.NewReader(buf))) + w := httptest.NewRecorder() + + s.ServeHTTP(w, r) + + if !capturer.called { + t.Fatal("plugin was not called") + } + if capturer.localAddr == nil { + t.Fatal("DoHWriter.laddr is nil") + } + if capturer.localAddr.String() != s.listenAddr.String() { + t.Errorf("expected fallback laddr %s, got %s", s.listenAddr, capturer.localAddr) + } +} + +type addrCapturingPlugin struct { + called bool + localAddr net.Addr + remoteAddr net.Addr +} + +func (p *addrCapturingPlugin) ServeDNS(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + p.called = true + p.localAddr = w.LocalAddr() + p.remoteAddr = w.RemoteAddr() + m := new(dns.Msg) + m.SetReply(r) + m.Authoritative = true + w.WriteMsg(m) + return dns.RcodeSuccess, nil +} + +func (p *addrCapturingPlugin) Name() string { return "addr_capturing" } + +func testConfigWithHandler(h plugin.Handler) *Config { + c := &Config{ + Zone: "example.com.", + Transport: "https", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + } + c.AddPlugin(func(_next plugin.Handler) plugin.Handler { return h }) return c } @@ -231,3 +403,183 @@ func TestHTTPRequestContextPropagation(t *testing.T) { } }) } + +type tsigStatusPlugin struct{} + +func (p *tsigStatusPlugin) ServeDNS(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + m := new(dns.Msg) + m.SetReply(r) + m.Authoritative = true + + switch { + case r.IsTsig() == nil: + m.Rcode = dns.RcodeRefused + case w.TsigStatus() != nil: + m.Rcode = dns.RcodeNotAuth + default: + m.Rcode = dns.RcodeSuccess + } + + if err := w.WriteMsg(m); err != nil { + return dns.RcodeServerFailure, err + } + return dns.RcodeSuccess, nil +} + +func (p *tsigStatusPlugin) Name() string { return "tsig_status" } + +func testConfigWithTSIGStatusPlugin() *Config { + c := &Config{ + Zone: "example.com.", + Transport: "https", + TLSConfig: &tls.Config{}, + ListenHosts: []string{"127.0.0.1"}, + Port: "443", + TsigSecret: map[string]string{ + testTSIGKeyName: testTSIGSecret, + }, + } + c.AddPlugin(func(_next plugin.Handler) plugin.Handler { return &tsigStatusPlugin{} }) + return c +} + +func testServerHTTPSMsg(t *testing.T, cfg *Config, req *dns.Msg) *dns.Msg { + t.Helper() + + s, err := NewServerHTTPS("127.0.0.1:443", []*Config{cfg}) + if err != nil { + t.Fatal("could not create HTTPS server:", err) + } + + buf, err := req.Pack() + if err != nil { + t.Fatal(err) + } + + r := httptest.NewRequest(http.MethodPost, "/dns-query", bytes.NewReader(buf)) + r.RemoteAddr = "127.0.0.1:12345" + w := httptest.NewRecorder() + + s.ServeHTTP(w, r) + + res := w.Result() + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + t.Fatalf("unexpected HTTP status: got %d", res.StatusCode) + } + + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + + m := new(dns.Msg) + if err := m.Unpack(body); err != nil { + t.Fatal(err) + } + return m +} + +func testServerHTTPSRaw(t *testing.T, cfg *Config, buf []byte) *dns.Msg { + t.Helper() + + s, err := NewServerHTTPS("127.0.0.1:443", []*Config{cfg}) + if err != nil { + t.Fatal("could not create HTTPS server:", err) + } + + r := httptest.NewRequest(http.MethodPost, "/dns-query", bytes.NewReader(buf)) + r.RemoteAddr = "127.0.0.1:12345" + w := httptest.NewRecorder() + + s.ServeHTTP(w, r) + + res := w.Result() + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + t.Fatalf("unexpected HTTP status: got %d", res.StatusCode) + } + + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + + m := new(dns.Msg) + if err := m.Unpack(body); err != nil { + t.Fatal(err) + } + return m +} + +func forgedTSIGMsg() *dns.Msg { + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + + m.Extra = append(m.Extra, &dns.TSIG{ + Hdr: dns.RR_Header{ + Name: "bogus-key.", + Rrtype: dns.TypeTSIG, + Class: dns.ClassANY, + Ttl: 0, + }, + Algorithm: dns.HmacSHA256, + TimeSigned: uint64(time.Now().Unix()), + Fudge: 300, + MACSize: 32, + MAC: strings.Repeat("00", 32), + OrigId: m.Id, + Error: dns.RcodeSuccess, + }) + return m +} + +func mustSignedTSIGQueryBytes(t *testing.T, keyName, secret string) []byte { + t.Helper() + return mustPackSignedTSIGQuery(t, keyName, secret, time.Now().Unix()) +} + +func TestServeHTTPRejectsUnsignedTSIGRequiredRequest(t *testing.T) { + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + + resp := testServerHTTPSMsg(t, testConfigWithTSIGStatusPlugin(), m) + if resp.Rcode != dns.RcodeRefused { + t.Fatalf("expected REFUSED for unsigned request, got %s", dns.RcodeToString[resp.Rcode]) + } +} + +func TestServeHTTPRejectsTSIGWithUnknownKey(t *testing.T) { + resp := testServerHTTPSMsg(t, testConfigWithTSIGStatusPlugin(), forgedTSIGMsg()) + + if resp.Rcode != dns.RcodeNotAuth { + t.Fatalf("expected NOTAUTH for unknown TSIG key, got %s", dns.RcodeToString[resp.Rcode]) + } +} + +func TestServeHTTPRejectsTSIGWithBadMAC(t *testing.T) { + buf := mustSignedTSIGQueryBytes(t, testTSIGKeyName, testTSIGWrongSecret) + + resp := testServerHTTPSRaw(t, testConfigWithTSIGStatusPlugin(), buf) + if resp.Rcode != dns.RcodeNotAuth { + t.Fatalf("expected NOTAUTH for bad TSIG MAC, got %s", dns.RcodeToString[resp.Rcode]) + } +} + +func TestServeHTTPAcceptsValidTSIG(t *testing.T) { + buf := mustSignedTSIGQueryBytes(t, testTSIGKeyName, testTSIGSecret) + + resp := testServerHTTPSRaw(t, testConfigWithTSIGStatusPlugin(), buf) + if resp.Rcode != dns.RcodeSuccess { + t.Fatalf("expected NOERROR for valid TSIG, got %s", dns.RcodeToString[resp.Rcode]) + } +} + +func TestDoHWriterTsigStatusReturnsStoredStatus(t *testing.T) { + dw := &DoHWriter{tsigStatus: dns.ErrSecret} + if dw.TsigStatus() != dns.ErrSecret { + t.Fatal("expected TsigStatus to return stored tsigStatus") + } +} diff --git a/core/dnsserver/server_quic.go b/core/dnsserver/server_quic.go index 531cbd82d9..6a5c0929ec 100644 --- a/core/dnsserver/server_quic.go +++ b/core/dnsserver/server_quic.go @@ -11,6 +11,7 @@ import ( "github.com/coredns/coredns/plugin/metrics/vars" clog "github.com/coredns/coredns/plugin/pkg/log" + cproxyproto "github.com/coredns/coredns/plugin/pkg/proxyproto" "github.com/coredns/coredns/plugin/pkg/reuseport" "github.com/coredns/coredns/plugin/pkg/transport" @@ -103,6 +104,14 @@ func NewServerQUIC(addr string, group []*Config) (*ServerQUIC, error) { // ServePacket implements caddy.UDPServer interface. func (s *ServerQUIC) ServePacket(p net.PacketConn) error { s.m.Lock() + if s.quicListener == nil { + listener, err := quic.Listen(p, s.tlsConfig, s.quicConfig) + if err != nil { + s.m.Unlock() + return err + } + s.quicListener = listener + } s.listenAddr = s.quicListener.Addr() s.m.Unlock() @@ -127,6 +136,15 @@ func (s *ServerQUIC) ServeQUIC() error { } } +func acquireQUICWorker(ctx context.Context, pool chan struct{}) bool { + select { + case pool <- struct{}{}: + return true + case <-ctx.Done(): + return false + } +} + // serveQUICConnection handles a new QUIC connection. It waits for new streams // and passes them to serveQUICStream. func (s *ServerQUIC) serveQUICConnection(conn *quic.Conn) { @@ -148,10 +166,13 @@ func (s *ServerQUIC) serveQUICConnection(conn *quic.Conn) { return } - // Use a bounded worker pool - s.streamProcessPool <- struct{}{} // Acquire a worker slot, may block + if !acquireQUICWorker(conn.Context(), s.streamProcessPool) { + _ = stream.Close() + return + } + go func(st *quic.Stream, cn *quic.Conn) { - defer func() { <-s.streamProcessPool }() // Release worker slot + defer func() { <-s.streamProcessPool }() s.serveQUICStream(st, cn) }(stream, conn) } @@ -200,9 +221,20 @@ func (s *ServerQUIC) serveQUICStream(stream *quic.Stream, conn *quic.Conn) { localAddr: conn.LocalAddr(), remoteAddr: conn.RemoteAddr(), stream: stream, + conn: conn, Msg: req, } + if tsig := req.IsTsig(); tsig != nil { + if s.tsigSecret == nil { + w.tsigStatus = dns.ErrSecret + } else if secret, ok := s.tsigSecret[tsig.Hdr.Name]; !ok { + w.tsigStatus = dns.ErrSecret + } else { + w.tsigStatus = dns.TsigVerify(buf, secret, "", false) + } + } + dnsCtx := context.WithValue(stream.Context(), Key{}, s.Server) dnsCtx = context.WithValue(dnsCtx, LoopKey{}, 0) s.ServeDNS(dnsCtx, w, req) @@ -216,6 +248,10 @@ func (s *ServerQUIC) ListenPacket() (net.PacketConn, error) { return nil, err } + if s.connPolicy != nil { + p = &cproxyproto.PacketConn{PacketConn: p, ConnPolicy: s.connPolicy} + } + s.m.Lock() defer s.m.Unlock() @@ -253,7 +289,7 @@ func (s *ServerQUIC) Stop() error { } // Serve implements caddy.TCPServer interface. -func (s *ServerQUIC) Serve(l net.Listener) error { return nil } +func (s *ServerQUIC) Serve(_l net.Listener) error { return nil } // Listen implements caddy.TCPServer interface. func (s *ServerQUIC) Listen() (net.Listener, error) { return nil, nil } @@ -338,7 +374,7 @@ func readDOQMessage(r io.Reader) ([]byte, error) { // A client or server receives a STREAM FIN before receiving all the bytes // for a message indicated in the 2-octet length field. // See https://www.rfc-editor.org/rfc/rfc9250#section-4.3.3-2.2 - if size != uint16(len(buf)) { + if size != uint16(len(buf)) { // #nosec G115 -- buf length fits in uint16 return nil, fmt.Errorf("message size does not match 2-byte prefix") } diff --git a/core/dnsserver/server_quic_test.go b/core/dnsserver/server_quic_test.go index 8deb11c7c2..76d592d866 100644 --- a/core/dnsserver/server_quic_test.go +++ b/core/dnsserver/server_quic_test.go @@ -2,9 +2,18 @@ package dnsserver import ( "bytes" + "context" + "crypto/rand" + "crypto/rsa" "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" "errors" + "math/big" "testing" + "time" + + "github.com/coredns/coredns/plugin/pkg/transport" "github.com/miekg/dns" "github.com/quic-go/quic-go" @@ -400,3 +409,399 @@ func TestAddPrefix(t *testing.T) { }) } } + +func TestAcquireQUICWorkerWaitsForSlot(t *testing.T) { + pool := make(chan struct{}, 1) + pool <- struct{}{} + + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + + done := make(chan bool, 1) + go func() { + done <- acquireQUICWorker(ctx, pool) + }() + + select { + case <-done: + t.Fatal("acquireQUICWorker returned before a slot was released") + default: + } + + <-pool + + got := <-done + if !got { + t.Fatal("expected acquireQUICWorker to succeed after slot release") + } +} + +func TestAcquireQUICWorkerReturnsFalseOnCancelledContext(t *testing.T) { + pool := make(chan struct{}, 1) + pool <- struct{}{} + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + if got := acquireQUICWorker(ctx, pool); got { + t.Fatal("expected acquireQUICWorker to return false when context is cancelled") + } +} + +func TestDoQWriterTsigStatusReturnsStoredStatus(t *testing.T) { + want := errors.New("bad tsig") + + w := &DoQWriter{ + tsigStatus: want, + } + + if got := w.TsigStatus(); got != want { + t.Fatalf("TsigStatus() = %v, want %v", got, want) + } +} + +func TestServerQUIC_ServeQUIC_TSIGBadSigSetsTsigStatus(t *testing.T) { + const keyName = "tsig-key." + const clientSecret = "MTIzNDU2Nzg5MDEyMzQ1Ng==" + const serverSecret = "QUJDREVGR0hJSktMTU5PUA==" + + called := make(chan struct{}, 1) + + config := testConfig("quic", tsigStatusCheckPlugin{ + t: t, + called: called, + check: func(t *testing.T, got error) { + t.Helper() + if got == nil { + t.Fatal("TsigStatus() = nil, want non-nil for bad TSIG MAC") + } + if errors.Is(got, dns.ErrSecret) { + t.Fatalf("TsigStatus() = %v, want signature verification error, not ErrSecret", got) + } + if errors.Is(got, dns.ErrTime) { + t.Fatalf("TsigStatus() = %v, want signature verification error, not ErrTime", got) + } + }, + }) + config.TLSConfig = mustMakeQUICServerTLSConfig(t) + + server, err := NewServerQUIC(transport.QUIC+"://127.0.0.1:0", []*Config{config}) + if err != nil { + t.Fatalf("NewServerQUIC() failed: %v", err) + } + + server.tsigSecret = map[string]string{ + keyName: serverSecret, + } + + pc, err := server.ListenPacket() + if err != nil { + t.Fatalf("ListenPacket() failed: %v", err) + } + defer pc.Close() + + serveErrCh := make(chan error, 1) + go func() { + serveErrCh <- server.ServeQUIC() + }() + + defer func() { + _ = server.Stop() + select { + case <-serveErrCh: + case <-time.After(2 * time.Second): + } + }() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + conn, err := quic.DialAddr(ctx, pc.LocalAddr().String(), mustMakeQUICClientTLSConfig(), &quic.Config{}) + if err != nil { + t.Fatalf("quic.DialAddr() failed: %v", err) + } + defer conn.CloseWithError(DoQCodeNoError, "") + + stream, err := conn.OpenStreamSync(ctx) + if err != nil { + t.Fatalf("OpenStreamSync() failed: %v", err) + } + + wire := mustPackSignedTSIGQuery(t, keyName, clientSecret, time.Now().Unix()) + + if _, err := stream.Write(AddPrefix(wire)); err != nil { + t.Fatalf("stream.Write() failed: %v", err) + } + if err := stream.Close(); err != nil { + t.Fatalf("stream.Close() failed: %v", err) + } + + respWire, err := readDOQMessage(stream) + if err != nil { + t.Fatalf("readDOQMessage() failed: %v", err) + } + + resp := new(dns.Msg) + if err := resp.Unpack(respWire); err != nil { + t.Fatalf("response unpack failed: %v", err) + } + + select { + case <-called: + case <-time.After(5 * time.Second): + t.Fatal("ServeDNS() was not called") + } +} + +func mustMakeQUICServerTLSConfig(t *testing.T) *tls.Config { + t.Helper() + + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("rsa.GenerateKey() failed: %v", err) + } + + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "127.0.0.1", + }, + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + DNSNames: []string{"localhost"}, + IPAddresses: nil, + } + + der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &priv.PublicKey, priv) + if err != nil { + t.Fatalf("x509.CreateCertificate() failed: %v", err) + } + + cert := tls.Certificate{ + Certificate: [][]byte{der}, + PrivateKey: priv, + } + + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + NextProtos: []string{"doq"}, + } +} + +func mustMakeQUICClientTLSConfig() *tls.Config { + return &tls.Config{ + InsecureSkipVerify: true, + NextProtos: []string{"doq"}, + } +} + +func TestServerQUIC_ServeQUIC_TSIGValidSigLeavesTsigStatusNil(t *testing.T) { + const keyName = "tsig-key." + const secret = "MTIzNDU2Nzg5MDEyMzQ1Ng==" + + called := make(chan struct{}, 1) + + config := testConfig("quic", tsigStatusCheckPlugin{ + t: t, + called: called, + check: func(t *testing.T, got error) { + t.Helper() + if got != nil { + t.Fatalf("TsigStatus() = %v, want nil for valid TSIG MAC", got) + } + }, + }) + config.TLSConfig = mustMakeQUICServerTLSConfig(t) + + server, err := NewServerQUIC(transport.QUIC+"://127.0.0.1:0", []*Config{config}) + if err != nil { + t.Fatalf("NewServerQUIC() failed: %v", err) + } + + server.tsigSecret = map[string]string{ + keyName: secret, + } + + pc, err := server.ListenPacket() + if err != nil { + t.Fatalf("ListenPacket() failed: %v", err) + } + defer pc.Close() + + serveErrCh := make(chan error, 1) + go func() { + serveErrCh <- server.ServeQUIC() + }() + + defer func() { + _ = server.Stop() + select { + case <-serveErrCh: + case <-time.After(2 * time.Second): + } + }() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + conn, err := quic.DialAddr(ctx, pc.LocalAddr().String(), mustMakeQUICClientTLSConfig(), &quic.Config{}) + if err != nil { + t.Fatalf("quic.DialAddr() failed: %v", err) + } + defer conn.CloseWithError(DoQCodeNoError, "") + + stream, err := conn.OpenStreamSync(ctx) + if err != nil { + t.Fatalf("OpenStreamSync() failed: %v", err) + } + + wire := mustPackSignedTSIGQuery(t, keyName, secret, time.Now().Unix()) + + if _, err := stream.Write(AddPrefix(wire)); err != nil { + t.Fatalf("stream.Write() failed: %v", err) + } + if err := stream.Close(); err != nil { + t.Fatalf("stream.Close() failed: %v", err) + } + + respWire, err := readDOQMessage(stream) + if err != nil { + t.Fatalf("readDOQMessage() failed: %v", err) + } + + resp := new(dns.Msg) + if err := resp.Unpack(respWire); err != nil { + t.Fatalf("response unpack failed: %v", err) + } + + select { + case <-called: + case <-time.After(5 * time.Second): + t.Fatal("ServeDNS() was not called") + } +} + +// connectionStateCapturePlugin records the *tls.ConnectionState observed via +// the dns.ConnectionStater interface implemented by the DoQ response writer. +type connectionStateCapturePlugin struct { + t *testing.T + called chan struct{} + state chan *tls.ConnectionState +} + +func (p connectionStateCapturePlugin) Name() string { return "connection-state-capture" } + +func (p connectionStateCapturePlugin) ServeDNS(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + p.t.Helper() + + if cs, ok := w.(dns.ConnectionStater); ok { + p.state <- cs.ConnectionState() + } else { + p.state <- nil + } + if p.called != nil { + p.called <- struct{}{} + } + + m := new(dns.Msg) + m.SetReply(r) + if err := w.WriteMsg(m); err != nil { + p.t.Fatalf("WriteMsg() failed: %v", err) + } + return dns.RcodeSuccess, nil +} + +func TestServerQUIC_ServeQUIC_ConnectionStateExposesSNI(t *testing.T) { + const sni = "doq.example.com" + + called := make(chan struct{}, 1) + stateCh := make(chan *tls.ConnectionState, 1) + + config := testConfig("quic", connectionStateCapturePlugin{ + t: t, + called: called, + state: stateCh, + }) + config.TLSConfig = mustMakeQUICServerTLSConfig(t) + + server, err := NewServerQUIC(transport.QUIC+"://127.0.0.1:0", []*Config{config}) + if err != nil { + t.Fatalf("NewServerQUIC() failed: %v", err) + } + + pc, err := server.ListenPacket() + if err != nil { + t.Fatalf("ListenPacket() failed: %v", err) + } + defer pc.Close() + + serveErrCh := make(chan error, 1) + go func() { + serveErrCh <- server.ServeQUIC() + }() + + defer func() { + _ = server.Stop() + select { + case <-serveErrCh: + case <-time.After(2 * time.Second): + } + }() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + clientTLS := mustMakeQUICClientTLSConfig() + clientTLS.ServerName = sni + + conn, err := quic.DialAddr(ctx, pc.LocalAddr().String(), clientTLS, &quic.Config{}) + if err != nil { + t.Fatalf("quic.DialAddr() failed: %v", err) + } + defer conn.CloseWithError(DoQCodeNoError, "") + + stream, err := conn.OpenStreamSync(ctx) + if err != nil { + t.Fatalf("OpenStreamSync() failed: %v", err) + } + + q := new(dns.Msg) + q.SetQuestion("example.com.", dns.TypeA) + q.Id = 0 + wire, err := q.Pack() + if err != nil { + t.Fatalf("dns.Msg.Pack() failed: %v", err) + } + + if _, err := stream.Write(AddPrefix(wire)); err != nil { + t.Fatalf("stream.Write() failed: %v", err) + } + if err := stream.Close(); err != nil { + t.Fatalf("stream.Close() failed: %v", err) + } + + if _, err := readDOQMessage(stream); err != nil { + t.Fatalf("readDOQMessage() failed: %v", err) + } + + select { + case <-called: + case <-time.After(5 * time.Second): + t.Fatal("ServeDNS() was not called") + } + + select { + case state := <-stateCh: + if state == nil { + t.Fatal("ConnectionState() = nil, want non-nil TLS state for DoQ request") + } + if state.ServerName != sni { + t.Errorf("ConnectionState().ServerName = %q, want %q", state.ServerName, sni) + } + case <-time.After(5 * time.Second): + t.Fatal("did not receive connection state from plugin") + } +} diff --git a/core/dnsserver/server_test.go b/core/dnsserver/server_test.go index fef01faed4..36395fcacf 100644 --- a/core/dnsserver/server_test.go +++ b/core/dnsserver/server_test.go @@ -17,7 +17,7 @@ import ( type testPlugin struct{} -func (tp testPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { +func (tp testPlugin) ServeDNS(_ctx context.Context, _w dns.ResponseWriter, _r *dns.Msg) (int, error) { return 0, nil } @@ -30,7 +30,7 @@ type blockingPlugin struct { func (b *blockingPlugin) Name() string { return "blocking" } -func (b *blockingPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { +func (b *blockingPlugin) ServeDNS(_ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { // Respond immediately to avoid waiting in dns.Exchange m := new(dns.Msg) m.SetRcodeFormatError(r) @@ -51,7 +51,7 @@ func testConfig(transport string, p plugin.Handler) *Config { Stacktrace: false, } - c.AddPlugin(func(next plugin.Handler) plugin.Handler { return p }) + c.AddPlugin(func(_next plugin.Handler) plugin.Handler { return p }) return c } diff --git a/core/dnsserver/server_tls.go b/core/dnsserver/server_tls.go index 83c560e690..0c2e390606 100644 --- a/core/dnsserver/server_tls.go +++ b/core/dnsserver/server_tls.go @@ -12,6 +12,7 @@ import ( "github.com/coredns/coredns/plugin/pkg/transport" "github.com/miekg/dns" + "github.com/pires/go-proxyproto" ) // ServerTLS represents an instance of a TLS-over-DNS-server. @@ -53,6 +54,7 @@ func (s *ServerTLS) Serve(l net.Listener) error { // Only fill out the TCP server for this one. s.server[tcp] = &dns.Server{Listener: l, Net: "tcp-tls", + TsigSecret: s.tsigSecret, MaxTCPQueries: tlsMaxQueries, ReadTimeout: s.ReadTimeout, WriteTimeout: s.WriteTimeout, @@ -71,7 +73,7 @@ func (s *ServerTLS) Serve(l net.Listener) error { } // ServePacket implements caddy.UDPServer interface. -func (s *ServerTLS) ServePacket(p net.PacketConn) error { return nil } +func (s *ServerTLS) ServePacket(_p net.PacketConn) error { return nil } // Listen implements caddy.TCPServer interface. func (s *ServerTLS) Listen() (net.Listener, error) { @@ -79,6 +81,9 @@ func (s *ServerTLS) Listen() (net.Listener, error) { if err != nil { return nil, err } + if s.connPolicy != nil { + l = &proxyproto.Listener{Listener: l, ConnPolicy: s.connPolicy} + } return l, nil } diff --git a/core/dnsserver/server_tls_test.go b/core/dnsserver/server_tls_test.go new file mode 100644 index 0000000000..01774b26ed --- /dev/null +++ b/core/dnsserver/server_tls_test.go @@ -0,0 +1,56 @@ +package dnsserver + +import ( + "errors" + "net" + "testing" +) + +type stubListener struct { + addr net.Addr +} + +func (l *stubListener) Accept() (net.Conn, error) { + return nil, errors.New("test listener closed") +} + +func (l *stubListener) Close() error { + return nil +} + +func (l *stubListener) Addr() net.Addr { + if l.addr != nil { + return l.addr + } + return &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0} +} + +func TestServerTLSSetsTsigSecret(t *testing.T) { + server, err := NewServerTLS("tls://127.0.0.1:0", []*Config{testConfig("tls", testPlugin{})}) + if err != nil { + t.Fatalf("NewServerTLS() failed: %v", err) + } + + server.tsigSecret = map[string]string{ + "test.": "abcd", + } + + l := &stubListener{} + + err = server.Serve(l) + if err == nil { + t.Fatal("expected Serve() to return from stub listener") + } + + if server.server[tcp] == nil { + t.Fatal("expected tcp server to be initialized") + } + + if server.server[tcp].TsigSecret == nil { + t.Fatal("expected TsigSecret to be propagated") + } + + if got := server.server[tcp].TsigSecret["test."]; got != "abcd" { + t.Fatalf("expected tsig secret %q, got %q", "abcd", got) + } +} diff --git a/core/dnsserver/tsig_test.go b/core/dnsserver/tsig_test.go new file mode 100644 index 0000000000..61cef3e80a --- /dev/null +++ b/core/dnsserver/tsig_test.go @@ -0,0 +1,46 @@ +package dnsserver + +import ( + "context" + "testing" + + "github.com/miekg/dns" +) + +type tsigStatusCheckPlugin struct { + t *testing.T + check func(*testing.T, error) + called chan struct{} +} + +func (p tsigStatusCheckPlugin) Name() string { return "tsig-status-check" } + +func (p tsigStatusCheckPlugin) ServeDNS(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + p.t.Helper() + if p.called != nil { + p.called <- struct{}{} + } + p.check(p.t, w.TsigStatus()) + + m := new(dns.Msg) + m.SetReply(r) + if err := w.WriteMsg(m); err != nil { + p.t.Fatalf("WriteMsg() failed: %v", err) + } + return dns.RcodeSuccess, nil +} + +func mustPackSignedTSIGQuery(t *testing.T, keyName, secret string, tsigTime int64) []byte { + t.Helper() + + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + m.Id = 0 + m.SetTsig(keyName, dns.HmacSHA256, 300, tsigTime) + + wire, _, err := dns.TsigGenerate(m, secret, "", false) + if err != nil { + t.Fatalf("dns.TsigGenerate() failed: %v", err) + } + return wire +} diff --git a/core/dnsserver/zdirectives.go b/core/dnsserver/zdirectives.go index c40f7f4c17..40d725b04e 100644 --- a/core/dnsserver/zdirectives.go +++ b/core/dnsserver/zdirectives.go @@ -15,7 +15,11 @@ var Directives = []string{ "geoip", "cancel", "tls", + "proxyproto", "quic", + "grpc_server", + "https", + "https3", "timeouts", "multisocket", "reload", @@ -33,7 +37,6 @@ var Directives = []string{ "dnstap", "local", "dns64", - "acl", "any", "chaos", "loadbalance", @@ -41,6 +44,7 @@ var Directives = []string{ "ocp_dnsnameresolver", "cache", "rewrite", + "acl", "header", "dnssec", "autopath", diff --git a/core/plugin/zplugin.go b/core/plugin/zplugin.go index bba027203a..0ac7e3c107 100644 --- a/core/plugin/zplugin.go +++ b/core/plugin/zplugin.go @@ -27,9 +27,12 @@ import ( _ "github.com/coredns/coredns/plugin/forward" _ "github.com/coredns/coredns/plugin/geoip" _ "github.com/coredns/coredns/plugin/grpc" + _ "github.com/coredns/coredns/plugin/grpc_server" _ "github.com/coredns/coredns/plugin/header" _ "github.com/coredns/coredns/plugin/health" _ "github.com/coredns/coredns/plugin/hosts" + _ "github.com/coredns/coredns/plugin/https" + _ "github.com/coredns/coredns/plugin/https3" _ "github.com/coredns/coredns/plugin/k8s_external" _ "github.com/coredns/coredns/plugin/kubernetes" _ "github.com/coredns/coredns/plugin/loadbalance" @@ -43,6 +46,7 @@ import ( _ "github.com/coredns/coredns/plugin/nomad" _ "github.com/coredns/coredns/plugin/nsid" _ "github.com/coredns/coredns/plugin/pprof" + _ "github.com/coredns/coredns/plugin/proxyproto" _ "github.com/coredns/coredns/plugin/quic" _ "github.com/coredns/coredns/plugin/ready" _ "github.com/coredns/coredns/plugin/reload" diff --git a/coredns.1.md b/coredns.1.md index 64daaca484..6418772769 100644 --- a/coredns.1.md +++ b/coredns.1.md @@ -39,6 +39,9 @@ Available options: **-version** : show version and quit. +**-windows-service** +: run as a Windows service (only available on Windows builds, default false). + ## Authors CoreDNS Authors. diff --git a/coremain/run.go b/coremain/run.go index 41e91b0508..93050c07f7 100644 --- a/coremain/run.go +++ b/coremain/run.go @@ -80,7 +80,7 @@ func Run() { } // Twiddle your thumbs - instance.Wait() + runService(instance) } // mustLogFatal wraps log.Fatal() in a way that ensures the @@ -192,6 +192,6 @@ var ( gitShortStat string // git diff-index --shortstat gitFilesModified string // git diff-index --name-only HEAD - // Gitcommit contains the commit where we built CoreDNS from. + // GitCommit contains the commit where we built CoreDNS from. GitCommit string ) diff --git a/coremain/run_test.go b/coremain/run_test.go index 84ca7dfa5a..4df352d2de 100644 --- a/coremain/run_test.go +++ b/coremain/run_test.go @@ -149,21 +149,23 @@ func TestDefaultLoader(t *testing.T) { } } - // Create a file but make it unreadable - tmpFile := filepath.Join(tmpDir, "Corefile") - if err := os.WriteFile(tmpFile, []byte("test"), 0644); err != nil { - t.Fatalf("Failed to create test file: %v", err) - } - if err := os.Chmod(tmpFile, 0000); err != nil { - t.Fatalf("Failed to change permissions: %v", err) - } + if runtime.GOOS != "windows" { + // Create a file but make it unreadable + tmpFile := filepath.Join(tmpDir, "Corefile") + if err := os.WriteFile(tmpFile, []byte("test"), 0644); err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + if err := os.Chmod(tmpFile, 0000); err != nil { + t.Fatalf("Failed to change permissions: %v", err) + } - input, err = defaultLoader("dns") - if err == nil { - t.Error("Expected error for unreadable Corefile but got none") - } - if input != nil { - t.Error("Expected nil input for unreadable Corefile") + input, err = defaultLoader("dns") + if err == nil { + t.Error("Expected error for unreadable Corefile but got none") + } + if input != nil { + t.Error("Expected nil input for unreadable Corefile") + } } } diff --git a/coremain/service_other.go b/coremain/service_other.go new file mode 100644 index 0000000000..023c7e701f --- /dev/null +++ b/coremain/service_other.go @@ -0,0 +1,9 @@ +//go:build !windows + +package coremain + +import "github.com/coredns/caddy" + +func runService(instance *caddy.Instance) { + instance.Wait() +} diff --git a/coremain/service_windows.go b/coremain/service_windows.go new file mode 100644 index 0000000000..2a4450caa6 --- /dev/null +++ b/coremain/service_windows.go @@ -0,0 +1,63 @@ +//go:build windows + +package coremain + +import ( + "flag" + "log" + + "github.com/coredns/caddy" + + "golang.org/x/sys/windows/svc" +) + +var windowsService bool + +func init() { + flag.BoolVar(&windowsService, "windows-service", false, "Run as a Windows service") +} + +type corednsService struct { + instance *caddy.Instance +} + +func (s *corednsService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) { + changes <- svc.Status{State: svc.StartPending} + changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown} + + for req := range r { + switch req.Cmd { + case svc.Interrogate: + changes <- req.CurrentStatus + case svc.Stop, svc.Shutdown: + changes <- svc.Status{State: svc.StopPending} + if s.instance != nil { + s.instance.Stop() + } + return false, 0 + default: + log.Printf("unexpected control request #%d", req.Cmd) + } + } + + return false, 0 +} + +func runService(instance *caddy.Instance) { + if windowsService { + isService, err := svc.IsWindowsService() + if err != nil { + log.Fatalf("failed to determine if running as service: %v", err) + } + if isService { + err = svc.Run("CoreDNS", &corednsService{instance: instance}) + if err != nil { + log.Fatalf("failed to start service: %v", err) + } + return + } else { + log.Printf("Windows service flag provided, but not running as a Windows service.") + } + } + instance.Wait() +} diff --git a/coremain/version.go b/coremain/version.go index 77931d8ece..8ef11a6682 100644 --- a/coremain/version.go +++ b/coremain/version.go @@ -2,7 +2,7 @@ package coremain // Various CoreDNS constants. const ( - CoreVersion = "1.13.1" + CoreVersion = "1.14.4" CoreName = "CoreDNS" serverType = "dns" ) diff --git a/go.mod b/go.mod index 1cbc686d46..bb4c3e753f 100644 --- a/go.mod +++ b/go.mod @@ -8,50 +8,57 @@ require ( github.com/Azure/azure-sdk-for-go v68.0.0+incompatible github.com/Azure/go-autorest/autorest v0.11.30 github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 - github.com/DataDog/dd-trace-go/v2 v2.2.3 - github.com/apparentlymart/go-cidr v1.1.0 - github.com/aws/aws-sdk-go-v2 v1.39.2 - github.com/aws/aws-sdk-go-v2/config v1.31.12 - github.com/aws/aws-sdk-go-v2/credentials v1.18.16 - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 - github.com/aws/aws-sdk-go-v2/service/route53 v1.58.4 - github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.6 + github.com/DataDog/dd-trace-go/v2 v2.8.2 + github.com/apparentlymart/go-cidr v1.1.1 + github.com/aws/aws-sdk-go-v2 v1.41.7 + github.com/aws/aws-sdk-go-v2/config v1.32.18 + github.com/aws/aws-sdk-go-v2/credentials v1.19.17 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 + github.com/aws/aws-sdk-go-v2/service/route53 v1.62.7 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.7 github.com/coredns/caddy v1.1.4-0.20250930002214-15135a999495 github.com/dnstap/golang-dnstap v0.4.0 - github.com/expr-lang/expr v1.17.7 + github.com/expr-lang/expr v1.17.8 github.com/farsightsec/golang-framestream v0.3.0 github.com/go-logr/logr v1.4.3 github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 github.com/hashicorp/nomad/api v0.0.0-20250909143645-a3b86c697f38 // v1.10.5 github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 - github.com/matttproud/golang_protobuf_extensions v1.0.4 - github.com/miekg/dns v1.1.68 - github.com/openshift/coredns-ocp-dnsnameresolver v0.0.0-20251118200623-f7b15b30153f + github.com/miekg/dns v1.1.72 github.com/opentracing/opentracing-go v1.2.0 github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 github.com/openzipkin/zipkin-go v0.4.3 - github.com/oschwald/geoip2-golang v1.13.0 - github.com/prometheus/client_golang v1.23.0 + github.com/oschwald/geoip2-golang/v2 v2.2.0 + github.com/prometheus/client_golang v1.23.2 github.com/prometheus/client_model v0.6.2 - github.com/prometheus/common v0.66.1 - github.com/quic-go/quic-go v0.55.0 - go.etcd.io/etcd/api/v3 v3.6.5 - go.etcd.io/etcd/client/v3 v3.6.5 + github.com/prometheus/common v0.67.5 + github.com/quic-go/quic-go v0.59.1 + github.com/stretchr/testify v1.11.1 + go.etcd.io/etcd/api/v3 v3.6.11 + go.etcd.io/etcd/client/v3 v3.6.11 go.uber.org/automaxprocs v1.6.0 - golang.org/x/crypto v0.50.0 - golang.org/x/sys v0.43.0 - google.golang.org/api v0.251.0 - google.golang.org/grpc v1.79.3 - google.golang.org/protobuf v1.36.10 - k8s.io/api v0.34.1 - k8s.io/apimachinery v0.34.1 - k8s.io/client-go v0.34.1 - k8s.io/klog/v2 v2.130.1 - sigs.k8s.io/mcs-api v0.3.0 + golang.org/x/crypto v0.52.0 + golang.org/x/sys v0.45.0 + google.golang.org/api v0.280.0 + google.golang.org/grpc v1.81.1 + google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af + k8s.io/api v0.36.2 + k8s.io/apimachinery v0.36.2 + k8s.io/client-go v0.36.2 + k8s.io/klog/v2 v2.140.0 + sigs.k8s.io/mcs-api v0.5.0 ) require ( - cloud.google.com/go/auth v0.16.5 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/openshift/coredns-ocp-dnsnameresolver v0.0.0-20260721173918-01fb3d1c63c6 + github.com/pires/go-proxyproto v0.12.0 + github.com/prometheus/exporter-toolkit v0.16.0 + golang.org/x/net v0.55.0 +) + +require ( + cloud.google.com/go/auth v0.20.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect @@ -61,44 +68,48 @@ require ( github.com/Azure/go-autorest/autorest/to v0.2.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/DataDog/appsec-internal-go v1.13.0 // indirect - github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.67.0 // indirect - github.com/DataDog/datadog-agent/pkg/obfuscate v0.67.0 // indirect - github.com/DataDog/datadog-agent/pkg/proto v0.67.0 // indirect - github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.69.0 // indirect - github.com/DataDog/datadog-agent/pkg/trace v0.67.0 // indirect - github.com/DataDog/datadog-agent/pkg/util/log v0.67.0 // indirect - github.com/DataDog/datadog-agent/pkg/util/scrubber v0.67.0 // indirect - github.com/DataDog/datadog-agent/pkg/version v0.67.0 // indirect - github.com/DataDog/datadog-go/v5 v5.6.0 // indirect - github.com/DataDog/go-libddwaf/v4 v4.3.2 // indirect - github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250721125240-fdf1ef85b633 // indirect - github.com/DataDog/go-sqllexer v0.1.6 // indirect - github.com/DataDog/go-tuf v1.1.0-0.5.2 // indirect - github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.27.0 // indirect - github.com/DataDog/sketches-go v1.4.7 // indirect - github.com/Masterminds/semver/v3 v3.3.1 // indirect + github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/obfuscate v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/opentelemetry-mapping-go/otlp/attributes v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/proto v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/template v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace/log v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace/otel v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace/stats v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace/traceutil v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/util/log v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/util/scrubber v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/version v0.77.0 // indirect + github.com/DataDog/datadog-go/v5 v5.8.3 // indirect + github.com/DataDog/go-libddwaf/v4 v4.9.0 // indirect + github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20260217080614-b0f4edc38a6d // indirect + github.com/DataDog/go-sqllexer v0.1.13 // indirect + github.com/DataDog/go-tuf v1.1.1-0.5.2 // indirect + github.com/DataDog/sketches-go v1.4.8 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.29.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 // indirect - github.com/aws/smithy-go v1.23.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect + github.com/aws/smithy-go v1.25.1 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect - github.com/ebitengine/purego v0.8.3 // indirect - github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/ebitengine/purego v0.10.0 // indirect + github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect @@ -106,97 +117,110 @@ require ( github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.15.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.15 // indirect + github.com/googleapis/gax-go/v2 v2.22.0 // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect github.com/hashicorp/cronexpr v1.1.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect - github.com/josharian/intern v1.0.0 // indirect + github.com/hashicorp/go-version v1.8.0 // indirect + github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.4 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/linkdata/deadlock v0.5.5 // indirect + github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect + github.com/mdlayher/socket v0.5.1 // indirect + github.com/mdlayher/vsock v1.2.1 // indirect + github.com/minio/simdjson-go v0.4.5 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.22.1 // indirect - github.com/onsi/gomega v1.36.2 // indirect - github.com/openshift/api v0.0.0-20251111193948-50e2ece149d7 // indirect - github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235 // indirect + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect + github.com/openshift/api v0.0.0-20260714141955-8bc26b0fcc2d // indirect + github.com/openshift/client-go v0.0.0-20260703082747-24d059aea27a // indirect github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect - github.com/oschwald/maxminddb-golang v1.13.0 // indirect + github.com/oschwald/maxminddb-golang/v2 v2.3.0 // indirect github.com/outcaste-io/ristretto v0.2.3 // indirect - github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect + github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect + github.com/philhofer/fwd v1.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect - github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect - github.com/shirou/gopsutil/v4 v4.25.3 // indirect - github.com/spf13/pflag v1.0.6 // indirect - github.com/stretchr/testify v1.11.1 // indirect - github.com/tinylib/msgp v1.2.5 // indirect - github.com/tklauser/go-sysconf v0.3.15 // indirect - github.com/tklauser/numcpus v0.10.0 // indirect + github.com/quic-go/qpack v0.6.0 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.10.0 // indirect + github.com/shirou/gopsutil/v4 v4.26.2 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/tinylib/msgp v1.6.3 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect + github.com/trailofbits/go-mutexasserts v0.0.0-20250514102930-c1f3d2e37561 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.5 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.11 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/collector/component v1.31.0 // indirect - go.opentelemetry.io/collector/featuregate v1.31.0 // indirect - go.opentelemetry.io/collector/internal/telemetry v0.125.0 // indirect - go.opentelemetry.io/collector/pdata v1.31.0 // indirect - go.opentelemetry.io/collector/semconv v0.125.0 // indirect - go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect - go.opentelemetry.io/otel v1.39.0 // indirect - go.opentelemetry.io/otel/log v0.11.0 // indirect - go.opentelemetry.io/otel/metric v1.39.0 // indirect - go.opentelemetry.io/otel/sdk v1.39.0 // indirect - go.opentelemetry.io/otel/trace v1.39.0 // indirect + go.opentelemetry.io/collector/component v1.51.1-0.20260205185216-81bc641f26c0 // indirect + go.opentelemetry.io/collector/featuregate v1.51.1-0.20260205185216-81bc641f26c0 // indirect + go.opentelemetry.io/collector/pdata v1.51.1-0.20260205185216-81bc641f26c0 // indirect + go.opentelemetry.io/collector/pdata/pprofile v0.145.1-0.20260205185216-81bc641f26c0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect + go.uber.org/zap v1.27.1 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/mod v0.34.0 // indirect - golang.org/x/net v0.53.0 // indirect - golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/exp v0.0.0-20260209203927-2842357ff358 // indirect + golang.org/x/mod v0.35.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.20.0 // indirect - golang.org/x/term v0.42.0 // indirect - golang.org/x/text v0.36.0 // indirect - golang.org/x/time v0.13.0 // indirect - golang.org/x/tools v0.43.0 // indirect - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/time v0.15.0 // indirect + golang.org/x/tools v0.44.0 // indirect + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/ini.v1 v1.67.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 // indirect + k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/go.sum b/go.sum index ddbb4dc8b4..71292e9003 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI= -cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ= +cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA= +cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= @@ -29,81 +29,89 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/DataDog/appsec-internal-go v1.13.0 h1:aO6DmHYsAU8BNFuvYJByhMKGgcQT3WAbj9J/sgAJxtA= -github.com/DataDog/appsec-internal-go v1.13.0/go.mod h1:9YppRCpElfGX+emXOKruShFYsdPq7WEPq/Fen4tYYpk= -github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.67.0 h1:2mEwRWvhIPHMPK4CMD8iKbsrYBxeMBSuuCXumQAwShU= -github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.67.0/go.mod h1:ejJHsyJTG7NU6c6TDbF7dmckD3g+AUGSdiSXy+ZyaCE= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.67.0 h1:NcvyDVIUA0NbBDbp7QJnsYhoBv548g8bXq886795mCQ= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.67.0/go.mod h1:1oPcs3BUTQhiTkmk789rb7ob105MxNV6OuBa28BdukQ= -github.com/DataDog/datadog-agent/pkg/proto v0.67.0 h1:7dO6mKYRb7qSiXEu7Q2mfeKbhp4hykCAULy4BfMPmsQ= -github.com/DataDog/datadog-agent/pkg/proto v0.67.0/go.mod h1:bKVXB7pxBg0wqXF6YSJ+KU6PeCWKDyJj83kUH1ab+7o= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.69.0 h1:/DsN4R+IkC6t1+4cHSfkxzLtDl84rBbPC5Wa9srBAoM= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.69.0/go.mod h1:Th2LD/IGid5Rza55pzqGu6nUdOv/Rts6wPwLjTyOSTs= -github.com/DataDog/datadog-agent/pkg/trace v0.67.0 h1:dqt+/nObo0JKyaEqIMZgfqGZbx9TfEHpCkrjQ/zzH7k= -github.com/DataDog/datadog-agent/pkg/trace v0.67.0/go.mod h1:zmZoEtKvOnaKHbJGBKH3a4xuyPrSfBaF0ZE3Q3rCoDw= -github.com/DataDog/datadog-agent/pkg/util/log v0.67.0 h1:xrH15QNqeJZkYoXYi44VCIvGvTwlQ3z2iT2QVTGiT7s= -github.com/DataDog/datadog-agent/pkg/util/log v0.67.0/go.mod h1:dfVLR+euzEyg1CeiExgJQq1c1dod42S6IeiRPj8H7Yk= -github.com/DataDog/datadog-agent/pkg/util/scrubber v0.67.0 h1:aIWF85OKxXGo7rVyqJ7jm7lm2qCQrgyXzYyFuw0T2EQ= -github.com/DataDog/datadog-agent/pkg/util/scrubber v0.67.0/go.mod h1:Lfap5FuM4b/Pw9IrTuAvWBWZEmXOvZhCya3dYv4G8O0= -github.com/DataDog/datadog-agent/pkg/version v0.67.0 h1:TB8H8r+laB1Qdttvvc6XJVyLGxp8E6j2f2Mh5IPbYmQ= -github.com/DataDog/datadog-agent/pkg/version v0.67.0/go.mod h1:kvAw/WbI7qLAsDI2wHabZfM7Cv2zraD3JA3323GEB+8= -github.com/DataDog/datadog-go/v5 v5.6.0 h1:2oCLxjF/4htd55piM75baflj/KoE6VYS7alEUqFvRDw= -github.com/DataDog/datadog-go/v5 v5.6.0/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= -github.com/DataDog/dd-trace-go/v2 v2.2.3 h1:6RvVdY9suR/rYYYZHjx4txrtSYcRZ5u5Cs2sXMsIBf4= -github.com/DataDog/dd-trace-go/v2 v2.2.3/go.mod h1:1LcqWELgQwgk6x7sO0MXUgsvxcAVjxSA423cUjvUqR0= -github.com/DataDog/go-libddwaf/v4 v4.3.2 h1:YGvW2Of1C4e1yU+p7iibmhN2zEOgi9XEchbhQjBxb/A= -github.com/DataDog/go-libddwaf/v4 v4.3.2/go.mod h1:/AZqP6zw3qGJK5mLrA0PkfK3UQDk1zCI2fUNCt4xftE= -github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250721125240-fdf1ef85b633 h1:ZRLR9Lbym748e8RznWzmSoK+OfV+8qW6SdNYA4/IqdA= -github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250721125240-fdf1ef85b633/go.mod h1:YFoTl1xsMzdSRFIu33oCSPS/3+HZAPGpO3oOM96wXCM= -github.com/DataDog/go-sqllexer v0.1.6 h1:skEXpWEVCpeZFIiydoIa2f2rf+ymNpjiIMqpW4w3YAk= -github.com/DataDog/go-sqllexer v0.1.6/go.mod h1:GGpo1h9/BVSN+6NJKaEcJ9Jn44Hqc63Rakeb+24Mjgo= -github.com/DataDog/go-tuf v1.1.0-0.5.2 h1:4CagiIekonLSfL8GMHRHcHudo1fQnxELS9g4tiAupQ4= -github.com/DataDog/go-tuf v1.1.0-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0= -github.com/DataDog/gostackparse v0.7.0 h1:i7dLkXHvYzHV308hnkvVGDL3BR4FWl7IsXNPz/IGQh4= -github.com/DataDog/gostackparse v0.7.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM= -github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.27.0 h1:5US5SqqhfkZkg/E64uvn7YmeTwnudJHtlPEH/LOT99w= -github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.27.0/go.mod h1:VRo4D6rj92AExpVBlq3Gcuol9Nm1bber12KyxRjKGWw= -github.com/DataDog/sketches-go v1.4.7 h1:eHs5/0i2Sdf20Zkj0udVFWuCrXGRFig2Dcfm5rtcTxc= -github.com/DataDog/sketches-go v1.4.7/go.mod h1:eAmQ/EBmtSO+nQp7IZMZVRPT4BQTmIc5RZQ+deGlTPM= -github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= -github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.77.0 h1:Lu/HEo5svx/UwE7XWh8vOrEHCrVRsein9X1N0jGK5bo= +github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.77.0/go.mod h1:+Ty3r23MjcmMSkr8JbFeqA3utgtc1wxsZ0KaQ9CzoWA= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.77.0 h1:mrHaNnDAIOFAVYhCqDpkenUtbadswHN68ZlG5krv40o= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.77.0/go.mod h1:E6RGAcEOr/d8wsV5/khYHvaHkijWex6dfNEvsBIgR7A= +github.com/DataDog/datadog-agent/pkg/opentelemetry-mapping-go/otlp/attributes v0.77.0 h1:g1d9d1CfG54WjXgvkysTFL9yjXexWeDbYssQaf1PG6c= +github.com/DataDog/datadog-agent/pkg/opentelemetry-mapping-go/otlp/attributes v0.77.0/go.mod h1:N/AB9VGpVwHxCcyX+7GLNYMfnTZvn65vp5cHb5Ed0ow= +github.com/DataDog/datadog-agent/pkg/proto v0.77.0 h1:21nDAKD+LdxZz2pMsLAQTZ+w9Z4JqecjKpt8xY1b7Ig= +github.com/DataDog/datadog-agent/pkg/proto v0.77.0/go.mod h1:g2QYJe1CheZdssiDQpSYWra9hORkh+S3WO8aOqDNLkg= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.77.0 h1:SxFGFN/Dd/uREaUTxuVTi0R7fRABzvUtu32YOXcjf6c= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.77.0/go.mod h1:TpW5ZwsQTrlRBPjtZH5/OFwpmOqxV/v2i9BiF4Xfcac= +github.com/DataDog/datadog-agent/pkg/template v0.77.0 h1:sUbTCoQyU9kXMc6/aDd4YTP2pe9PlNkgySM11ydMEbE= +github.com/DataDog/datadog-agent/pkg/template v0.77.0/go.mod h1:ZUjICHSlN0of0cmWrYk9Pof0DV0eqHSpTUK1NTnN26Y= +github.com/DataDog/datadog-agent/pkg/trace v0.77.0 h1:B7M6IW0sd60XnLfeP6HEneeR4lRnaNtI9bboU4R1cV0= +github.com/DataDog/datadog-agent/pkg/trace v0.77.0/go.mod h1:+7zMNPjHTDidiphECirrpq5jLK09S9kmLtGRv7di29Q= +github.com/DataDog/datadog-agent/pkg/trace/log v0.77.0 h1:2VY1byEA2XnYVg7+eLQSTgX2f76ZCf/AwpCBJDXCiDc= +github.com/DataDog/datadog-agent/pkg/trace/log v0.77.0/go.mod h1:thnxBOGfMU9uRlFUClXud6J7DdI8qWtElELSds5jqts= +github.com/DataDog/datadog-agent/pkg/trace/otel v0.77.0 h1:9zSto72E+wSETaKs47Yiq5D9du9H71IqWgbDJzGpzSs= +github.com/DataDog/datadog-agent/pkg/trace/otel v0.77.0/go.mod h1:IxBidgqUt8aBrKYq4VKynBHWYZYNoflk+0+m7w+lfbI= +github.com/DataDog/datadog-agent/pkg/trace/stats v0.77.0 h1:InA6JO5R8TFAUcKRxsdmIF1hJpVZqVO5Aqux+Iw/2V0= +github.com/DataDog/datadog-agent/pkg/trace/stats v0.77.0/go.mod h1:iZVotmInV8qaU6Q5h+tsKk4CBYupDcOgTzonzLlMi0k= +github.com/DataDog/datadog-agent/pkg/trace/traceutil v0.77.0 h1:b/2+uA/cG2xEV0LzgwnxloMFWe5sdJa3xtaQhSGN0+s= +github.com/DataDog/datadog-agent/pkg/trace/traceutil v0.77.0/go.mod h1:csT+8o3GOUjhKPs/GqWMb5Zh4iQpuZ/HZQ4Z5ls8Sak= +github.com/DataDog/datadog-agent/pkg/util/log v0.77.0 h1:YFa+8kIg2qQZca9zvowtwCPdHDhGMcTIF+PMIQsLSRs= +github.com/DataDog/datadog-agent/pkg/util/log v0.77.0/go.mod h1:DFK2U5RcB8/BcObgmVEZ4VxqXUi2t7y2svLTtJwQqeo= +github.com/DataDog/datadog-agent/pkg/util/scrubber v0.77.0 h1:dd0W9e39rv0R3DSgnaurVnQ43/jX/juqQPwLpGAJgFs= +github.com/DataDog/datadog-agent/pkg/util/scrubber v0.77.0/go.mod h1:nkhevws2pJvoXSGhjc8wuTbptNQ9ECRBjwVr4hSvoq0= +github.com/DataDog/datadog-agent/pkg/version v0.77.0 h1:fxpMWuoaRHS5vHzCNHftvJ6wdQrGhEmuozjjl8wZG5k= +github.com/DataDog/datadog-agent/pkg/version v0.77.0/go.mod h1:h9eJjfeTHlYYv+kzq6n3rQ07qXGirdCCacn1Ryu4TFQ= +github.com/DataDog/datadog-go/v5 v5.8.3 h1:s58CUJ9s8lezjhTNJO/SxkPBv2qZjS3ktpRSqGF5n0s= +github.com/DataDog/datadog-go/v5 v5.8.3/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= +github.com/DataDog/dd-trace-go/v2 v2.8.2 h1:ZqF2M7j5DPG7PxkJpLIjF4L62LU/QnI86oOSAZjQC/U= +github.com/DataDog/dd-trace-go/v2 v2.8.2/go.mod h1:o+fhXzd1mPT4Ji5YYcqIjORnNKWcS6m2eW4xqdJplRA= +github.com/DataDog/go-libddwaf/v4 v4.9.0 h1:a788e37iuH7sR9uIYHkulvTnp2FkXTiZ3yY/kuaHgZE= +github.com/DataDog/go-libddwaf/v4 v4.9.0/go.mod h1:/AZqP6zw3qGJK5mLrA0PkfK3UQDk1zCI2fUNCt4xftE= +github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20260217080614-b0f4edc38a6d h1:cH9Bm0tJ8FEQbA4FRi0iRm7Zr/5Lata/Or31c+Dth0E= +github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20260217080614-b0f4edc38a6d/go.mod h1:yDuvU+Ak1TKwgd4K8DNcpJmUrrK8ONLkBMGNAppmBRk= +github.com/DataDog/go-sqllexer v0.1.13 h1:HhT2G21y7SDZYQx9i1b+3Sy/CHhESHet/YKMSm06XcE= +github.com/DataDog/go-sqllexer v0.1.13/go.mod h1:vOw7Ia7z+z6nl3zGZlLIZe0vQlPtCPR906WIPBJadxc= +github.com/DataDog/go-tuf v1.1.1-0.5.2 h1:YWvghV4ZvrQsPcUw8IOUMSDpqc3W5ruOIC+KJxPknv0= +github.com/DataDog/go-tuf v1.1.1-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0= +github.com/DataDog/sketches-go v1.4.8 h1:pFk9BNn+Rzv8IMIoPUttoOpOr3bJOqU3P6EP5wK+Lv8= +github.com/DataDog/sketches-go v1.4.8/go.mod h1:a/wjRUqzqtGS8qRHRPDCs4EAQfmvPDZGDlMIF5mxXOE= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= -github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/aws/aws-sdk-go-v2 v1.39.2 h1:EJLg8IdbzgeD7xgvZ+I8M1e0fL0ptn/M47lianzth0I= -github.com/aws/aws-sdk-go-v2 v1.39.2/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= -github.com/aws/aws-sdk-go-v2/config v1.31.12 h1:pYM1Qgy0dKZLHX2cXslNacbcEFMkDMl+Bcj5ROuS6p8= -github.com/aws/aws-sdk-go-v2/config v1.31.12/go.mod h1:/MM0dyD7KSDPR+39p9ZNVKaHDLb9qnfDurvVS2KAhN8= -github.com/aws/aws-sdk-go-v2/credentials v1.18.16 h1:4JHirI4zp958zC026Sm+V4pSDwW4pwLefKrc0bF2lwI= -github.com/aws/aws-sdk-go-v2/credentials v1.18.16/go.mod h1:qQMtGx9OSw7ty1yLclzLxXCRbrkjWAM7JnObZjmCB7I= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 h1:Mv4Bc0mWmv6oDuSWTKnk+wgeqPL5DRFu5bQL9BGPQ8Y= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9/go.mod h1:IKlKfRppK2a1y0gy1yH6zD+yX5uplJ6UuPlgd48dJiQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 h1:se2vOWGD3dWQUtfn4wEjRQJb1HK1XsNIt825gskZ970= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9/go.mod h1:hijCGH2VfbZQxqCDN7bwz/4dzxV+hkyhjawAtdPWKZA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 h1:6RBnKZLkJM4hQ+kN6E7yWFveOTg8NLPHAkqrs4ZPlTU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9/go.mod h1:V9rQKRmK7AWuEsOMnHzKj8WyrIir1yUJbZxDuZLFvXI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9 h1:5r34CgVOD4WZudeEKZ9/iKpiT6cM1JyEROpXjOcdWv8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9/go.mod h1:dB12CEbNWPbzO2uC6QSWHteqOg4JfBVJOojbAoAUb5I= -github.com/aws/aws-sdk-go-v2/service/route53 v1.58.4 h1:KycXrohD5OxAZ5h02YechO2gevvoHfAPAaJM5l8zqb0= -github.com/aws/aws-sdk-go-v2/service/route53 v1.58.4/go.mod h1:xNLZLn4SusktBQ5moqUOgiDKGz3a7vHwF4W0KD+WBPc= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.6 h1:9PWl450XOG+m5lKv+qg5BXso1eLxpsZLqq7VPug5km0= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.6/go.mod h1:hwt7auGsDcaNQ8pzLgE2kCNyIWouYlAKSjuUu5Dqr7I= -github.com/aws/aws-sdk-go-v2/service/sso v1.29.6 h1:A1oRkiSQOWstGh61y4Wc/yQ04sqrQZr1Si/oAXj20/s= -github.com/aws/aws-sdk-go-v2/service/sso v1.29.6/go.mod h1:5PfYspyCU5Vw1wNPsxi15LZovOnULudOQuVxphSflQA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1 h1:5fm5RTONng73/QA73LhCNR7UT9RpFH3hR6HWL6bIgVY= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1/go.mod h1:xBEjWD13h+6nq+z4AkqSfSvqRKFgDIQeaMguAJndOWo= -github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 h1:p3jIvqYwUZgu/XYeI48bJxOhvm47hZb5HUQ0tn6Q9kA= -github.com/aws/aws-sdk-go-v2/service/sts v1.38.6/go.mod h1:WtKK+ppze5yKPkZ0XwqIVWD4beCwv056ZbPQNoeHqM8= -github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE= -github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/apparentlymart/go-cidr v1.1.1 h1:oEEk8CE0HP0YpHxsegk/TaOtR2FLHdWv4p3eM4ceUwg= +github.com/apparentlymart/go-cidr v1.1.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= +github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8= +github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc= +github.com/aws/aws-sdk-go-v2/config v1.32.18 h1:Hcia46bxhGgF3BaSnG8nSNCWmqTK6bj9xN9/FJ3WK6Q= +github.com/aws/aws-sdk-go-v2/config v1.32.18/go.mod h1:zEjCAYmxqDadH1WX8CdBvmLKhUEUVFgKRQG38zjDmrY= +github.com/aws/aws-sdk-go-v2/credentials v1.19.17 h1:gP2nkGsS+KMvF/jfFz2Vv2qiiOqWKyPACSzPsqHgoW8= +github.com/aws/aws-sdk-go-v2/credentials v1.19.17/go.mod h1:Bsew3S/moG5iT77giPj1q8wb/s0RE5/QfH+ASjYtuQc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA= +github.com/aws/aws-sdk-go-v2/service/route53 v1.62.7 h1:twRRMmtSITnt/rrp+D7UDLzE5pKMZe759aalkUdN+OY= +github.com/aws/aws-sdk-go-v2/service/route53 v1.62.7/go.mod h1:ztM1lr+sRoCAI8336ZUvlRPbToue0d3gE/wd6jomSJ8= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.7 h1:JUGKqUnJHbXpS8uyuICP/zpQ+vXUIXW2zTEqjMLCqrY= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.7/go.mod h1:l/cqI7ujYqBuTR6Ll13d9/gG/uUdlVzJ1UDltEEBTOo= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 h1:nDARhv/oF55bcxF7rCI/4PDxOKnVXVWwDuDwCs2I2SQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio= +github.com/aws/smithy-go v1.25.1 h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI= +github.com/aws/smithy-go v1.25.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -113,8 +121,8 @@ github.com/coredns/caddy v1.1.4-0.20250930002214-15135a999495 h1:JFeOmbjLnVRhvmL github.com/coredns/caddy v1.1.4-0.20250930002214-15135a999495/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= +github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -132,14 +140,12 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg= -github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds= -github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc= -github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= -github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/expr-lang/expr v1.17.7 h1:Q0xY/e/2aCIp8g9s/LGvMDCC5PxYlvHgDZRQ4y16JX8= -github.com/expr-lang/expr v1.17.7/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= +github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM= +github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/farsightsec/golang-framestream v0.3.0 h1:/spFQHucTle/ZIPkYqrfshQqPe2VQEzesH243TjIwqA= github.com/farsightsec/golang-framestream v0.3.0/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -162,14 +168,36 @@ github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kO github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= @@ -177,10 +205,11 @@ github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -198,21 +227,21 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= -github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= -github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= +github.com/googleapis/enterprise-certificate-proxy v0.3.15 h1:xolVQTEXusUcAA5UgtyRLjelpFFHWlPQ4XfWGc7MBas= +github.com/googleapis/enterprise-certificate-proxy v0.3.15/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= +github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hashicorp/cronexpr v1.1.3 h1:rl5IkxXN2m681EfivTlccqIryzYJSXRGRNa0xeG7NA4= @@ -226,20 +255,25 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4= +github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/nomad/api v0.0.0-20250909143645-a3b86c697f38 h1:1LTbcTpGdSdbj0ee7YZHNe4R2XqxfyWwIkSGWRhgkfM= github.com/hashicorp/nomad/api v0.0.0-20250909143645-a3b86c697f38/go.mod h1:0Tdp+9HbvwrxprXv/LfYZ8P21bOl4oA8Afyet1kUvhI= github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 h1:w66aaP3c6SIQ0pi3QH1Tb4AMO3aWoEPxd1CNvLphbkA= github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9/go.mod h1:BaIJzjD2ZnHmx2acPF6XfGLPzNCMiBbMRqJr+8/8uRI= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -249,15 +283,20 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= -github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/linkdata/deadlock v0.5.5 h1:d6O+rzEqasSfamGDA8u7bjtaq7hOX8Ha4Zn36Wxrkvo= +github.com/linkdata/deadlock v0.5.5/go.mod h1:tXb28stzAD3trzEEK0UJWC+rZKuobCoPktPYzebb1u0= +github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM= +github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= +github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= -github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= +github.com/minio/simdjson-go v0.4.5 h1:r4IQwjRGmWCQ2VeMc7fGiilu1z5du0gJ/I/FsKwgo5A= +github.com/minio/simdjson-go v0.4.5/go.mod h1:eoNz0DcLQRyEDeaPr4Ru6JpjlZPzbA0IodxVJk8lO8E= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= @@ -270,20 +309,18 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= -github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.125.0 h1:0dOJCEtabevxxDQmxed69oMzSw+gb3ErCnFwFYZFu0M= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.125.0/go.mod h1:QwzQhtxPThXMUDW1XRXNQ+l0GrI2BRsvNhX6ZuKyAds= -github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.125.0 h1:F68/Nbpcvo3JZpaWlRUDJtG7xs8FHBZ7A8GOMauDkyc= -github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.125.0/go.mod h1:haO4cJtAk05Y0p7NO9ME660xxtSh54ifCIIT7+PO9C0= -github.com/openshift/api v0.0.0-20251111193948-50e2ece149d7 h1:MemawsK6SpxEaE5y0NqO5sIX3yTLIIyP89w6DGKukAk= -github.com/openshift/api v0.0.0-20251111193948-50e2ece149d7/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY= -github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235 h1:9JBeIXmnHlpXTQPi7LPmu1jdxznBhAE7bb1K+3D8gxY= -github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235/go.mod h1:L49W6pfrZkfOE5iC1PqEkuLkXG4W0BX4w8b+L2Bv7fM= -github.com/openshift/coredns-ocp-dnsnameresolver v0.0.0-20251118200623-f7b15b30153f h1:qD47fr/BfvuOiAy3lRoMql4bl1I9bNS2REUjZyRyf18= -github.com/openshift/coredns-ocp-dnsnameresolver v0.0.0-20251118200623-f7b15b30153f/go.mod h1:Fi8MBsadvu5BiQViStarlv89qGT1d+DGEpCxKmg/Wp8= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.145.0 h1:7rdLY2Ewa1WVnjMfJTEKwQ5uPDHYeA1tqNPNROi957U= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.145.0/go.mod h1:jYlQAaJO4ZyJAW2jcKAbjN+nt5BRCyu49mlZv4Rui7U= +github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.145.0 h1:12mxn+8YLeAjMZ1kLGulBcvHrdhRNUmxLVIDnaLkJbQ= +github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.145.0/go.mod h1:V87HYJpfmvCeQ6Cjy3Q4xylxfCn2wVSS80wvv5ECc0s= +github.com/openshift/api v0.0.0-20260714141955-8bc26b0fcc2d h1:wu0NFMDd8ZZOIOCTfDVjMDsmlBFptbAQVr41wiJbyPQ= +github.com/openshift/api v0.0.0-20260714141955-8bc26b0fcc2d/go.mod h1:7WJ3IPaK6nmWT8bDcaNooHqd0H5WepjVqV/10VlkMEM= +github.com/openshift/client-go v0.0.0-20260703082747-24d059aea27a h1:RfmstmmWz5/23/Tt8gBipICzC1VHQLgGBeQUQ1aWoUA= +github.com/openshift/client-go v0.0.0-20260703082747-24d059aea27a/go.mod h1:fNuXvm6bMJff2AxiRb9CR5L3a9CLzVgcoSmHZ3l7FgU= +github.com/openshift/coredns-ocp-dnsnameresolver v0.0.0-20260721173918-01fb3d1c63c6 h1:sE7sjDLzzyBcNHNbWDqgDb71JD+5Mv/KB0CMk9uCvqQ= +github.com/openshift/coredns-ocp-dnsnameresolver v0.0.0-20260721173918-01fb3d1c63c6/go.mod h1:G6KeVeDImlPdDJLfhph7g6M4LuZtzU/Hy9d+kcVzvz8= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -292,14 +329,19 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 h1:uhcF5Jd7rP9DVEL10S github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0/go.mod h1:+oCZ5GXXr7KPI/DNOQORPTq5AWHfALJj9c72b0+YsEY= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= -github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNsSFzQATJI= -github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo= -github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU= -github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o= +github.com/oschwald/geoip2-golang/v2 v2.2.0 h1:gdkhpnHQMiH9ymOI+zSB0QKFGH+n4TntNt7vz+TxGPY= +github.com/oschwald/geoip2-golang/v2 v2.2.0/go.mod h1:xW4tCeQiNU1gqMD1x7zEH2CDNM3d796Ls50yxYDaX0U= +github.com/oschwald/maxminddb-golang/v2 v2.3.0 h1:PnXjMGjkSQlwOBSyZ7hk6Fd75t7erkAhJNJgEhA3MQU= +github.com/oschwald/maxminddb-golang/v2 v2.3.0/go.mod h1:NSQvgFwPxODpBTJI5+5Ns1AAucnx7ggW9PSRRifAT1s= github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pires/go-proxyproto v0.12.0 h1:TTCxD66dU898tahivkqc3hoceZp7P44FnorWyo9d5vM= +github.com/pires/go-proxyproto v0.12.0/go.mod h1:qUvfqUMEoX7T8g0q7TQLDnhMjdTrxnG0hvpMn+7ePNI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= @@ -311,33 +353,37 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= -github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/exporter-toolkit v0.16.0 h1:xT/j7L2XKF+VJd6B4fpUw6xWabHrSmsUf6mYmFqyu0s= +github.com/prometheus/exporter-toolkit v0.16.0/go.mod h1:d1EL8Z9674xQe/iWhwP2wDyCEoBPbXVeqDbqAUsgJWY= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= -github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk= -github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic= +github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3 h1:4+LEVOB87y175cLJC/mbsgKmoDOjrBldtXvioEy96WY= github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3/go.mod h1:vl5+MqJ1nBINuSsUI2mGgH79UweUT/B5Fy8857PqyyI= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/secure-systems-lab/go-securesystemslib v0.9.0 h1:rf1HIbL64nUpEIZnjLZ3mcNEL9NBPB0iuVjyxvq3LZc= -github.com/secure-systems-lab/go-securesystemslib v0.9.0/go.mod h1:DVHKMcZ+V4/woA/peqr+L0joiRXbPpQ042GgJckkFgw= -github.com/shirou/gopsutil/v4 v4.25.3 h1:SeA68lsu8gLggyMbmCn8cmp97V1TI9ld9sVzAUcKcKE= -github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= +github.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxoGv1jjNpGYdZ9RcheFkB2WI14= +github.com/secure-systems-lab/go-securesystemslib v0.10.0/go.mod h1:MRKONWmRoFzPNQ9USRF9i1mc7MvAVvF1LlW8X5VWDvk= +github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI= +github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/shoenig/test v1.12.1 h1:mLHfnMv7gmhhP44WrvT+nKSxKkPDiNkIuHGdIGI9RLU= github.com/shoenig/test v1.12.1/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -349,14 +395,17 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= -github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= -github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= -github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= -github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= -github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= +github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= +github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/trailofbits/go-mutexasserts v0.0.0-20250514102930-c1f3d2e37561 h1:qqa3P9AtNn6RMe90l/lxd3eJWnIRxjI4eb5Rx8xqCLA= +github.com/trailofbits/go-mutexasserts v0.0.0-20250514102930-c1f3d2e37561/go.mod h1:GA3+Mq3kt3tYAfM0WZCu7ofy+GW9PuGysHfhr+6JX7s= github.com/vmihailenco/msgpack/v4 v4.3.13 h1:A2wsiTbvp63ilDaWmsk2wjx6xZdxQOvpiNlKBGKKXKI= github.com/vmihailenco/msgpack/v4 v4.3.13/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= @@ -369,64 +418,68 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.etcd.io/etcd/api/v3 v3.6.5 h1:pMMc42276sgR1j1raO/Qv3QI9Af/AuyQUW6CBAWuntA= -go.etcd.io/etcd/api/v3 v3.6.5/go.mod h1:ob0/oWA/UQQlT1BmaEkWQzI0sJ1M0Et0mMpaABxguOQ= -go.etcd.io/etcd/client/pkg/v3 v3.6.5 h1:Duz9fAzIZFhYWgRjp/FgNq2gO1jId9Yae/rLn3RrBP8= -go.etcd.io/etcd/client/pkg/v3 v3.6.5/go.mod h1:8Wx3eGRPiy0qOFMZT/hfvdos+DjEaPxdIDiCDUv/FQk= -go.etcd.io/etcd/client/v3 v3.6.5 h1:yRwZNFBx/35VKHTcLDeO7XVLbCBFbPi+XV4OC3QJf2U= -go.etcd.io/etcd/client/v3 v3.6.5/go.mod h1:ZqwG/7TAFZ0BJ0jXRPoJjKQJtbFo/9NIY8uoFFKcCyo= +go.etcd.io/etcd/api/v3 v3.6.11 h1:XFGTgrJ8nak3kB4NgMG8t7NT+lEeuuvKQAqUHKVgkWQ= +go.etcd.io/etcd/api/v3 v3.6.11/go.mod h1:HYfTh0jyh+uFgp6gMbxJteIDYY97yMuYz85Rnw6Gy9o= +go.etcd.io/etcd/client/pkg/v3 v3.6.11 h1:e41mp315Yn3QMGPmEzCyLsMINgJXTY/dX8kM++1csxU= +go.etcd.io/etcd/client/pkg/v3 v3.6.11/go.mod h1:DysuMe/inqRyC/1tjRR6hReH/VV9Lufs27YKSKBWWJg= +go.etcd.io/etcd/client/v3 v3.6.11 h1:LAByD96VmmeuairkvdAcE0RZnrmGz/q3ceeWePo9bwc= +go.etcd.io/etcd/client/v3 v3.6.11/go.mod h1:vOTDMCo+fGPEClJqcFEFSqZ+8e7WKV7AyqJjX//HR2w= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/collector/component v1.31.0 h1:9LzU8X1RhV3h8/QsAoTX23aFUfoJ3EUc9O/vK+hFpSI= -go.opentelemetry.io/collector/component v1.31.0/go.mod h1:JbZl/KywXJxpUXPbt96qlEXJSym1zQ2hauMxYMuvlxM= -go.opentelemetry.io/collector/component/componentstatus v0.125.0 h1:zlxGQZYd9kknRZSjRpOYW5SBjl0a5zYFYRPbreobXoU= -go.opentelemetry.io/collector/component/componentstatus v0.125.0/go.mod h1:bHXc2W8bqqo9adOvCgvhcO7pYzJOSpyV4cuQ1wiIl04= -go.opentelemetry.io/collector/component/componenttest v0.125.0 h1:E2mpnMQbkMpYoZ3Q8pHx4kod7kedjwRs1xqDpzCe/84= -go.opentelemetry.io/collector/component/componenttest v0.125.0/go.mod h1:pQtsE1u/SPZdTphP5BZP64XbjXSq6wc+mDut5Ws/JDI= -go.opentelemetry.io/collector/consumer v1.31.0 h1:L+y66ywxLHnAxnUxv0JDwUf5bFj53kMxCCyEfRKlM7s= -go.opentelemetry.io/collector/consumer v1.31.0/go.mod h1:rPsqy5ni+c6xNMUkOChleZYO/nInVY6eaBNZ1FmWJVk= -go.opentelemetry.io/collector/consumer/consumertest v0.125.0 h1:TUkxomGS4DAtjBvcWQd2UY4FDLLEKMQD6iOIDUr/5dM= -go.opentelemetry.io/collector/consumer/consumertest v0.125.0/go.mod h1:vkHf3y85cFLDHARO/cTREVjLjOPAV+cQg7lkC44DWOY= -go.opentelemetry.io/collector/consumer/xconsumer v0.125.0 h1:oTreUlk1KpMSWwuHFnstW+orrjGTyvs2xd3o/Dpy+hI= -go.opentelemetry.io/collector/consumer/xconsumer v0.125.0/go.mod h1:FX0G37r0W+wXRgxxFtwEJ4rlsCB+p0cIaxtU3C4hskw= -go.opentelemetry.io/collector/featuregate v1.31.0 h1:20q7plPQZwmAiaYAa6l1m/i2qDITZuWlhjr4EkmeQls= -go.opentelemetry.io/collector/featuregate v1.31.0/go.mod h1:Y/KsHbvREENKvvN9RlpiWk/IGBK+CATBYzIIpU7nccc= -go.opentelemetry.io/collector/internal/telemetry v0.125.0 h1:6lcGOxw3dAg7LfXTKdN8ZjR+l7KvzLdEiPMhhLwG4r4= -go.opentelemetry.io/collector/internal/telemetry v0.125.0/go.mod h1:5GyFslLqjZgq1DZTtFiluxYhhXrCofHgOOOybodDPGE= -go.opentelemetry.io/collector/pdata v1.31.0 h1:P5WuLr1l2JcIvr6Dw2hl01ltp2ZafPnC4Isv+BLTBqU= -go.opentelemetry.io/collector/pdata v1.31.0/go.mod h1:m41io9nWpy7aCm/uD1L9QcKiZwOP0ldj83JEA34dmlk= -go.opentelemetry.io/collector/pdata/pprofile v0.125.0 h1:Qqlx8w1HpiYZ9RQqjmMQIysI0cHNO1nh3E/fCTeFysA= -go.opentelemetry.io/collector/pdata/pprofile v0.125.0/go.mod h1:p/yK023VxAp8hm27/1G5DPTcMIpnJy3cHGAFUQZGyaQ= -go.opentelemetry.io/collector/pdata/testdata v0.125.0 h1:due1Hl0EEVRVwfCkiamRy5E8lS6yalv0lo8Zl/SJtGw= -go.opentelemetry.io/collector/pdata/testdata v0.125.0/go.mod h1:1GpEWlgdMrd+fWsBk37ZC2YmOP5YU3gFQ4rWuCu9g24= -go.opentelemetry.io/collector/pipeline v0.125.0 h1:oitBgcAFqntDB4ihQJUHJSQ8IHqKFpPkaTVbTYdIUzM= -go.opentelemetry.io/collector/pipeline v0.125.0/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4= -go.opentelemetry.io/collector/processor v1.31.0 h1:+u7sBUpnCBsHYoALp4hfr9VEjLHHYa4uKENGITe0K9Q= -go.opentelemetry.io/collector/processor v1.31.0/go.mod h1:5hDYJ7/hTdfd2tF2Rj5Hs6+mfyFz2O7CaPzVvW1qHQc= -go.opentelemetry.io/collector/processor/processorhelper v0.125.0 h1:QRpX7oFW88DAZhy+Q93npklRoaQr8ue0GKpeup7C/Fk= -go.opentelemetry.io/collector/processor/processorhelper v0.125.0/go.mod h1:oXRvslUuN62wErcoJrcEJYoTXu5wHyNyJsE+/a9Cc9s= -go.opentelemetry.io/collector/processor/processortest v0.125.0 h1:ZVAN4iZPDcWhpzKqnuok2NIuS5hwGVVQUOWkJFR12tA= -go.opentelemetry.io/collector/processor/processortest v0.125.0/go.mod h1:VAw0IRG35cWTBjBtreXeXJEgqkRegfjrH/EuLhNX2+I= -go.opentelemetry.io/collector/processor/xprocessor v0.125.0 h1:VWYPMW1VmDq6xB7M5SYjBpQCCIq3MhQ3W++wU47QpZM= -go.opentelemetry.io/collector/processor/xprocessor v0.125.0/go.mod h1:bCxUyFVlksANg8wjYZqWVsRB33lkLQ294rTrju/IZiM= -go.opentelemetry.io/collector/semconv v0.125.0 h1:SyRP617YGvNSWRSKMy7Lbk9RaJSR+qFAAfyxJOeZe4s= -go.opentelemetry.io/collector/semconv v0.125.0/go.mod h1:te6VQ4zZJO5Lp8dM2XIhDxDiL45mwX0YAQQWRQ0Qr9U= -go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 h1:ojdSRDvjrnm30beHOmwsSvLpoRF40MlwNCA+Oo93kXU= -go.opentelemetry.io/contrib/bridges/otelzap v0.10.0/go.mod h1:oTTm4g7NEtHSV2i/0FeVdPaPgUIZPfQkFbq0vbzqnv0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= -go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= -go.opentelemetry.io/otel/log v0.11.0 h1:c24Hrlk5WJ8JWcwbQxdBqxZdOK7PcP/LFtOtwpDTe3Y= -go.opentelemetry.io/otel/log v0.11.0/go.mod h1:U/sxQ83FPmT29trrifhQg+Zj2lo1/IPN1PF6RTFqdwc= -go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= -go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= -go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= -go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= -go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= -go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/collector/component v1.51.1-0.20260205185216-81bc641f26c0 h1:ZSlXxE90IY0Cl53RTqzyEgRgRPLTeTNBdGhaTmvj9eY= +go.opentelemetry.io/collector/component v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:944C7vEIdk13Pn1fBbyaU8C1qKf2XC0jRBlc69NAsRY= +go.opentelemetry.io/collector/component/componentstatus v0.145.0 h1:EwUZfSaagdpRXnlrb0TqReJXXW2p9HWBU5YiIeXPCAE= +go.opentelemetry.io/collector/component/componentstatus v0.145.0/go.mod h1:OiYb8rT4FtSJPFSGCKYvOaajdueDUTJZncixGrmy5aM= +go.opentelemetry.io/collector/component/componenttest v0.145.1-0.20260205185216-81bc641f26c0 h1:+VCK6wX/WN170dcaWJweRAkxpmAEyVucfrUV13NwUlY= +go.opentelemetry.io/collector/component/componenttest v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:U2wUjKMGwgqM49/q8ORkzzYzSWY2m6zpG/e606eK1wc= +go.opentelemetry.io/collector/consumer v1.51.1-0.20260205185216-81bc641f26c0 h1:WNkJ1bKnRVAEJtBm1bwEkoLG2x7GyANc3/OnErZJ338= +go.opentelemetry.io/collector/consumer v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:Erk6qdfVj+24QTrGCpurcrF+qdUlHkb4dgMy5wJxLvY= +go.opentelemetry.io/collector/consumer/consumertest v0.145.1-0.20260205185216-81bc641f26c0 h1:FHyDIlTbqt0Y6tDI9EbI3hr9uWthwkeLY7uGF1jZYqQ= +go.opentelemetry.io/collector/consumer/consumertest v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:IFc/FeaIHQClb8KK0aVn0tFDNMc+/MmfQ+aBT1cJNeo= +go.opentelemetry.io/collector/consumer/xconsumer v0.145.1-0.20260205185216-81bc641f26c0 h1:zg2Jqfy7n7o/LEmLsXB4sFhxWtOEMFCKRyQUFLFUS9M= +go.opentelemetry.io/collector/consumer/xconsumer v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:SryDCLP2ZaFeZJtA2CSksJ0XvjH8k3LmlfXvy/kC7Wc= +go.opentelemetry.io/collector/featuregate v1.51.1-0.20260205185216-81bc641f26c0 h1:fOXhfT2xKqNhfalTXaT/Wic9EBRK8+9ZH0y8phReQS4= +go.opentelemetry.io/collector/featuregate v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:/1bclXgP91pISaEeNulRxzzmzMTm4I5Xih2SnI4HRSo= +go.opentelemetry.io/collector/internal/componentalias v0.145.1-0.20260205185216-81bc641f26c0 h1:s4/vCxeIxgQpuWmX1AK1DRbZmEdmNBq925EKES8ebiI= +go.opentelemetry.io/collector/internal/componentalias v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:Z0TtMbzaMp2qhj1dw4toya8toyQzqoTF46/WhJXplVw= +go.opentelemetry.io/collector/internal/testutil v0.145.0 h1:H/KL0GH3kGqSMKxZvnQ0B0CulfO9xdTg4DZf28uV7fY= +go.opentelemetry.io/collector/internal/testutil v0.145.0/go.mod h1:YAD9EAkwh/l5asZNbEBEUCqEjoL1OKMjAMoPjPqH76c= +go.opentelemetry.io/collector/pdata v1.51.1-0.20260205185216-81bc641f26c0 h1:8tgf9W3aW3vFabyVxPNHKsaoyUytudfVOQbqZI9xBHQ= +go.opentelemetry.io/collector/pdata v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:GoX1bjKDR++mgFKdT7Hynv9+mdgQ1DDXbjs7/Ww209Q= +go.opentelemetry.io/collector/pdata/pprofile v0.145.1-0.20260205185216-81bc641f26c0 h1:MJcnK8txYZlqHZyfZ1rVf66kt5/kEveIdR6KX//BY1Y= +go.opentelemetry.io/collector/pdata/pprofile v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:a60GC7wQPhLAixWzKbbP51QLwwc+J0Cmp4SurOlhGUk= +go.opentelemetry.io/collector/pdata/testdata v0.145.0 h1:iFsxsCMtE3lnAc/5kZbhZHpRv1OMmM+O5ry46xdQHbg= +go.opentelemetry.io/collector/pdata/testdata v0.145.0/go.mod h1:0y2ERArdzqmYdJHdKLKue+AUubSEGlwK49F+23+Mbic= +go.opentelemetry.io/collector/pipeline v1.51.1-0.20260205185216-81bc641f26c0 h1:1KP5gXGF9qN1mEzJupZDUQVIND35qe/0Hy6Cptvdk0s= +go.opentelemetry.io/collector/pipeline v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:xUrAqiebzYbrgxyoXSkk6/Y3oi5Sy3im2iCA51LwUAI= +go.opentelemetry.io/collector/processor v1.51.0 h1:PKpCzkLQmqaW08TOVh/zM0qx07Ihq+DR5J/OBkPiL9o= +go.opentelemetry.io/collector/processor v1.51.0/go.mod h1:rtIPFS+EFRAkG+CSwtjxs2IsIkuZStObvALeueD02XI= +go.opentelemetry.io/collector/processor/processorhelper v0.145.0 h1:vXdv6lHz20Tm3ZEsg0i6jPZJBQgy9kzk/PuqWhHWiiM= +go.opentelemetry.io/collector/processor/processorhelper v0.145.0/go.mod h1:3Ecpe5jHRHGf24EvJHeJ/ekK/a1DLByyq0CSUxjjURg= +go.opentelemetry.io/collector/processor/processortest v0.145.0 h1:RDGBmyZnHk7XVK/EdLt/8iPWj+QLStbbVi1nFTNR01s= +go.opentelemetry.io/collector/processor/processortest v0.145.0/go.mod h1:WAvxAzSojkdoZB915Z1lsVHCPDJBb2fepjJBjenrzjg= +go.opentelemetry.io/collector/processor/xprocessor v0.145.0 h1:DaIE7MxRlg0OL1o2P0GQZtmZeExAmVso3qWv8S0RLps= +go.opentelemetry.io/collector/processor/xprocessor v0.145.0/go.mod h1:kUwRyKBU/kjCmXodd+0z7CpvcP0A9G9/QL+MaJt4U2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= +go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= +go.opentelemetry.io/proto/slim/otlp v1.9.0 h1:fPVMv8tP3TrsqlkH1HWYUpbCY9cAIemx184VGkS6vlE= +go.opentelemetry.io/proto/slim/otlp v1.9.0/go.mod h1:xXdeJJ90Gqyll+orzUkY4bOd2HECo5JofeoLpymVqdI= +go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0 h1:o13nadWDNkH/quoDomDUClnQBpdQQ2Qqv0lQBjIXjE8= +go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0/go.mod h1:Gyb6Xe7FTi/6xBHwMmngGoHqL0w29Y4eW8TGFzpefGA= +go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0 h1:EiUYvtwu6PMrMHVjcPfnsG3v+ajPkbUeH+IL93+QYyk= +go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0/go.mod h1:mUUHKFiN2SST3AhJ8XhJxEoeVW12oqfXog0Bo8W3Ec4= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= @@ -434,14 +487,14 @@ go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -450,18 +503,18 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/exp v0.0.0-20260209203927-2842357ff358 h1:kpfSV7uLwKJbFSEgNhWzGSL47NDSF/5pYYQw1V0ub6c= +golang.org/x/exp v0.0.0-20260209203927-2842357ff358/go.mod h1:R3t0oliuryB5eenPWl3rrQxwnNM3WTwnsRZZiXLAAW8= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= -golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -473,11 +526,10 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= -golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= -golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -506,15 +558,15 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= -golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -522,10 +574,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -534,68 +586,68 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= -golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/api v0.251.0 h1:6lea5nHRT8RUmpy9kkC2PJYnhnDAB13LqrLSVQlMIE8= -google.golang.org/api v0.251.0/go.mod h1:Rwy0lPf/TD7+T2VhYcffCHhyyInyuxGjICxdfLqT7KI= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.280.0 h1:F4OfEHZhZh6a7uTufJAXXVd/2TQ8EjM4vZH+jX/vFYk= +google.golang.org/api v0.280.0/go.mod h1:oGKmPZRDoD3vdkf6MA7F4VNkR1rxCiuaPSkhsf3EolU= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= -google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= -google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= +google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= +google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI= +google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= +gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= -k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= -k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= -k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= -k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= -k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= -k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= -k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= -sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/mcs-api v0.3.0 h1:LjRvgzjMrvO1904GP6XBJSnIX221DJMyQlZOYt9LAnM= -sigs.k8s.io/mcs-api v0.3.0/go.mod h1:zZ5CK8uS6HaLkxY4HqsmcBHfzHuNMrY2uJy8T7jffK4= +k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= +k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= +k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= +k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= +k8s.io/client-go v0.36.2 h1:bfgxmFKc9CgqsgX4xKLAAdmTQlWee7Ob/HlDOrJ5TBI= +k8s.io/client-go v0.36.2/go.mod h1:1vgO4OAlfPnoLcb+Rze2GF5rAr14w8qjrYMoyXJzQj0= +k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= +k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 h1:A7Lby6ekC6nv+6oO38huCMFBRP0Os+tIeq1GkwxOQes= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/mcs-api v0.5.0 h1:UMgKuFFIRVEy4LR2LQovPnBkV9rgmZMT+sJO7MkaVj4= +sigs.k8s.io/mcs-api v0.5.0/go.mod h1:zZ5CK8uS6HaLkxY4HqsmcBHfzHuNMrY2uJy8T7jffK4= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/man/coredns-acl.7 b/man/coredns-acl.7 index f03731cc9c..7dcbf30ecd 100644 --- a/man/coredns-acl.7 +++ b/man/coredns-acl.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-ACL" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-ACL" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -7,7 +7,13 @@ .SH "DESCRIPTION" .PP -With \fB\fCacl\fR enabled, users are able to block or filter suspicious DNS queries by configuring IP filter rule sets, i.e. allowing authorized queries to recurse or blocking unauthorized queries. +With \fB\fCacl\fR enabled, users are able to block or filter suspicious DNS queries by configuring IP filter rule sets, i.e. allowing authorized queries or blocking unauthorized queries. + +.PP +When evaluating the rule sets, \fIacl\fP uses the source IP of the TCP/UDP headers of the DNS query received by CoreDNS. +This source IP will be different than the IP of the client originating the request in cases where the source IP of the request is changed in transit. For example: +* if the request passes though an intermediate forwarding DNS server or recursive DNS server before reaching CoreDNS +* if the request traverses a Source NAT before reaching CoreDNS .PP This plugin can be used multiple times per Server Block. @@ -27,7 +33,7 @@ acl [ZONES...] { .IP \(bu 4 \fBZONES\fP zones it should be authoritative for. If empty, the zones from the configuration block are used. .IP \(bu 4 -\fBACTION\fP (\fIallow\fP, \fIblock\fP, or \fIfilter\fP) defines the way to deal with DNS queries matched by this rule. The default action is \fIallow\fP, which means a DNS query not matched by any rules will be allowed to recurse. The difference between \fIblock\fP and \fIfilter\fP is that block returns status code of \fIREFUSED\fP while filter returns an empty set \fINOERROR\fP +\fBACTION\fP (\fIallow\fP, \fIblock\fP, \fIfilter\fP, or \fIdrop\fP) defines the way to deal with DNS queries matched by this rule. The default action is \fIallow\fP, which means a DNS query not matched by any rules will be allowed to recurse. The difference between \fIblock\fP and \fIfilter\fP is that block returns status code of \fIREFUSED\fP while filter returns an empty set \fINOERROR\fP. \fIdrop\fP however returns no response to the client. .IP \(bu 4 \fBQTYPE\fP is the query type to match for the requests to be allowed or blocked. Common resource record types are supported. \fB\fC*\fR stands for all record types. The default behavior for an omitted \fB\fCtype QTYPE...\fR is to match all kinds of DNS queries (same as \fB\fCtype *\fR). .IP \(bu 4 @@ -120,14 +126,34 @@ example.org { .fi .RE +.PP +Drop all DNS queries from 192.0.2.0/24: + +.PP +.RS + +.nf +\&. { + acl { + drop net 192.0.2.0/24 + } +} + +.fi +.RE + .SH "METRICS" .PP If monitoring is enabled (via the \fIprometheus\fP plugin) then the following metrics are exported: .IP \(bu 4 -\fB\fCcoredns_acl_blocked_requests_total{server, zone}\fR - counter of DNS requests being blocked. +\fB\fCcoredns_acl_blocked_requests_total{server, zone, view}\fR - counter of DNS requests being blocked. +.IP \(bu 4 +\fB\fCcoredns_acl_filtered_requests_total{server, zone, view}\fR - counter of DNS requests being filtered. +.IP \(bu 4 +\fB\fCcoredns_acl_allowed_requests_total{server, view}\fR - counter of DNS requests being allowed. .IP \(bu 4 -\fB\fCcoredns_acl_allowed_requests_total{server}\fR - counter of DNS requests being allowed. +\fB\fCcoredns_acl_dropped_requests_total{server, zone, view}\fR - counter of DNS requests being dropped. .PP diff --git a/man/coredns-any.7 b/man/coredns-any.7 index c17b34ca57..a578a8bf44 100644 --- a/man/coredns-any.7 +++ b/man/coredns-any.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-ANY" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-ANY" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-auto.7 b/man/coredns-auto.7 index 2362129d50..6253b90725 100644 --- a/man/coredns-auto.7 +++ b/man/coredns-auto.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-AUTO" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-AUTO" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -34,7 +34,8 @@ are used. used to extract the origin. \fBORIGIN_TEMPLATE\fP will be used as a template for the origin. Strings like \fB\fC{}\fR are replaced with the respective matches in the file name, e.g. \fB\fC{1}\fR is the first match, \fB\fC{2}\fR is the second. The default is: \fB\fCdb\.(.*) {1}\fR i.e. from a file with the -name \fB\fCdb.example.com\fR, the extracted origin will be \fB\fCexample.com\fR. +name \fB\fCdb.example.com\fR, the extracted origin will be \fB\fCexample.com\fR. \fBREGEXP\fP must not be longer +than 10000 characters. .IP \(bu 4 \fB\fCreload\fR interval to perform reloads of zones if SOA version changes and zonefiles. It specifies how often CoreDNS should scan the directory to watch for file removal and addition. Default is one minute. Value of \fB\fC0\fR means to not scan for changes and reload. eg. \fB\fC30s\fR checks zonefile every 30 seconds diff --git a/man/coredns-autopath.7 b/man/coredns-autopath.7 index 4840b8ab80..66bb63d06e 100644 --- a/man/coredns-autopath.7 +++ b/man/coredns-autopath.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-AUTOPATH" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-AUTOPATH" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -81,7 +81,7 @@ path) in the following case. To properly build the search path of a client \fIau the namespace of the a Pod making a DNS request. To do this, it relies on the \fIkubernetes\fP plugin's Pod cache to resolve the client's IP address to a Pod. The Pod cache is maintained by an API watch on Pods. When Pod IP assignments change, the Kubernetes API notifies CoreDNS via the API watch. -However, that notification is not instantaneous. In the case that a Pod is deleted, and it's IP is +However, that notification is not instantaneous. In the case that a Pod is deleted, and its IP is immediately provisioned to a Pod in another namespace, and that new Pod make a DNS lookup \fIbefore\fP the API watch can notify CoreDNS of the change, \fIautopath\fP will resolve the IP to the previous Pod's namespace. diff --git a/man/coredns-azure.7 b/man/coredns-azure.7 index dc92154fa6..07286280dc 100644 --- a/man/coredns-azure.7 +++ b/man/coredns-azure.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-AZURE" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-AZURE" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-bind.7 b/man/coredns-bind.7 index 2306bca15e..7f19afc9b7 100644 --- a/man/coredns-bind.7 +++ b/man/coredns-bind.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-BIND" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-BIND" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -17,23 +17,43 @@ If several addresses are provided, a listener will be open on each of the IP pro Each address has to be an IP or name of one of the interfaces of the host. Bind by interface name, binds to the IPs on that interface at the time of startup or reload (reload will happen with a SIGHUP or if the config file changes). .PP -If the given argument is an interface name, and that interface has serveral IP addresses, CoreDNS will listen on all of the interface IP addresses (including IPv4 and IPv6). +If the given argument is an interface name, and that interface has several IP addresses, CoreDNS will listen on all of the interface IP addresses (including IPv4 and IPv6). .SH "SYNTAX" +.PP +In its basic form, a simple bind uses this syntax: + .PP .RS .nf -bind ADDRESS ... +bind ADDRESS|IFACE ... .fi .RE .PP -\fBADDRESS\fP is an IP address to bind to. -When several addresses are provided a listener will be opened on each of the addresses. +You can also exclude some addresses with their IP address or interface name in expanded syntax: + +.PP +.RS + +.nf +bind ADDRESS|IFACE ... { + except ADDRESS|IFACE ... +} + +.fi +.RE + +.IP \(bu 4 +\fBADDRESS|IFACE\fP is an IP address or interface name to bind to. +When several addresses are provided a listener will be opened on each of the addresses. Please read the \fIDescription\fP for more details. +.IP \(bu 4 +\fB\fCexcept\fR, excludes interfaces or IP addresses to bind to. \fB\fCexcept\fR option only excludes addresses for the current \fB\fCbind\fR directive if multiple \fB\fCbind\fR directives are used in the same server block. .SH "EXAMPLES" + .PP To make your socket accessible only to that machine, bind to IP 127.0.0.1 (localhost): @@ -92,12 +112,35 @@ The following server block, binds on localhost with its interface name (both "12 .fi .RE +.PP +You can exclude some addresses by their IP or interface name (The following will only listen on \fB\fC::1\fR or whatever addresses have been assigned to the \fB\fClo\fR interface): + +.PP +.RS + +.nf +\&. { + bind lo { + except 127.0.0.1 + } +} + +.fi +.RE + .SH "BUGS" +.SS "AVOIDING LISTENER CONTENTION" +.PP +TL;DR, When adding the \fIbind\fP plugin to a server block, it must also be added to all other server blocks that listen on the same port. + .PP -When defining more than one server block, take care not to bind more than one server to the same -address and port. Doing so will result in unpredictable behavior (requests may be randomly -served by either server). Keep in mind that \fIwithout\fP the \fIbind\fP plugin, a server will bind to all -interfaces, and this will collide with another server if it's using \fIbind\fP to listen to an interface +When more than one server block is configured to listen to a common port, those server blocks must either +all use the \fIbind\fP plugin, or all use default binding (no \fIbind\fP plugin). Note that "port" here refers the TCP/UDP port that +a server block is configured to serve (default 53) - not a network interface. For two server blocks listening on the same port, +if one uses the bind plugin and the other does not, two separate listeners will be created that will contend for serving +packets destined to the same address. Doing so will result in unpredictable behavior (requests may be randomly +served by either server). This happens because \fIwithout\fP the \fIbind\fP plugin, a server will bind to all +interfaces, and this will collide with another server if it's using \fIbind\fP to listen to an address on the same port. For example, the following creates two servers that both listen on 127.0.0.1:53, which would result in unpredictable behavior for queries in \fB\fCa.bad.example.com\fR: diff --git a/man/coredns-bufsize.7 b/man/coredns-bufsize.7 index e5303e3636..e21a92618e 100644 --- a/man/coredns-bufsize.7 +++ b/man/coredns-bufsize.7 @@ -1,14 +1,20 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-BUFSIZE" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-BUFSIZE" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP -\fIbufsize\fP - sizes EDNS0 buffer size to prevent IP fragmentation. +\fIbufsize\fP - limits EDNS0 buffer size to prevent IP fragmentation. .SH "DESCRIPTION" .PP -\fIbufsize\fP limits a requester's UDP payload size. +\fIbufsize\fP limits a requester's UDP payload size to within a maximum value. +If a request with an OPT RR has a bufsize greater than the limit, the bufsize +of the request will be reduced. Otherwise the request is unaffected. It prevents IP fragmentation, mitigating certain DNS vulnerabilities. +It cannot increase UDP size requested by the client, it can be reduced only. +This will only affect queries that have +an OPT RR (EDNS(0) +\[la]https://www.rfc-editor.org/rfc/rfc6891\[ra]). .SH "SYNTAX" .PP @@ -22,7 +28,7 @@ bufsize [SIZE] .PP \fB[SIZE]\fP is an int value for setting the buffer size. -The default value is 512, and the value must be within 512 - 4096. +The default value is 1232, and the value must be within 512 - 4096. Only one argument is acceptable, and it covers both IPv4 and IPv6. .SH "EXAMPLES" @@ -34,7 +40,7 @@ Enable limiting the buffer size of outgoing query to the resolver (172.31.0.10): .nf \&. { - bufsize 512 + bufsize 1100 forward . 172.31.0.10 log } @@ -50,7 +56,7 @@ Enable limiting the buffer size as an authoritative nameserver: .nf \&. { - bufsize 512 + bufsize 1220 file db.example.org log } @@ -61,7 +67,5 @@ Enable limiting the buffer size as an authoritative nameserver: .SH "CONSIDERATIONS" .IP \(bu 4 Setting 1232 bytes to bufsize may avoid fragmentation on the majority of networks in use today, but it depends on the MTU of the physical network links. -.IP \(bu 4 -For now, if a client does not use EDNS, this plugin adds OPT RR. diff --git a/man/coredns-cache.7 b/man/coredns-cache.7 index b05eeae3f5..2e1a1e9fe3 100644 --- a/man/coredns-cache.7 +++ b/man/coredns-cache.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-CACHE" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-CACHE" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -12,8 +12,7 @@ With \fIcache\fP enabled, all records except zone transfers and metadata records database, etc.) is expensive. .PP -\fICache\fP will change the query to enable DNSSEC (DNSSEC OK; DO) if it passes through the plugin. If -the client didn't request any DNSSEC (records), these are filtered out when replying. +\fICache\fP will pass DNSSEC (DNSSEC OK; DO) options through the plugin for upstream queries. .PP This plugin can only be used once per Server Block. @@ -38,6 +37,11 @@ Setting a TTL of 300: \fB\fCcache 300\fR would cache records up to 300 seconds. .PP Each element in the cache is cached according to its TTL (with \fBTTL\fP as the max). +Note that \fBTTL\fP only caps the cache duration and does not extend it. A record with a 30s TTL +will still be cached for 30s even with \fB\fCcache 600\fR. The minimum cache duration defaults to 5 +seconds and can be adjusted per cache type using \fBMINTTL\fP in the \fB\fCsuccess\fR or \fB\fCdenial\fR directives. + +.PP A cache is divided into 256 shards, each holding up to 39 items by default - for a total size of 256 * 39 = 9984 items. @@ -52,7 +56,10 @@ cache [TTL] [ZONES...] { success CAPACITY [TTL] [MINTTL] denial CAPACITY [TTL] [MINTTL] prefetch AMOUNT [[DURATION] [PERCENTAGE%]] - serve\_stale [DURATION] + serve\_stale [DURATION] [REFRESH\_MODE] + servfail DURATION + disable success|denial [ZONES...] + keepttl } .fi @@ -76,10 +83,28 @@ Popular means \fBAMOUNT\fP queries have been seen with no gaps of \fBDURATION\fP which defaults to \fB\fC10%\fR, or latest 1 second before TTL expiration. Values should be in the range \fB\fC[10%, 90%]\fR. Note the percent sign is mandatory. \fBPERCENTAGE\fP is treated as an \fB\fCint\fR. .IP \(bu 4 -\fB\fCserve_stale\fR, when serve_stale is set, cache always will serve an expired entry to a client if there is one -available. When this happens, cache will attempt to refresh the cache entry after sending the expired cache -entry to the client. The responses have a TTL of 0. \fBDURATION\fP is how far back to consider -stale responses as fresh. The default duration is 1h. +\fB\fCserve_stale\fR, when serve_stale is set, cache will always serve an expired entry to a client if there is one +available as long as it has not been expired for longer than \fBDURATION\fP (default 1 hour). By default, the \fIcache\fP plugin will +attempt to refresh the cache entry after sending the expired cache entry to the client. The +responses have a TTL of 0. \fBREFRESH_MODE\fP controls the timing of the expired cache entry refresh. +\fB\fCverify\fR will first verify that an entry is still unavailable from the source before sending the expired entry to the client. +\fB\fCimmediate\fR will immediately send the expired entry to the client before +checking to see if the entry is available from the source. \fBREFRESH_MODE\fP defaults to \fB\fCimmediate\fR. Setting this +value to \fB\fCverify\fR can lead to increased latency when serving stale responses, but will prevent stale entries +from ever being served if an updated response can be retrieved from the source. +.IP \(bu 4 +\fB\fCservfail\fR cache SERVFAIL responses for \fBDURATION\fP. Setting \fBDURATION\fP to 0 will disable caching of SERVFAIL +responses. If this option is not set, SERVFAIL responses will be cached for 5 seconds. \fBDURATION\fP may not be +greater than 5 minutes. +.IP \(bu 4 +\fB\fCdisable\fR disable the success or denial cache for the listed \fBZONES\fP. If no \fBZONES\fP are given, the specified +cache will be disabled for all zones. +.IP \(bu 4 +\fB\fCkeepttl\fR do not age TTL when serving responses from cache. The entry will still be removed from cache +when the TTL expires as normal, but until it expires responses will include the original TTL instead +of the remaining TTL. This can be useful if CoreDNS is used as an authoritative server and you want +to serve a consistent TTL to downstream clients. This is \fBNOT\fP recommended when CoreDNS is caching +records it is not authoritative for because it could result in downstream clients using stale answers. .SH "CAPACITY AND EVICTION" @@ -98,17 +123,21 @@ Entries with 0 TTL will remain in the cache until randomly evicted when the shar If monitoring is enabled (via the \fIprometheus\fP plugin) then the following metrics are exported: .IP \(bu 4 -\fB\fCcoredns_cache_entries{server, type}\fR - Total elements in the cache by cache type. +\fB\fCcoredns_cache_entries{server, type, zones, view}\fR - Total elements in the cache by cache type. +.IP \(bu 4 +\fB\fCcoredns_cache_hits_total{server, type, zones, view}\fR - Counter of cache hits by cache type. .IP \(bu 4 -\fB\fCcoredns_cache_hits_total{server, type}\fR - Counter of cache hits by cache type. +\fB\fCcoredns_cache_misses_total{server, zones, view}\fR - Counter of cache misses. - Deprecated, derive misses from cache hits/requests counters. .IP \(bu 4 -\fB\fCcoredns_cache_misses_total{server}\fR - Counter of cache misses. +\fB\fCcoredns_cache_requests_total{server, zones, view}\fR - Counter of cache requests. .IP \(bu 4 -\fB\fCcoredns_cache_prefetch_total{server}\fR - Counter of times the cache has prefetched a cached item. +\fB\fCcoredns_cache_prefetch_total{server, zones, view}\fR - Counter of times the cache has prefetched a cached item. .IP \(bu 4 -\fB\fCcoredns_cache_drops_total{server}\fR - Counter of responses excluded from the cache due to request/response question name mismatch. +\fB\fCcoredns_cache_drops_total{server, zones, view}\fR - Counter of responses excluded from the cache due to request/response question name mismatch. .IP \(bu 4 -\fB\fCcoredns_cache_served_stale_total{server}\fR - Counter of requests served from stale cache entries. +\fB\fCcoredns_cache_served_stale_total{server, zones, view}\fR - Counter of requests served from stale cache entries. +.IP \(bu 4 +\fB\fCcoredns_cache_evictions_total{server, type, zones, view}\fR - Counter of cache evictions. .PP @@ -163,3 +192,19 @@ example.org { .fi .RE +.PP +Enable caching for \fB\fCexample.org\fR, but do not cache denials in \fB\fCsub.example.org\fR: + +.PP +.RS + +.nf +example.org { + cache { + disable denial sub.example.org + } +} + +.fi +.RE + diff --git a/man/coredns-cancel.7 b/man/coredns-cancel.7 index a0c83865b4..a1037b03bf 100644 --- a/man/coredns-cancel.7 +++ b/man/coredns-cancel.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-CANCEL" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-CANCEL" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-chaos.7 b/man/coredns-chaos.7 index a873d694b9..23e815ac22 100644 --- a/man/coredns-chaos.7 +++ b/man/coredns-chaos.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-CHAOS" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-CHAOS" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-clouddns.7 b/man/coredns-clouddns.7 index 3b83a3a59a..51ac55dd10 100644 --- a/man/coredns-clouddns.7 +++ b/man/coredns-clouddns.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-CLOUDDNS" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-CLOUDDNS" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -41,6 +41,13 @@ Therefore, for a non-existing resource record, SOA response will be from the rig accessed. .IP \(bu 4 \fB\fCcredentials\fR is used for reading the credential file from \fBFILENAME\fP (normally a .json file). +This field is optional. If this field is not provided then authentication will be done automatically, +e.g., through environmental variable \fB\fCGOOGLE_APPLICATION_CREDENTIALS\fR. Note that CoreDNS validates that the given +file has a valid credentials type, but does not validate the credentials file for malicious input. Please see +Google Cloud's authentication method +\[la]https://cloud.google.com/docs/authentication\[ra] and +validating credential configurations from external sources +\[la]https://docs.cloud.google.com/docs/authentication/client-libraries#external-credentials\[ra] for more details. .IP \(bu 4 \fB\fCfallthrough\fR If zone matches and no record can be generated, pass request to the next plugin. If \fB[ZONES...]\fP is omitted, then fallthrough happens for all zones for which the plugin is diff --git a/man/coredns-debug.7 b/man/coredns-debug.7 index 90ee34961e..ab034baece 100644 --- a/man/coredns-debug.7 +++ b/man/coredns-debug.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-DEBUG" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-DEBUG" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-dns64.7 b/man/coredns-dns64.7 index 7a5274cb24..7491460382 100644 --- a/man/coredns-dns64.7 +++ b/man/coredns-dns64.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-DNS64" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-DNS64" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -41,6 +41,7 @@ Or use this slightly longer form with more options: dns64 [PREFIX] { [translate\_all] prefix PREFIX + [allow\_ipv4] } .fi @@ -50,6 +51,8 @@ dns64 [PREFIX] { \fB\fCprefix\fR specifies any local IPv6 prefix to use, instead of the well known prefix (64:ff9b::/96) .IP \(bu 4 \fB\fCtranslate_all\fR translates all queries, including responses that have AAAA results. +.IP \(bu 4 +\fB\fCallow_ipv4\fR Allow translating queries if they come in over IPv4, default is IPv6 only translation. .SH "EXAMPLES" @@ -113,6 +116,25 @@ Enable translation even if an existing AAAA record is present. .fi .RE +.PP +Apply translation even to the requests which arrived over IPv4 network. Warning, the \fB\fCallow_ipv4\fR feature will apply +translations to requests coming from dual-stack clients. This means that a request for a client that sends an \fB\fCAAAA\fR +that would normal result in an \fB\fCNXDOMAIN\fR would get a translated result. +This may cause unwanted IPv6 dns64 traffic when a dualstack client would normally use the result of an \fB\fCA\fR record request. + +.PP +.RS + +.nf +\&. { + dns64 { + allow\_ipv4 + } +} + +.fi +.RE + .SH "METRICS" .PP If monitoring is enabled (via the \fIprometheus\fP plugin) then the following metrics are exported: diff --git a/man/coredns-dnssec.7 b/man/coredns-dnssec.7 index 7376e6b03b..d4c7249737 100644 --- a/man/coredns-dnssec.7 +++ b/man/coredns-dnssec.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-DNSSEC" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-DNSSEC" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -20,7 +20,7 @@ This plugin can only be used once per Server Block. .nf dnssec [ZONES... ] { - key file KEY... + key file|aws\_secretsmanager KEY... cache\_capacity CAPACITY } @@ -39,10 +39,13 @@ ZSK/KSK split. All signing operations are done online. Authenticated denial of existence is implemented with NSEC black lies. Using ECDSA as an algorithm is preferred as this leads to smaller signatures (compared to RSA). NSEC3 is \fInot\fP supported. +.PP +As the \fIdnssec\fP plugin can't see the original TTL of the RRSets it signs, it will always use 3600s +as the value. + .PP If multiple \fIdnssec\fP plugins are specified in the same zone, the last one specified will be -used (See bugs -\[la]#bugs\[ra]). +used. .IP \(bu 4 \fBZONES\fP zones that should be signed. If empty, the zones from the configuration block @@ -62,6 +65,36 @@ generated public key \fB\fCKexample.org+013+45330.key\fR generated private key \fB\fCKexample.org+013+45330.private\fR .RE +.IP \(bu 4 +\fB\fCkey aws_secretsmanager\fR indicates that \fBKEY\fP secret(s) should be read from AWS Secrets Manager. Secret +names or ARNs may be used. After generating the keys as described in the \fB\fCkey file\fR section, you can +store them in AWS Secrets Manager using the following AWS CLI v2 command: + + +.PP +.RS + +.nf + aws secretsmanager create\-secret \-\-name "Kexample.org.+013+45330" \\ + \-\-description "DNSSEC keys for example.org" \\ + \-\-secret\-string "$(jq \-n \-\-arg key "$(cat Kexample.org.+013+45330.key)" \\ + \-\-arg private "$(cat Kexample.org.+013+45330.private)" \\ + '{key: $key, private: $private}')" + +.fi +.RE + +.PP +This command reads the contents of the \fB\fC.key\fR and \fB\fC.private\fR files, constructs a JSON object, and stores it + as a new secret in AWS Secrets Manager with the specified name and description. CoreDNS will then fetch + the key data from AWS Secrets Manager when using the \fB\fCkey aws_secretsmanager\fR directive. + +.PP +AWS SDK for Go V2 +\[la]https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/#specifying-credentials\[ra] is used + for authentication with AWS Secrets Manager. Make sure the provided AWS credentials have the necessary + permissions (e.g., \fB\fCsecretsmanager:GetSecretValue\fR) to access the specified secrets in AWS Secrets Manager. + .IP \(bu 4 \fB\fCcache_capacity\fR indicates the capacity of the cache. The dnssec plugin uses a cache to store RRSIGs. The default for \fBCAPACITY\fP is 10000. @@ -100,6 +133,24 @@ example.org { .fi .RE +.PP +Sign responses for \fB\fCexample.org\fR with the key stored in AWS Secrets Manager under the secret name +"Kexample.org.+013+45330". + +.PP +.RS + +.nf +example.org { + dnssec { + key aws\_secretsmanager Kexample.org.+013+45330 + } + whoami +} + +.fi +.RE + .PP Sign responses for a kubernetes zone with the key "Kcluster.local+013+45129.key". diff --git a/man/coredns-dnstap.7 b/man/coredns-dnstap.7 index 6d39902505..a94c5c421f 100644 --- a/man/coredns-dnstap.7 +++ b/man/coredns-dnstap.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-DNSTAP" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-DNSTAP" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -20,7 +20,12 @@ Every message is sent to the socket as soon as it comes in, the \fIdnstap\fP plu .RS .nf -dnstap SOCKET [full] +dnstap SOCKET [full] [writebuffer] [queue] { + [identity IDENTITY] + [version VERSION] + [extra EXTRA] + [skipverify] +} .fi .RE @@ -29,6 +34,19 @@ dnstap SOCKET [full] \fBSOCKET\fP is the socket (path) supplied to the dnstap command line tool. .IP \(bu 4 \fB\fCfull\fR to include the wire-format DNS message. +.IP \(bu 4 +\fBwritebuffer\fP sets the TCP write buffer multiplier in MiB. Valid range: [1, 1024]. +.IP \(bu 4 +\fBqueue\fP sets the queue multiplier, applied to 10,000 messages. Valid range: [1, 4096]. +.IP \(bu 4 +\fBIDENTITY\fP to override the identity of the server. Defaults to the hostname. +.IP \(bu 4 +\fBVERSION\fP to override the version field. Defaults to the CoreDNS version. +.IP \(bu 4 +\fBEXTRA\fP to define "extra" field in dnstap payload, metadata +\[la]../metadata/\[ra] replacement available here. +.IP \(bu 4 +\fB\fCskipverify\fR to skip tls verification during connection. Default to be secure .SH "EXAMPLES" @@ -44,6 +62,18 @@ dnstap /tmp/dnstap.sock .fi .RE +.PP +Log information about client requests and responses with a custom TCP write buffer (1024 MiB) and queue capacity (2048 x 10000). + +.PP +.RS + +.nf +dnstap /tmp/dnstap.sock full 1024 2048 + +.fi +.RE + .PP Log information including the wire-format DNS message about client requests and responses to \fI/tmp/dnstap.sock\fP. @@ -68,6 +98,78 @@ dnstap tcp://127.0.0.1:6000 full .fi .RE +.PP +Log to a remote endpoint by FQDN. + +.PP +.RS + +.nf +dnstap tcp://example.com:6000 full + +.fi +.RE + +.PP +Log to a socket, overriding the default identity and version. + +.PP +.RS + +.nf +dnstap /tmp/dnstap.sock { + identity my\-dns\-server1 + version MyDNSServer\-1.2.3 +} + +.fi +.RE + +.PP +Log to a socket, customize the "extra" field in dnstap payload. You may use metadata provided by other plugins in the extra field. + +.PP +.RS + +.nf +forward . 8.8.8.8 +metadata +dnstap /tmp/dnstap.sock { + extra "upstream: {/forward/upstream}" +} + +.fi +.RE + +.PP +Log to a remote TLS endpoint. + +.PP +.RS + +.nf +dnstap tls://127.0.0.1:6000 full { + skipverify +} + +.fi +.RE + +.PP +You can use \fIdnstap\fP more than once to define multiple taps. The following logs information including the +wire-format DNS message about client requests and responses to \fI/tmp/dnstap.sock\fP, +and also sends client requests and responses without wire-format DNS messages to a remote FQDN. + +.PP +.RS + +.nf +dnstap /tmp/dnstap.sock full +dnstap tcp://example.com:6000 + +.fi +.RE + .SH "COMMAND LINE TOOL" .PP Dnstap has a command line tool that can be used to inspect the logging. The tool can be found @@ -112,16 +214,18 @@ $ dnstap \-l 127.0.0.1:6000 .SH "USING DNSTAP IN YOUR PLUGIN" .PP -In your setup function, check to see if the \fIdnstap\fP plugin is loaded: +In your setup function, collect and store a list of all \fIdnstap\fP plugins loaded in the config: .PP .RS .nf +x := \&ExamplePlugin{} + c.OnStartup(func() error { if taph := dnsserver.GetConfig(c).Handler("dnstap"); taph != nil { - if tapPlugin, ok := taph.(dnstap.Dnstap); ok { - f.tapPlugin = \&tapPlugin + for tapPlugin, ok := taph.(*dnstap.Dnstap); ok; tapPlugin, ok = tapPlugin.Next.(*dnstap.Dnstap) { + x.tapPlugins = append(x.tapPlugins, tapPlugin) } } return nil @@ -137,8 +241,15 @@ And then in your plugin: .RS .nf -func (x RandomPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { - if tapPlugin != nil { +import ( + "github.com/coredns/coredns/plugin/dnstap/msg" + "github.com/coredns/coredns/request" + + tap "github.com/dnstap/golang\-dnstap" +) + +func (x ExamplePlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + for \_, tapPlugin := range x.tapPlugins { q := new(msg.Msg) msg.SetQueryTime(q, time.Now()) msg.SetQueryAddress(q, w.RemoteAddr()) @@ -147,7 +258,12 @@ func (x RandomPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns q.QueryMessage = buf } msg.SetType(q, tap.Message\_CLIENT\_QUERY) + + // if no metadata interpretation is needed, just send the message tapPlugin.TapMessage(q) + + // OR: to interpret the metadata in "extra" field, give more context info + tapPlugin.TapMessageWithMetadata(ctx, q, request.Request{W: w, Req: query}) } // ... } diff --git a/man/coredns-erratic.7 b/man/coredns-erratic.7 index c851536581..71d88c4d5a 100644 --- a/man/coredns-erratic.7 +++ b/man/coredns-erratic.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-ERRATIC" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-ERRATIC" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-errors.7 b/man/coredns-errors.7 index b296fa3247..7357a5956f 100644 --- a/man/coredns-errors.7 +++ b/man/coredns-errors.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-ERRORS" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-ERRORS" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -33,14 +33,19 @@ Extra knobs are available with an expanded syntax: .nf errors { - consolidate DURATION REGEXP + stacktrace + consolidate DURATION REGEXP [LEVEL] [show\_first] } .fi .RE .PP -Option \fB\fCconsolidate\fR allows collecting several error messages matching the regular expression \fBREGEXP\fP during \fBDURATION\fP. After the \fBDURATION\fP since receiving the first such message, the consolidated message will be printed to standard output, e.g. +Option \fB\fCstacktrace\fR will log a stacktrace during panic recovery. + +.PP +Option \fB\fCconsolidate\fR allows collecting several error messages matching the regular expression \fBREGEXP\fP during \fBDURATION\fP. \fBREGEXP\fP must not exceed 10000 characters. After the \fBDURATION\fP since receiving the first such message, the consolidated message will be printed to standard output with +log level, which is configurable by optional option \fBLEVEL\fP. Supported options for \fBLEVEL\fP option are \fB\fCwarning\fR,\fB\fCerror\fR,\fB\fCinfo\fR and \fB\fCdebug\fR. .PP .RS @@ -51,6 +56,36 @@ Option \fB\fCconsolidate\fR allows collecting several error messages matching th .fi .RE +.PP +If the optional \fB\fCshow_first\fR flag is specified, the first error will be logged immediately when it occurs, and then subsequent matching errors will be consolidated. When the consolidation period ends: +- If only one error occurred, no summary is printed (since it was already logged) +- If multiple errors occurred, a summary is printed showing the total count + +.PP +Example with 3 errors: + +.PP +.RS + +.nf +[WARNING] 2 example.org. A: read udp 10.0.0.1:53\->8.8.8.8:53: i/o timeout +[WARNING] 3 errors like '^read udp .* i/o timeout$' occurred in last 30s + +.fi +.RE + +.PP +Example with 1 error: + +.PP +.RS + +.nf +[WARNING] 2 example.org. A: read udp 10.0.0.1:53\->8.8.8.8:53: i/o timeout + +.fi +.RE + .PP Multiple \fB\fCconsolidate\fR options with different \fBDURATION\fP and \fBREGEXP\fP are allowed. In case if some error message corresponds to several defined regular expressions the message will be associated with the first appropriate \fBREGEXP\fP. @@ -74,7 +109,9 @@ example.org { .RE .PP -Use the \fIforward\fP to resolve queries via 8.8.8.8 and print consolidated error messages for errors with suffix " i/o timeout" or with prefix "Failed to ". +Use the \fIforward\fP plugin to resolve queries via 8.8.8.8 and print consolidated messages +for errors with suffix " i/o timeout" as warnings, +and errors with prefix "Failed to " as errors. .PP .RS @@ -83,7 +120,7 @@ Use the \fIforward\fP to resolve queries via 8.8.8.8 and print consolidated erro \&. { forward . 8.8.8.8 errors { - consolidate 5m ".* i/o timeout$" + consolidate 5m ".* i/o timeout$" warning consolidate 30s "^Failed to .+" } } @@ -91,3 +128,22 @@ Use the \fIforward\fP to resolve queries via 8.8.8.8 and print consolidated erro .fi .RE +.PP +Use the \fIforward\fP plugin and consolidate timeout errors with \fB\fCshow_first\fR option to see both +the summary and the first occurrence of the error: + +.PP +.RS + +.nf +\&. { + forward . 8.8.8.8 + errors { + consolidate 5m ".* i/o timeout$" warning show\_first + consolidate 30s "^Failed to .+" error show\_first + } +} + +.fi +.RE + diff --git a/man/coredns-etcd.7 b/man/coredns-etcd.7 index f3484adde4..0a384f7272 100644 --- a/man/coredns-etcd.7 +++ b/man/coredns-etcd.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-ETCD" 7 "August 2025" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-ETCD" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-file.7 b/man/coredns-file.7 index 972ac3d476..14f3958259 100644 --- a/man/coredns-file.7 +++ b/man/coredns-file.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-FILE" 7 "May 2025" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-FILE" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-forward.7 b/man/coredns-forward.7 index c6f608d248..4d88c558d6 100644 --- a/man/coredns-forward.7 +++ b/man/coredns-forward.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-FORWARD" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-FORWARD" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -22,9 +22,6 @@ is taken as a healthy upstream. The health check uses the same protocol as speci When \fIall\fP upstreams are down it assumes health checking as a mechanism has failed and will try to connect to a random upstream (which may or may not work). -.PP -This plugin can only be used once per Server Block. - .SH "SYNTAX" .PP In its most basic form, a simple forwarder uses this syntax: @@ -39,7 +36,8 @@ forward FROM TO... .RE .IP \(bu 4 -\fBFROM\fP is the base domain to match for the request to be forwarded. +\fBFROM\fP is the base domain to match for the request to be forwarded. Domains using CIDR notation +that expand to multiple reverse zones are not fully supported; only the first expanded zone is used. .IP \(bu 4 \fBTO...\fP are the destination endpoints to forward to. The \fBTO\fP syntax allows you to specify a protocol, \fB\fCtls://9.9.9.9\fR or \fB\fCdns://\fR (or no protocol) for plain DNS. The number of upstreams is @@ -62,12 +60,17 @@ forward FROM TO... { force\_tcp prefer\_udp expire DURATION + max\_idle\_conns INTEGER max\_fails INTEGER + max\_connect\_attempts INTEGER tls CERT KEY CA tls\_servername NAME policy random|round\_robin|sequential - health\_check DURATION [no\_rec] + health\_check DURATION [no\_rec] [domain FQDN] max\_concurrent MAX + next RCODE\_1 [RCODE\_2] [RCODE\_3...] + failfast\_all\_unhealthy\_upstreams + failover RCODE\_1 [RCODE\_2] [RCODE\_3...] } .fi @@ -89,8 +92,15 @@ Requests that match none of these names will be passed through. an upstream to be down. If 0, the upstream will never be marked as down (nor health checked). Default is 2. .IP \(bu 4 +\fB\fCmax_connect_attempts\fR caps the total number of upstream connect attempts +performed for a single incoming DNS request. Default value of 0 means no per-request +cap. +.IP \(bu 4 \fB\fCexpire\fR \fBDURATION\fP, expire (cached) connections after this time, the default is 10s. .IP \(bu 4 +\fB\fCmax_idle_conns\fR \fBINTEGER\fP, maximum number of idle connections to cache per upstream for reuse. +Default is 0, which means unlimited. +.IP \(bu 4 \fB\fCtls\fR \fBCERT\fP \fBKEY\fP \fBCA\fP define the TLS properties for TLS connection. From 0 to 3 arguments can be provided with the meaning as described below @@ -109,9 +119,18 @@ The server certificate is verified using the specified CA file .RE .IP \(bu 4 \fB\fCtls_servername\fR \fBNAME\fP allows you to set a server name in the TLS configuration; for instance 9.9.9.9 -needs this to be set to \fB\fCdns.quad9.net\fR. Multiple upstreams are still allowed in this scenario, -but they have to use the same \fB\fCtls_servername\fR. E.g. mixing 9.9.9.9 (QuadDNS) with 1.1.1.1 -(Cloudflare) will not work. +needs this to be set to \fB\fCdns.quad9.net\fR. Using TLS forwarding but not setting \fB\fCtls_servername\fR results in anyone +being able to man-in-the-middle your connection to the DNS server you are forwarding to. Because of this, +it is strongly recommended to set this value when using TLS forwarding. + + +.PP +Per destination endpoint TLS server name indication is possible in the form of \fB\fCtls://9.9.9.9%dns.quad9.net\fR. + \fB\fCtls_servername\fR must not be specified when using per destination endpoint TLS server name indication + as it would introduce clash between the server name indication spectifications. If destination endpoint + is to be reached via a port other than 853 then the port must be appended to the end of the destination + endpoint specifier. In case of port 10853, the above string would be: \fB\fCtls://9.9.9.9%dns.quad9.net:10853\fR. + .IP \(bu 4 \fB\fCpolicy\fR specifies the policy to use for selecting upstream servers. The default is \fB\fCrandom\fR. @@ -133,6 +152,9 @@ but they have to use the same \fB\fCtls_servername\fR. E.g. mixing 9.9.9.9 (Quad .IP \(en 4 \fB\fCno_rec\fR - optional argument that sets the RecursionDesired-flag of the dns-query used in health checking to \fB\fCfalse\fR. The flag is default \fB\fCtrue\fR. +.IP \(en 4 +\fB\fCdomain FQDN\fR - set the domain name used for health checks to \fBFQDN\fP. +If not configured, the domain name used for health checks is \fB\fC.\fR. .RE .IP \(bu 4 @@ -141,17 +163,23 @@ raise the number of concurrent queries above the \fBMAX\fP will result in a REFU response does not count as a health failure. When choosing a value for \fBMAX\fP, pick a number at least greater than the expected \fIupstream query rate\fP * \fIlatency\fP of the upstream servers. As an upper bound for \fBMAX\fP, consider that each concurrent query will use about 2kb of memory. +.IP \(bu 4 +\fB\fCnext\fR If the \fB\fCRCODE\fR (i.e. \fB\fCNXDOMAIN\fR) is returned by the remote then execute the next plugin. If no next plugin is defined, or the next plugin is not a \fB\fCforward\fR plugin, this setting is ignored +.IP \(bu 4 +\fB\fCfailfast_all_unhealthy_upstreams\fR - determines the handling of requests when all upstream servers are unhealthy and unresponsive to health checks. Enabling this option will immediately return SERVFAIL responses for all requests. By default, requests are sent to a random upstream. +.IP \(bu 4 +\fB\fCfailover\fR - By default when a DNS lookup fails to return a DNS response (e.g. timeout), \fIforward\fP will attempt a lookup on the next upstream server. The \fB\fCfailover\fR option will make \fIforward\fP do the same for any response with a response code matching an \fB\fCRCODE\fR ( e.g. \fB\fCSERVFAIL\fR、\fB\fCREFUSED\fR). \fB\fCNOERROR\fR cannot be used. If all upstreams have been tried, the response from the last attempt is returned. .PP Also note the TLS config is "global" for the whole forwarding proxy if you need a different -\fB\fCtls-name\fR for different upstreams you're out of luck. +\fB\fCtls_servername\fR for different upstreams you're out of luck. .PP On each endpoint, the timeouts for communication are set as follows: .IP \(bu 4 -The dial timeout by default is 30s, and can decrease automatically down to 100ms based on early results. +The dial timeout by default is 30s, and can decrease automatically down to 1s based on early results. .IP \(bu 4 The read timeout is static at 2s. @@ -170,28 +198,35 @@ plugin is also enabled: If monitoring is enabled (via the \fIprometheus\fP plugin) then the following metric are exported: .IP \(bu 4 -\fB\fCcoredns_forward_requests_total{to}\fR - query count per upstream. -.IP \(bu 4 -\fB\fCcoredns_forward_responses_total{to}\fR - Counter of responses received per upstream. -.IP \(bu 4 -\fB\fCcoredns_forward_request_duration_seconds{to, rcode, type}\fR - duration per upstream, RCODE, type -.IP \(bu 4 -\fB\fCcoredns_forward_responses_total{to, rcode}\fR - count of RCODEs per upstream. -.IP \(bu 4 -\fB\fCcoredns_forward_healthcheck_failures_total{to}\fR - number of failed health checks per upstream. -.IP \(bu 4 -\fB\fCcoredns_forward_healthcheck_broken_total{}\fR - counter of when all upstreams are unhealthy, +\fB\fCcoredns_forward_healthcheck_broken_total{}\fR - count of when all upstreams are unhealthy, and we are randomly (this always uses the \fB\fCrandom\fR policy) spraying to an upstream. .IP \(bu 4 -\fB\fCcoredns_forward_max_concurrent_rejects_total{}\fR - counter of the number of queries rejected because the +\fB\fCcoredns_forward_max_concurrent_rejects_total{}\fR - count of queries rejected because the number of concurrent queries were at maximum. .IP \(bu 4 -\fB\fCcoredns_forward_conn_cache_hits_total{to, proto}\fR - counter of connection cache hits per upstream and protocol. +\fB\fCcoredns_proxy_request_duration_seconds{proxy_name="forward", to, rcode}\fR - histogram per upstream, RCODE +.IP \(bu 4 +\fB\fCcoredns_proxy_healthcheck_failures_total{proxy_name="forward", to, rcode}\fR- count of failed health checks per upstream. .IP \(bu 4 -\fB\fCcoredns_forward_conn_cache_misses_total{to, proto}\fR - counter of connection cache misses per upstream and protocol. +\fB\fCcoredns_proxy_conn_cache_hits_total{proxy_name="forward", to, proto}\fR- count of connection cache hits per upstream and protocol. +.IP \(bu 4 +\fB\fCcoredns_proxy_conn_cache_misses_total{proxy_name="forward", to, proto}\fR - count of connection cache misses per upstream and protocol. + + +.PP Where \fB\fCto\fR is one of the upstream servers (\fBTO\fP from the config), \fB\fCrcode\fR is the returned RCODE from the upstream, \fB\fCproto\fR is the transport protocol like \fB\fCudp\fR, \fB\fCtcp\fR, \fB\fCtcp-tls\fR. +.PP +The following metrics have recently been deprecated: +* \fB\fCcoredns_forward_healthcheck_failures_total{to, rcode}\fR + * Can be replaced with \fB\fCcoredns_proxy_healthcheck_failures_total{proxy_name="forward", to, rcode}\fR +* \fB\fCcoredns_forward_requests_total{to}\fR + * Can be replaced with \fB\fCsum(coredns_proxy_request_duration_seconds_count{proxy_name="forward", to})\fR +* \fB\fCcoredns_forward_responses_total{to, rcode}\fR + * Can be replaced with \fB\fCcoredns_proxy_request_duration_seconds_count{proxy_name="forward", to, rcode}\fR +* \fB\fCcoredns_forward_request_duration_seconds{to, rcode}\fR + * Can be replaced with \fB\fCcoredns_proxy_request_duration_seconds{proxy_name="forward", to, rcode}\fR .SH "EXAMPLES" .PP @@ -208,6 +243,52 @@ example.org { .fi .RE +.PP +Send all requests within \fB\fClab.example.local.\fR to \fB\fC10.20.0.1\fR, all requests within \fB\fCexample.local.\fR (and not in +\fB\fClab.example.local.\fR) to \fB\fC10.0.0.1\fR, all others requests to the servers defined in \fB\fC/etc/resolv.conf\fR, and +caches results. Note that a CoreDNS server configured with multiple \fIforward\fP plugins in a server block will evaluate those +forward plugins in the order they are listed when serving a request. Therefore, subdomains should be +placed before parent domains otherwise subdomain requests will be forwarded to the parent domain's upstream. +Accordingly, in this example \fB\fClab.example.local\fR is before \fB\fCexample.local\fR, and \fB\fCexample.local\fR is before \fB\fC.\fR. + +.PP +.RS + +.nf +\&. { + cache + forward lab.example.local 10.20.0.1 + forward example.local 10.0.0.1 + forward . /etc/resolv.conf +} + +.fi +.RE + +.PP +The example above is almost equivalent to the following example, except that example below defines three separate plugin +chains (and thus 3 separate instances of \fIcache\fP). + +.PP +.RS + +.nf +lab.example.local { + cache + forward . 10.20.0.1 +} +example.local { + cache + forward . 10.0.0.1 +} +\&. { + cache + forward . /etc/resolv.conf +} + +.fi +.RE + .PP Load balance all requests between three resolvers, one of which has a IPv6 address. @@ -275,6 +356,24 @@ service with health checks. .fi .RE +.PP +Or configure other domain name for health check requests + +.PP +.RS + +.nf +\&. { + forward . tls://9.9.9.9 { + tls\_servername dns.quad9.net + health\_check 5s domain example.org + } + cache 30 +} + +.fi +.RE + .PP Or with multiple upstreams from the same provider @@ -305,13 +404,13 @@ Or when you have multiple DoT upstreams with different \fB\fCtls_servername\fRs, } \&.:5301 { - forward . 8.8.8.8 8.8.4.4 { + forward . tls://8.8.8.8 tls://8.8.4.4 { tls\_servername dns.google } } \&.:5302 { - forward . 1.1.1.1 1.0.0.1 { + forward . tls://1.1.1.1 tls://1.0.0.1 { tls\_servername cloudflare\-dns.com } } @@ -319,6 +418,44 @@ Or when you have multiple DoT upstreams with different \fB\fCtls_servername\fRs, .fi .RE +.PP +The following would try 1.2.3.4 first. If the response is \fB\fCNXDOMAIN\fR, try 5.6.7.8. If the response from 5.6.7.8 is \fB\fCNXDOMAIN\fR, try 9.0.1.2. + +.PP +.RS + +.nf +\&. { + forward . 1.2.3.4 { + next NXDOMAIN + } + forward . 5.6.7.8 { + next NXDOMAIN + } + forward . 9.0.1.2 { + } +} + +.fi +.RE + +.PP +In the following example, if the response from \fB\fC1.2.3.4\fR is \fB\fCSERVFAIL\fR or \fB\fCREFUSED\fR, it will try \fB\fC5.6.7.8\fR. If the response from \fB\fC5.6.7.8\fR is \fB\fCSERVFAIL\fR or \fB\fCREFUSED\fR, it will try \fB\fC9.0.1.2\fR. + +.PP +.RS + +.nf +\&. { + forward . 1.2.3.4 5.6.7.8 9.0.1.2 { + policy sequential + failover SERVFAIL REFUSED + } +} + +.fi +.RE + .SH "SEE ALSO" .PP RFC 7858 diff --git a/man/coredns-geoip.7 b/man/coredns-geoip.7 index 28104259d0..7d2b54db13 100644 --- a/man/coredns-geoip.7 +++ b/man/coredns-geoip.7 @@ -1,17 +1,20 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-GEOIP" 7 "July 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-GEOIP" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP -\fIgeoip\fP - Lookup maxmind geoip2 databases using the client IP, then add associated geoip data to the context request. +\fIgeoip\fP - Lookup \fB\fC.mmdb\fR (MaxMind db file format +\[la]https://maxmind.github.io/MaxMind-DB/\[ra]) databases using the client IP, then add associated geoip data to the context request. .SH "DESCRIPTION" .PP -The \fIgeoip\fP plugin add geo location data associated with the client IP, it allows you to configure a geoIP2 maxmind database -\[la]https://dev.maxmind.com/geoip/docs/databases\[ra] to add the geo location data associated with the IP address. +The \fIgeoip\fP plugin allows you to enrich the data associated with Client IP addresses, e.g. geoip information like City, Country, and Network ASN. GeoIP data is commonly available in the \fB\fC.mmdb\fR format, a database format that maps IPv4 and IPv6 addresses to data records using a binary search tree. .PP -The data is added leveraging the \fImetadata\fP plugin, values can then be retrieved using it as well, for example: +The data is added leveraging the \fImetadata\fP plugin, values can then be retrieved using it as well. + +.PP +\fBLongitude example:\fP .PP .RS @@ -34,13 +37,64 @@ if getLongitude := metadata.ValueFunc(ctx, "geoip/longitude"); getLongitude != n .fi .RE +.PP +\fBCity example:\fP + +.PP +.RS + +.nf +import ( + "github.com/coredns/coredns/plugin/metadata" +) +// ... +if getCity := metadata.ValueFunc(ctx, "geoip/city/name"); getCity != nil { + city := getCity() + // Do something useful with city. +} else { + // The metadata label geoip/city/name for some reason, was not set. +} +// ... + +.fi +.RE + +.PP +\fBASN example:\fP + +.PP +.RS + +.nf +import ( + "strconv" + "github.com/coredns/coredns/plugin/metadata" +) +// ... +if getASN := metadata.ValueFunc(ctx, "geoip/asn/number"); getASN != nil { + if asn, err := strconv.ParseUint(getASN(), 10, 32); err == nil { + // Do something useful with asn. + } +} +if getASNOrg := metadata.ValueFunc(ctx, "geoip/asn/org"); getASNOrg != nil { + asnOrg := getASNOrg() + // Do something useful with asnOrg. +} +// ... + +.fi +.RE + .SH "DATABASES" .PP -The supported databases use city schema such as \fB\fCCity\fR and \fB\fCEnterprise\fR. Other databases types with different schemas are not supported yet. +The supported databases use city schema such as \fB\fCASN\fR, \fB\fCCity\fR, and \fB\fCEnterprise\fR. \fB\fC.mmdb\fR files are generally supported, as long as their field names correctly map to the Metadata Labels below. Other database types with different schemas are not supported yet. .PP -You can download a free and public City database -\[la]https://dev.maxmind.com/geoip/geolite2-free-geolocation-data\[ra]. +Free and commercial GeoIP \fB\fC.mmdb\fR files are commonly available from vendors like MaxMind +\[la]https://dev.maxmind.com/geoip/docs/databases\[ra], IPinfo +\[la]https://ipinfo.io/developers/database-download\[ra], and IPtoASN +\[la]https://iptoasn.com/\[ra] which is Public Domain-licensed +\[la]https://opendatacommons.org/licenses/pddl/1-0/\[ra]. .SH "SYNTAX" .PP @@ -52,34 +106,88 @@ geoip [DBFILE] .fi .RE +.PP +or + +.PP +.RS + +.nf +geoip [DBFILE] { + [edns\-subnet] +} + +.fi +.RE + +.IP \(bu 4 +\fBDBFILE\fP the \fB\fCmmdb\fR database file path. We recommend updating your \fB\fCmmdb\fR database periodically for more accurate results. .IP \(bu 4 -\fBDBFILE\fP the mmdb database file path. +\fB\fCedns-subnet\fR: Optional. Use EDNS0 subnet +\[la]https://en.wikipedia.org/wiki/EDNS_Client_Subnet\[ra] (if present) for Geo IP instead of the source IP of the DNS request. This helps identifying the closest source IP address through intermediary DNS resolvers, and it also makes GeoIP testing easy: \fB\fCdig +subnet=1.2.3.4 @dns-server.example.com www.geo-aware.com\fR. +.PP +\fBNOTE:\fP due to security reasons, recursive DNS resolvers may mask a few bits off of the clients' IP address, which can cause inaccuracies in GeoIP resolution. + +.PP +There is no defined mask size in the standards, but there are examples: RFC 7871's example +\[la]https://datatracker.ietf.org/doc/html/rfc7871#section-13\[ra] conceals the last 72 bits of an IPv6 source address, and NS1 Help Center mentions +\[la]https://help.ns1.com/hc/en-us/articles/360020256573-About-the-EDNS-Client-Subnet-ECS-DNS-extension\[ra] that ECS-enabled DNS resolvers send only the first three octets (eg. /24) of the source IPv4 address. + .SH "EXAMPLES" .PP -The following configuration configures the \fB\fCCity\fR database. +The following configuration configures the \fB\fCCity\fR database, and looks up geolocation based on EDNS0 subnet if present. .PP .RS .nf \&. { - geoip /opt/geoip2/db/GeoLite2\-City.mmdb + geoip /opt/geoip2/db/GeoLite2\-City.mmdb { + edns\-subnet + } metadata # Note that metadata plugin must be enabled as well. } .fi .RE -.SH "METADATADA LABELS" +.PP +The \fIview\fP plugin can use \fIgeoip\fP metadata as selection criteria to provide GSLB functionality. +In this example, clients from the city "Exampleshire" will receive answers for \fB\fCexample.com\fR from the zone defined in +\fB\fCexample.com.exampleshire-db\fR. All other clients will receive answers from the zone defined in \fB\fCexample.com.db\fR. +Note that the order of the two \fB\fCexample.com\fR server blocks below is important; the default viewless server block +must be last. + +.PP +.RS + +.nf +example.com { + view exampleshire { + expr metadata('geoip/city/name') == 'Exampleshire' + } + geoip /opt/geoip2/db/GeoLite2\-City.mmdb + metadata + file example.com.exampleshire\-db +} + +example.com { + file example.com.db +} + +.fi +.RE + +.SH "METADATA LABELS" .PP A limited set of fields will be exported as labels, all values are stored using strings \fBregardless of their underlying value type\fP, and therefore you may have to convert it back to its original type, note that numeric values are always represented in base 10. .RS .TS allbox; -l l l l +l l l l l l l l . \fBLabel\fP\fB Type\fP\fB Example\fP\fB Description\fP \fB\fCgeoip/city/name\fR \fB\fCstring\fR \fB\fCCambridge\fR Then city name in English language. @@ -94,6 +202,10 @@ l l l l . \fB\fCgeoip/longitude\fR \fB\fCfloat64\fR \fB\fC0.1315\fR Base 10, max available precision. \fB\fCgeoip/timezone\fR \fB\fCstring\fR \fB\fCEurope/London\fR The timezone. \fB\fCgeoip/postalcode\fR \fB\fCstring\fR \fB\fCCB4\fR The postal code. +\fB\fCgeoip/subdivisions/code\fR \fB\fCstring\fR \fB\fCENG,TWH\fR Comma separated ISO 3166-2 +\[la]https://en.wikipedia.org/wiki/ISO_3166-2\[ra] subdivision(region) codes, e.g. first level (province), second level (state). +\fB\fCgeoip/asn/number\fR \fB\fCuint\fR \fB\fC396982\fR The autonomous system number. +\fB\fCgeoip/asn/org\fR \fB\fCstring\fR \fB\fCGOOGLE-CLOUD-PLATFORM\fR The autonomous system organization. .TE .RE @@ -102,7 +214,7 @@ l l l l . .RS .TS allbox; -l l +l l l l . \fBValue\fP\fB Continent (EN)\fP AF Africa @@ -116,3 +228,11 @@ SA South America .RE +.SH "NOTABLE CHANGES" +.IP \(bu 4 +In CoreDNS v1.13.2, the \fB\fCgeoip\fR plugin was upgraded to use \fB\fCoschwald/geoip2-golang/v2\fR +\[la]https://github.com/oschwald/geoip2-golang/blob/main/MIGRATION.md\[ra], the Go library that reads and parses \fB\fC.mmdb\fR +\[la]https://maxmind.github.io/MaxMind-DB/\[ra] databases. It has a small, but possibly-breaking change, where the \fB\fCLocation.Latitude\fR and \fB\fCLocation.Longitude\fR structs changed from value types to pointers (\fB\fCfloat64\fR → \fB\fC*float64\fR). In \fB\fCoschwald/geoip2-golang\fR v1, missing coordinates returned "0" (which is a valid location +\[la]https://en.wikipedia.org/wiki/Null_Island\[ra]), and in v2 they now return an empty string "". + + diff --git a/man/coredns-grpc.7 b/man/coredns-grpc.7 index d286cda0eb..f2aefd908f 100644 --- a/man/coredns-grpc.7 +++ b/man/coredns-grpc.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-GRPC" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-GRPC" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -48,6 +48,7 @@ grpc FROM TO... { tls CERT KEY CA tls\_servername NAME policy random|round\_robin|sequential + fallthrough [ZONES...] } .fi @@ -82,6 +83,13 @@ but they have to use the same \fB\fCtls_servername\fR. E.g. mixing 9.9.9.9 (Quad (Cloudflare) will not work. .IP \(bu 4 \fB\fCpolicy\fR specifies the policy to use for selecting upstream servers. The default is \fB\fCrandom\fR. +.IP \(bu 4 +\fB\fCfallthrough\fR \fB[ZONES...]\fP If a query results in NXDOMAIN from the gRPC backend, pass the request +to the next plugin instead of returning the NXDOMAIN response. This is useful when the gRPC backend +is authoritative for a zone but should not return authoritative NXDOMAIN responses for queries that +don't actually belong to that zone (e.g., search path queries). If \fB[ZONES...]\fP is omitted, then +fallthrough happens for all zones. If specific zones are listed, then only queries for those zones +will be subject to fallthrough. .PP @@ -198,6 +206,37 @@ Or with multiple upstreams from the same provider .fi .RE +.PP +Forward requests to a local upstream listening on a Unix domain socket. + +.PP +.RS + +.nf +\&. { + grpc . unix:///path/to/grpc.sock +} + +.fi +.RE + +.PP +Proxy requests for \fB\fCexample.org.\fR to a gRPC backend, but fallthrough to the next plugin for NXDOMAIN responses to handle search path queries correctly. + +.PP +.RS + +.nf +example.org { + grpc . 127.0.0.1:9005 { + fallthrough + } + forward . 8.8.8.8 +} + +.fi +.RE + .SH "BUGS" .PP The TLS config is global for the whole grpc proxy if you need a different \fB\fCtls_servername\fR for diff --git a/man/coredns-grpc_server.7 b/man/coredns-grpc_server.7 new file mode 100644 index 0000000000..3dfa8b25f7 --- /dev/null +++ b/man/coredns-grpc_server.7 @@ -0,0 +1,72 @@ +.\" Generated by Mmark Markdown Processer - mmark.miek.nl +.TH "COREDNS-GRPC_SERVER" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" + +.SH "NAME" +.PP +\fIgrpc_server\fP - configures DNS-over-gRPC server options. + +.SH "DESCRIPTION" +.PP +The \fIgrpc_server\fP plugin allows you to configure parameters for the DNS-over-gRPC server to fine-tune the security posture and performance of the server. + +.PP +This plugin can only be used once per gRPC listener block. + +.SH "SYNTAX" +.PP +.RS + +.nf +grpc\_server { + max\_streams POSITIVE\_INTEGER + max\_connections POSITIVE\_INTEGER +} + +.fi +.RE + +.IP \(bu 4 +\fB\fCmax_streams\fR limits the number of concurrent gRPC streams per connection. This helps prevent unbounded streams on a single connection, exhausting server resources. The default value is 256 if not specified. Set to 0 for unbounded. +.IP \(bu 4 +\fB\fCmax_connections\fR limits the number of concurrent TCP connections to the gRPC server. The default value is 200 if not specified. Set to 0 for unbounded. + + +.SH "EXAMPLES" +.PP +Set custom limits for maximum streams and connections: + +.PP +.RS + +.nf +grpc://.:8053 { + tls cert.pem key.pem + grpc\_server { + max\_streams 50 + max\_connections 100 + } + whoami +} + +.fi +.RE + +.PP +Set values to 0 for unbounded, matching CoreDNS behaviour before v1.14.0: + +.PP +.RS + +.nf +grpc://.:8053 { + tls cert.pem key.pem + grpc\_server { + max\_streams 0 + max\_connections 0 + } + whoami +} + +.fi +.RE + diff --git a/man/coredns-header.7 b/man/coredns-header.7 index c0e76e46df..0dbd89718b 100644 --- a/man/coredns-header.7 +++ b/man/coredns-header.7 @@ -1,14 +1,14 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-HEADER" 7 "July 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-HEADER" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP -\fIheader\fP - modifies the header for responses. +\fIheader\fP - modifies the header for queries and responses. .SH "DESCRIPTION" .PP -\fIheader\fP ensures that the flags are in the desired state for responses. The modifications are made transparently for -the client. +\fIheader\fP ensures that the flags are in the desired state for queries and responses. +The modifications are made transparently for the client and subsequent plugins. .SH "SYNTAX" .PP @@ -16,13 +16,15 @@ the client. .nf header { - ACTION FLAGS... - ACTION FLAGS... + SELECTOR ACTION FLAGS... + SELECTOR ACTION FLAGS... } .fi .RE +.IP \(bu 4 +\fBSELECTOR\fP defines if the action should be applied on \fB\fCquery\fR or \fB\fCresponse\fR. .IP \(bu 4 \fBACTION\fP defines the state for DNS message header flags. Actions are evaluated in the order they are defined so last one has the most precedence. Allowed values are: @@ -58,7 +60,7 @@ Make sure recursive available \fB\fCra\fR flag is set in all the responses: .nf \&. { header { - set ra + response set ra } } @@ -74,8 +76,24 @@ Make sure "recursion available" \fB\fCra\fR and "authoritative answer" \fB\fCaa\ .nf \&. { header { - set ra aa - clear rd + response set ra aa + response clear rd + } +} + +.fi +.RE + +.PP +Make sure "recursion desired" \fB\fCrd\fR is set for all subsequent plugins:: + +.PP +.RS + +.nf +\&. { + header { + query set rd } } diff --git a/man/coredns-health.7 b/man/coredns-health.7 index 388d4e96ce..0db899642d 100644 --- a/man/coredns-health.7 +++ b/man/coredns-health.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-HEALTH" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-HEALTH" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -40,7 +40,7 @@ health [ADDRESS] { .IP \(bu 4 Where \fB\fClameduck\fR will delay shutdown for \fBDURATION\fP. /health will still answer 200 OK. -Note: The \fIready\fP plugin will not answer OK while CoreDNS is in lameduck mode prior to shutdown. +Note: The \fIready\fP plugin will not answer OK while CoreDNS is in lame duck mode prior to shutdown. .PP @@ -69,16 +69,19 @@ Doing this is supported but both endpoints ":8080" and ":8081" will export the e .SH "METRICS" .PP -If monitoring is enabled (via the \fIprometheus\fP plugin) then the following metric is exported: +If monitoring is enabled (via the \fIprometheus\fP plugin) then the following metrics are exported: .IP \(bu 4 -\fB\fCcoredns_health_request_duration_seconds{}\fR - duration to process a HTTP query to the local -\fB\fC/health\fR endpoint. As this a local operation it should be fast. A (large) increase in this +\fB\fCcoredns_health_request_duration_seconds{}\fR - The \fIhealth\fP plugin performs a self health check +once per second on the \fB\fC/health\fR endpoint. This metric is the duration to process that request. +As this is a local operation it should be fast. A (large) increase in this duration indicates the CoreDNS process is having trouble keeping up with its query load. +.IP \(bu 4 +\fB\fCcoredns_health_request_failures_total{}\fR - The number of times the self health check failed. .PP -Note that this metric \fIdoes not\fP have a \fB\fCserver\fR label, because being overloaded is a symptom of +Note that these metrics \fIdo not\fP have a \fB\fCserver\fR label, because being overloaded is a symptom of the running process, \fInot\fP a specific server. .SH "EXAMPLES" @@ -98,7 +101,7 @@ Run another health endpoint on http://localhost:8091 .RE .PP -Set a lameduck duration of 1 second: +Set a lame duck duration of 1 second: .PP .RS diff --git a/man/coredns-hosts.7 b/man/coredns-hosts.7 index 72bf9a9081..826dd0e68a 100644 --- a/man/coredns-hosts.7 +++ b/man/coredns-hosts.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-HOSTS" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-HOSTS" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP diff --git a/man/coredns-https.7 b/man/coredns-https.7 new file mode 100644 index 0000000000..d164e30719 --- /dev/null +++ b/man/coredns-https.7 @@ -0,0 +1,67 @@ +.\" Generated by Mmark Markdown Processer - mmark.miek.nl +.TH "COREDNS-HTTPS" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" + +.SH "NAME" +.PP +\fIhttps\fP - configures DNS-over-HTTPS (DoH) server options. + +.SH "DESCRIPTION" +.PP +The \fIhttps\fP plugin allows you to configure parameters for the DNS-over-HTTPS (DoH) server to fine-tune the security posture and performance of the server. + +.PP +This plugin can only be used once per HTTPS listener block. + +.SH "SYNTAX" +.PP +.RS + +.nf +https { + max\_connections POSITIVE\_INTEGER +} + +.fi +.RE + +.IP \(bu 4 +\fB\fCmax_connections\fR limits the number of concurrent TCP connections to the HTTPS server. The default value is 200 if not specified. Set to 0 for unbounded. + + +.SH "EXAMPLES" +.PP +Set custom limits for maximum connections: + +.PP +.RS + +.nf +https://.:443 { + tls cert.pem key.pem + https { + max\_connections 100 + } + whoami +} + +.fi +.RE + +.PP +Set values to 0 for unbounded, matching CoreDNS behaviour before v1.14.0: + +.PP +.RS + +.nf +https://.:443 { + tls cert.pem key.pem + https { + max\_connections 0 + } + whoami +} + +.fi +.RE + diff --git a/man/coredns-https3.7 b/man/coredns-https3.7 new file mode 100644 index 0000000000..fbcc2c3f20 --- /dev/null +++ b/man/coredns-https3.7 @@ -0,0 +1,67 @@ +.\" Generated by Mmark Markdown Processer - mmark.miek.nl +.TH "COREDNS-HTTPS3" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" + +.SH "NAME" +.PP +\fIhttps3\fP - configures DNS-over-HTTPS/3 (DoH3) server options. + +.SH "DESCRIPTION" +.PP +The \fIhttps3\fP plugin allows you to configure parameters for the DNS-over-HTTPS/3 (DoH3) server to fine-tune the security posture and performance of the server. HTTPS/3 uses QUIC as the underlying transport. + +.PP +This plugin can only be used once per HTTPS3 listener block. + +.SH "SYNTAX" +.PP +.RS + +.nf +https3 { + max\_streams POSITIVE\_INTEGER +} + +.fi +.RE + +.IP \(bu 4 +\fB\fCmax_streams\fR limits the number of concurrent QUIC streams per connection. This helps prevent unbounded streams on a single connection, exhausting server resources. The default value is 256 if not specified. Set to 0 to use underlying QUIC transport default. + + +.SH "EXAMPLES" +.PP +Set custom limits for maximum streams: + +.PP +.RS + +.nf +https3://.:443 { + tls cert.pem key.pem + https3 { + max\_streams 50 + } + whoami +} + +.fi +.RE + +.PP +Set values to 0 for QUIC transport default, matching CoreDNS behaviour before v1.14.0: + +.PP +.RS + +.nf +https3://.:443 { + tls cert.pem key.pem + https3 { + max\_streams 0 + } + whoami +} + +.fi +.RE + diff --git a/man/coredns-import.7 b/man/coredns-import.7 index dda17a022a..57dd1e1a35 100644 --- a/man/coredns-import.7 +++ b/man/coredns-import.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-IMPORT" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-IMPORT" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -29,6 +29,9 @@ import PATTERN this line, as if that file's contents appeared here to begin with. +.PP +Corefile may contain at most 10000 import statements. A glob pattern counts as a single import. The limit protects the configuration from recursive imports. + .SH "FILES" .PP You can use \fIimport\fP to include a file or files. This file's location is relative to the diff --git a/man/coredns-k8s_external.7 b/man/coredns-k8s_external.7 index f0b902e499..657620c736 100644 --- a/man/coredns-k8s_external.7 +++ b/man/coredns-k8s_external.7 @@ -1,19 +1,18 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-K8S_EXTERNAL" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-K8S_EXTERNAL" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP -\fIk8s_external\fP - resolves load balancer and external IPs from outside Kubernetes clusters. +\fIk8s_external\fP - resolves load balancer, external IPs from outside Kubernetes clusters and if enabled headless services. .SH "DESCRIPTION" .PP This plugin allows an additional zone to resolve the external IP address(es) of a Kubernetes -service. This plugin is only useful if the \fIkubernetes\fP plugin is also loaded. +service and headless services. This plugin is only useful if the \fIkubernetes\fP plugin is also loaded. .PP The plugin uses an external zone to resolve in-cluster IP addresses. It only handles queries for A, -AAAA and SRV records; all others result in NODATA responses. To make it a proper DNS zone, it handles -SOA and NS queries for the apex of the zone. +AAAA, SRV, and PTR records; To make it a proper DNS zone, it handles SOA and NS queries for the apex of the zone. .PP By default the apex of the zone will look like the following (assuming the zone used is \fB\fCexample.org\fR): @@ -82,6 +81,38 @@ k8s\_external [ZONE...] { \fB\fCttl\fR allows you to set a custom \fBTTL\fP for responses. The default is 5 (seconds). +.PP +If you want to enable headless service resolution, you can do so by adding \fB\fCheadless\fR option. + +.PP +.RS + +.nf +k8s\_external [ZONE...] { + headless +} + +.fi +.RE + +.IP \(bu 4 +if there is a headless service with external IPs set, external IPs will be resolved + + +.PP +If the queried domain does not exist, you can fall through to next plugin by adding the \fB\fCfallthrough\fR option. + +.PP +.RS + +.nf +k8s\_external [ZONE...] { + fallthrough [ZONE...] +} + +.fi +.RE + .SH "EXAMPLES" .PP Enable names under \fB\fCexample.org\fR to be resolved to in-cluster DNS addresses. @@ -119,12 +150,46 @@ spec: .fi .RE +.PP +The \fIk8s_external\fP plugin can be used in conjunction with the \fItransfer\fP plugin to enable +zone transfers. Notifies are not supported. + +.PP +.RS + +.nf + . { + transfer example.org { + to * + } + kubernetes cluster.local + k8s\_external example.org + } + +.fi +.RE + +.PP +With the \fB\fCfallthrough\fR option, if the queried domain does not exist, it will be passed to the next plugin that matches the zone. + +.PP +.RS + +.nf +\&. { + kubernetes cluster.local + k8s\_external example.org { + fallthrough + } + forward . 8.8.8.8 +} + +.fi +.RE + .PP For some background see resolve external IP address \[la]https://github.com/kubernetes/dns/issues/242\[ra]. And A records for services with Load Balancer IP \[la]https://github.com/coredns/coredns/issues/1851\[ra]. -.PP -PTR queries for the reverse zone is not supported. - diff --git a/man/coredns-kubernetes.7 b/man/coredns-kubernetes.7 index 078c73d604..06ce806a19 100644 --- a/man/coredns-kubernetes.7 +++ b/man/coredns-kubernetes.7 @@ -1,5 +1,5 @@ .\" Generated by Mmark Markdown Processer - mmark.miek.nl -.TH "COREDNS-KUBERNETES" 7 "March 2021" "CoreDNS" "CoreDNS Plugins" +.TH "COREDNS-KUBERNETES" 7 "March 2026" "CoreDNS" "CoreDNS Plugins" .SH "NAME" .PP @@ -50,6 +50,9 @@ kubernetes [ZONES...] { endpoint URL tls CERT KEY CACERT kubeconfig KUBECONFIG [CONTEXT] + apiserver\_qps QPS + apiserver\_burst BURST + apiserver\_max\_inflight MAX namespaces NAMESPACE... labels EXPRESSION pods POD\-MODE @@ -58,6 +61,8 @@ kubernetes [ZONES...] { noendpoints fallthrough [ZONES...] ignore empty\_service + multicluster [ZONES...] + startup\_timeout DURATION } .fi @@ -65,7 +70,8 @@ kubernetes [ZONES...] { .IP \(bu 4 \fB\fCendpoint\fR specifies the \fBURL\fP for a remote k8s API endpoint. -If omitted, it will connect to k8s in-cluster using the cluster service account. +If omitted, it will connect to k8s in-cluster using the cluster service account. Needs \fB\fCtls\fR for clusters with authentication. +This option is ignored if \fB\fCkubeconfig\fR is set. .IP \(bu 4 \fB\fCtls\fR \fBCERT\fP \fBKEY\fP \fBCACERT\fP are the TLS cert, key and the CA cert file names for remote k8s connection. This option is ignored if connecting in-cluster (i.e. endpoint is not specified). @@ -73,7 +79,16 @@ This option is ignored if connecting in-cluster (i.e. endpoint is not specified) \fB\fCkubeconfig\fR \fBKUBECONFIG [CONTEXT]\fP authenticates the connection to a remote k8s cluster using a kubeconfig file. \fB[CONTEXT]\fP is optional, if not set, then the current context specified in kubeconfig will be used. It supports TLS, username and password, or token-based authentication. -This option is ignored if connecting in-cluster (i.e., the endpoint is not specified). +This option is ignored if omitted. The cluster address in the \fB\fCkubeconfig\fR is given preference. +.IP \(bu 4 +\fB\fCapiserver_qps\fR \fBQPS\fP sets the maximum queries per second (QPS) rate limit for requests. +This allows you to control the rate at which the plugin sends requests to the API server to prevent overwhelming it. +.IP \(bu 4 +\fB\fCapiserver_burst\fR \fBBURST\fP sets the maximum burst size for requests. +This allows temporary spikes in request rate up to this value, even if it exceeds the QPS limit. +.IP \(bu 4 +\fB\fCapiserver_max_inflight\fR \fBMAX\fP sets the maximum number of concurrent in-flight requests. +This caps the total number of simultaneous requests the plugin can make to the API server. .IP \(bu 4 \fB\fCnamespaces\fR \fBNAMESPACE [NAMESPACE...]\fP only exposes the k8s namespaces listed. If this option is omitted all namespaces are exposed @@ -120,7 +135,7 @@ IP address (e.g., \fB\fC1-2-3-4.my-service.namespace.svc.cluster.local.\fR) If this directive is included, then name selection for endpoints changes as follows: Use the hostname of the endpoint, or if hostname is not set, use the pod name of the pod targeted by the endpoint. If there is no pod targeted by -the endpoint, use the dashed IP address form. +the endpoint or pod name is longer than 63, use the dashed IP address form. .IP \(bu 4 \fB\fCttl\fR allows you to set a custom TTL for responses. The default is 5 seconds. The minimum TTL allowed is 0 seconds, and the maximum is capped at 3600 seconds. Setting TTL to 0 will prevent records from being cached. @@ -138,16 +153,41 @@ queries for those zones will be subject to fallthrough. \fB\fCignore empty_service\fR returns NXDOMAIN for services without any ready endpoint addresses (e.g., ready pods). This allows the querying pod to continue searching for the service in the search path. The search path could, for example, include another Kubernetes cluster. +.IP \(bu 4 +\fB\fCmulticluster\fR defines the multicluster zones as defined by Multi-Cluster +Services API (MCS-API). Specifying this option is generally paired with the +installation of an MCS-API implementation and the ServiceImport and ServiceExport +CRDs. The plugin MUST be authoritative for the zones listed here. +.IP \(bu 4 +\fB\fCstartup_timeout\fR specifies the \fBDURATION\fP value that limits the time to wait for informer cache synced +when the kubernetes plugin starts. If not specified, the default timeout will be 5s. .PP Enabling zone transfer is done by using the \fItransfer\fP plugin. +.SH "STARTUP" +.PP +When CoreDNS starts with the \fIkubernetes\fP plugin enabled, it will delay serving DNS for up to 5 seconds +until it can connect to the Kubernetes API and synchronize all object watches. If this cannot happen within +5 seconds, then CoreDNS will start serving DNS while the \fIkubernetes\fP plugin continues to try to connect +and synchronize all object watches. CoreDNS will answer SERVFAIL to any request made for a Kubernetes record +that has not yet been synchronized. You can also determine how long to wait by specifying \fB\fCstartup_timeout\fR. + +.SH "MONITORING KUBERNETES ENDPOINTS" +.PP +The \fIkubernetes\fP plugin watches Endpoints via the \fB\fCdiscovery.EndpointSlices\fR API. + .SH "READY" .PP This plugin reports readiness to the ready plugin. This will happen after it has synced to the Kubernetes API. +.SH "PTR RECORDS" +.PP +This plugin creates PTR records for every Pod selected by a Service. If a given Pod is selected by more than +one Service a separate PTR record will exist for each Service selecting it. + .SH "EXAMPLES" .PP Handle all queries in the \fB\fCcluster.local\fR zone. Connect to Kubernetes in-cluster. Also handle all @@ -196,6 +236,20 @@ kubernetes cluster.local { .fi .RE +.PP +Configure multicluster + +.PP +.RS + +.nf +kubernetes cluster.local clusterset.local { + multicluster clusterset.local +} + +.fi +.RE + .SH "STUBDOMAINS AND UPSTREAMNAMESERVERS" .PP Here we use the \fIforward\fP plugin to implement a stubDomain that forwards \fB\fCexample.local\fR to the nameserver \fB\fC10.100.0.10:53\fR. @@ -256,37 +310,6 @@ cluster.local { .fi .RE -.SH "WILDCARDS" -.PP -Some query labels accept a wildcard value to match any value. If a label is a valid wildcard (*, -or the word "any"), then that label will match all values. The labels that accept wildcards are: - -.IP \(bu 4 -\fIendpoint\fP in an \fB\fCA\fR record request: \fIendpoint\fP.service.namespace.svc.zone, e.g., \fB\fC*.nginx.ns.svc.cluster.local\fR -.IP \(bu 4 -\fIservice\fP in an \fB\fCA\fR record request: \fIservice\fP.namespace.svc.zone, e.g., \fB\fC*.ns.svc.cluster.local\fR -.IP \(bu 4 -\fInamespace\fP in an \fB\fCA\fR record request: service.\fInamespace\fP.svc.zone, e.g., \fB\fCnginx.*.svc.cluster.local\fR -.IP \(bu 4 -\fIport and/or protocol\fP in an \fB\fCSRV\fR request: \fBport_.\fPprotocol_.service.namespace.svc.zone., -e.g., \fB\fC_http.*.service.ns.svc.cluster.local\fR -.IP \(bu 4 -multiple wildcards are allowed in a single query, e.g., \fB\fCA\fR Request \fB\fC*.*.svc.zone.\fR or \fB\fCSRV\fR request \fB\fC*.*.*.*.svc.zone.\fR - - -.PP -For example, wildcards can be used to resolve all Endpoints for a Service as \fB\fCA\fR records. e.g.: \fB\fC*.service.ns.svc.myzone.local\fR will return the Endpoint IPs in the Service \fB\fCservice\fR in namespace \fB\fCdefault\fR: - -.PP -.RS - -.nf -*.service.default.svc.cluster.local. 5 IN A 192.168.10.10 -*.service.default.svc.cluster.local. 5 IN A 192.168.25.15 - -.fi -.RE - .SH "METADATA" .PP The kubernetes plugin will publish the following metadata, if the \fImetadata\fP @@ -308,11 +331,14 @@ plugin is also enabled: \fB\fCkubernetes/client-namespace\fR: the client pod's namespace (see requirements below) .IP \(bu 4 \fB\fCkubernetes/client-pod-name\fR: the client pod's name (see requirements below) +.IP \(bu 4 +\fB\fCkubernetes/client-label/