diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 217bef2ada..c9397fc8ae 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -1,8 +1,13 @@ name: CIFuzz + on: pull_request: branches: - master + +permissions: + contents: read + jobs: Fuzzing: runs-on: ubuntu-latest diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c87a60ad49..30cd01710f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,15 +27,15 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Initialize CodeQL - uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 + uses: github/codeql-action/init@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 + uses: github/codeql-action/autobuild@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 + uses: github/codeql-action/analyze@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11 diff --git a/.github/workflows/depsreview.yml b/.github/workflows/depsreview.yml index 38c8f38d2f..9fc948280e 100644 --- a/.github/workflows/depsreview.yml +++ b/.github/workflows/depsreview.yml @@ -9,6 +9,6 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 + uses: actions/dependency-review-action@bc41886e18ea39df68b1b1245f4184881938e050 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a5a26214ea..8037b5a4b3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -20,13 +20,13 @@ jobs: DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} RELEASE: ${{ github.event.inputs.release || github.event.release.tag_name }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - 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@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PASSWORD }} diff --git a/.github/workflows/go.coverage.yml b/.github/workflows/go.coverage.yml index 0e47d03f31..2c249463da 100644 --- a/.github/workflows/go.coverage.yml +++ b/.github/workflows/go.coverage.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Setup Go Version run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV @@ -25,10 +25,10 @@ jobs: - name: Test With Coverage run: | - go install github.com/fatih/faillint@latest + 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@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 + uses: codecov/codecov-action@fdcc8476540edceab3de004e990f80d881c6cc00 # v5.5.0 diff --git a/.github/workflows/go.test.yml b/.github/workflows/go.test.yml index 5c17d0697c..06b9656952 100644 --- a/.github/workflows/go.test.yml +++ b/.github/workflows/go.test.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Setup Go Version run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Setup Go Version run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV @@ -56,7 +56,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Setup Go Version run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV @@ -72,7 +72,7 @@ jobs: - name: Test run: | - go install github.com/fatih/faillint@latest + go install github.com/fatih/faillint@c56e3ec6dbfc933bbeb884fd31f2bcd41f712657 # v1.15.0 ( cd test; go test -race ./... ) test-makefile-release: @@ -80,7 +80,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - 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 9580bc8164..1ad2763ea3 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -1,12 +1,17 @@ name: golangci-lint + on: pull_request: + +permissions: + contents: read + jobs: golangci: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Setup Go Version run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 @@ -15,4 +20,4 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 with: - version: v2.1.6 + version: v2.4.0 diff --git a/.github/workflows/make.doc.yml b/.github/workflows/make.doc.yml index af4ce5751d..471ca31bd7 100644 --- a/.github/workflows/make.doc.yml +++ b/.github/workflows/make.doc.yml @@ -4,7 +4,8 @@ on: schedule: - cron: '22 10 * * 0' -permissions: read-all +permissions: + contents: read jobs: fix: @@ -13,7 +14,7 @@ jobs: contents: write steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Setup Go Version run: echo "GO_VERSION=$(cat .go-version)" >> $GITHUB_ENV diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 44219fc901..d1b1b4bad4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,6 +7,9 @@ on: description: "Commit (e.g., 52f0348)" default: "master" +permissions: + contents: read + jobs: release: name: Release @@ -15,7 +18,7 @@ jobs: contents: write steps: - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ github.event.inputs.commit }} - name: Set up info diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 581ea704f8..68269a125e 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -23,7 +23,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -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@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 + uses: github/codeql-action/upload-sarif@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11 with: sarif_file: results.sarif diff --git a/.github/workflows/trivy-scan.yaml b/.github/workflows/trivy-scan.yaml index d59d358338..7a0bca8a32 100644 --- a/.github/workflows/trivy-scan.yaml +++ b/.github/workflows/trivy-scan.yaml @@ -18,9 +18,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # master + uses: aquasecurity/trivy-action@dc5a429b52fcf669ce959baa2c2dd26090d2a6c4 # master with: image-ref: 'docker.io/coredns/coredns:${{ matrix.versions }}' severity: 'CRITICAL,HIGH' @@ -28,6 +28,6 @@ jobs: output: 'trivy-results.sarif' - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 + uses: github/codeql-action/upload-sarif@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11 with: sarif_file: 'trivy-results.sarif' diff --git a/.github/workflows/yamllint.yml b/.github/workflows/yamllint.yml index 12332cb371..7f05d86ee3 100644 --- a/.github/workflows/yamllint.yml +++ b/.github/workflows/yamllint.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout' - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Yamllint' uses: karancode/yamllint-github-action@4052d365f09b8d34eb552c363d1141fd60e2aeb2 with: diff --git a/.go-version b/.go-version index 2f4320f67f..ad2191947f 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.24.4 +1.25.0 diff --git a/ADOPTERS.md b/ADOPTERS.md index 2e7d862788..8e5eaa8bfc 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -34,3 +34,4 @@ * [Northflank](https://northflank.com/) uses CoreDNS on all of our Kubernetes clusters across GCP, AWS, and bare-metal. * [PITS Global Data Recovery Services](https://www.pitsdatarecovery.net) uses CoreDNS on K8s in its highly-loaded internal infrastructure. * [plusserver](https://www.plusserver.com) uses CoreDNS on K8s in its plusserver Kubernetes Engine. +* [Sophotech](https://sopho.tech) uses CoreDNS with a tuned configuration for Kubernetes deployment in production environments. \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 09ebd672e0..5202e8b7b4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,8 +8,8 @@ RUN export DEBCONF_NONINTERACTIVE_SEEN=true \ DEBIAN_PRIORITY=critical \ TERM=linux ; \ apt-get -qq update ; \ - apt-get -yyqq upgrade ; \ - apt-get -yyqq install ca-certificates libcap2-bin; \ + apt-get -qq upgrade ; \ + apt-get -qq --no-install-recommends install ca-certificates libcap2-bin; \ apt-get clean COPY coredns /coredns RUN setcap cap_net_bind_service=+ep /coredns @@ -18,6 +18,8 @@ FROM --platform=$TARGETPLATFORM ${BASE} COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=build /coredns /coredns USER nonroot:nonroot +# Reset the working directory inherited from the base image back to the expected default: +# https://github.com/coredns/coredns/issues/7009#issuecomment-3124851608 WORKDIR / EXPOSE 53 53/udp ENTRYPOINT ["/coredns"] diff --git a/README.md b/README.md index 2ae028654c..9d60143042 100644 --- a/README.md +++ b/README.md @@ -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.23.0 or higher as `go mod` support and other api is needed. +First, make sure your golang version is 1.24.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,7 +79,7 @@ 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.22 sh -c 'GOFLAGS="-buildvcs=false" make gen && GOFLAGS="-buildvcs=false" make' + golang:1.24 sh -c 'GOFLAGS="-buildvcs=false" make gen && GOFLAGS="-buildvcs=false" make' ``` The above command alone will have `coredns` binary generated. diff --git a/core/dnsserver/https.go b/core/dnsserver/https.go index 015c52ec56..437c561f2b 100644 --- a/core/dnsserver/https.go +++ b/core/dnsserver/https.go @@ -43,6 +43,11 @@ func (d *DoHWriter) LocalAddr() net.Addr { return d.laddr } +// Network no-op implementation. +func (d *DoHWriter) Network() string { + return "" +} + // Request returns the HTTP request. func (d *DoHWriter) Request() *http.Request { return d.request diff --git a/core/dnsserver/quic.go b/core/dnsserver/quic.go index 5c2890a723..f7cde74a81 100644 --- a/core/dnsserver/quic.go +++ b/core/dnsserver/quic.go @@ -2,6 +2,7 @@ package dnsserver import ( "encoding/binary" + "errors" "net" "github.com/miekg/dns" @@ -11,11 +12,14 @@ import ( type DoQWriter struct { localAddr net.Addr remoteAddr net.Addr - stream quic.Stream + stream *quic.Stream Msg *dns.Msg } func (w *DoQWriter) Write(b []byte) (int, error) { + if w.stream == nil { + return 0, errors.New("stream is nil") + } b = AddPrefix(b) return w.stream.Write(b) } @@ -40,6 +44,9 @@ func (w *DoQWriter) WriteMsg(m *dns.Msg) error { // mechanism that no further data will be sent on that stream. // See https://www.rfc-editor.org/rfc/rfc9250#section-4.2-7 func (w *DoQWriter) Close() error { + if w.stream == nil { + return errors.New("stream is nil") + } return w.stream.Close() } @@ -58,3 +65,4 @@ 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 "" } diff --git a/core/dnsserver/quic_test.go b/core/dnsserver/quic_test.go index 4a4f408cd9..7e73019066 100644 --- a/core/dnsserver/quic_test.go +++ b/core/dnsserver/quic_test.go @@ -1,15 +1,8 @@ package dnsserver import ( - "bytes" - "context" - "errors" "net" "testing" - "time" - - "github.com/miekg/dns" - "github.com/quic-go/quic-go" ) func TestDoQWriterAddPrefix(t *testing.T) { @@ -55,210 +48,3 @@ func TestDoQWriter_ResponseWriterMethods(t *testing.T) { t.Errorf("RemoteAddr() = %v, want %v", addr, remoteAddr) } } - -// mockQuicStream is a mock implementation of quic.Stream for testing. -type mockQuicStream struct { - writer func(p []byte) (n int, err error) - closer func() error - closed bool - data []byte -} - -func (m *mockQuicStream) Write(p []byte) (n int, err error) { - m.data = append(m.data, p...) - if m.writer != nil { - return m.writer(p) - } - return len(p), nil -} - -func (m *mockQuicStream) Close() error { - m.closed = true - if m.closer != nil { - return m.closer() - } - return nil -} - -// Required by quic.Stream interface, but not used in these tests -func (m *mockQuicStream) Read(p []byte) (n int, err error) { return 0, nil } -func (m *mockQuicStream) CancelRead(code quic.StreamErrorCode) {} -func (m *mockQuicStream) CancelWrite(code quic.StreamErrorCode) {} -func (m *mockQuicStream) SetReadDeadline(t time.Time) error { return nil } -func (m *mockQuicStream) SetWriteDeadline(t time.Time) error { return nil } -func (m *mockQuicStream) SetDeadline(t time.Time) error { return nil } -func (m *mockQuicStream) StreamID() quic.StreamID { return 0 } -func (m *mockQuicStream) Context() context.Context { return nil } - -func TestDoQWriter_Write(t *testing.T) { - tests := []struct { - name string - input []byte - streamWriter func(p []byte) (n int, err error) - expectErr bool - expectedData []byte - expectedN int - }{ - { - name: "successful write", - input: []byte{0x1, 0x2, 0x3}, - streamWriter: func(p []byte) (n int, err error) { - return len(p), nil - }, - expectErr: false, - expectedData: []byte{0x0, 0x3, 0x1, 0x2, 0x3}, // 3-byte length prefix - expectedN: 5, - }, - { - name: "stream write error", - input: []byte{0x4, 0x5}, - streamWriter: func(p []byte) (n int, err error) { - return 0, errors.New("stream error") - }, - expectErr: true, - expectedData: []byte{0x0, 0x2, 0x4, 0x5}, // 2-byte length prefix - expectedN: 0, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockStream := &mockQuicStream{writer: tt.streamWriter} - writer := &DoQWriter{stream: mockStream} - - n, err := writer.Write(tt.input) - - if (err != nil) != tt.expectErr { - t.Errorf("Write() error = %v, expectErr %v", err, tt.expectErr) - return - } - if n != tt.expectedN { - t.Errorf("Write() n = %v, want %v", n, tt.expectedN) - } - - if !bytes.Equal(mockStream.data, tt.expectedData) { - t.Errorf("Write() data written to stream = %X, want %X", mockStream.data, tt.expectedData) - } - }) - } -} - -func TestDoQWriter_WriteMsg(t *testing.T) { - newMsg := func() *dns.Msg { - m := new(dns.Msg) - m.SetQuestion("example.com.", dns.TypeA) - return m - } - - tests := []struct { - name string - msg *dns.Msg - mockStream *mockQuicStream - expectErr bool - expectClosed bool - expectedData []byte // Expected data written to stream (packed msg with prefix) - packErr bool // Simulate error during msg.Pack() - }{ - { - name: "successful write and close", - msg: newMsg(), - mockStream: &mockQuicStream{}, - expectErr: false, - expectClosed: true, - }, - { - name: "msg.Pack() error", - msg: new(dns.Msg), - mockStream: &mockQuicStream{}, - expectErr: true, - packErr: true, // We'll make msg.Pack() fail by corrupting the msg or using a mock - expectClosed: false, // Close should not be called if Pack fails - }, - { - name: "stream write error", - msg: newMsg(), - mockStream: &mockQuicStream{ - writer: func(p []byte) (n int, err error) { - return 0, errors.New("stream write failed") - }, - }, - expectErr: true, - expectClosed: false, // Close should not be called if Write fails - }, - { - name: "stream close error", - msg: newMsg(), - mockStream: &mockQuicStream{ - closer: func() error { - return errors.New("stream close failed") - }, - }, - expectErr: true, - expectClosed: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if tt.packErr { - // Intentionally make the message invalid to cause a pack error. - // Invalid Rcode to ensure Pack fails. - tt.msg.Rcode = 1337 - } - - writer := &DoQWriter{stream: tt.mockStream, Msg: tt.msg} - err := writer.WriteMsg(tt.msg) - - if (err != nil) != tt.expectErr { - t.Errorf("WriteMsg() error = %v, expectErr %v", err, tt.expectErr) - } - - if tt.mockStream.closed != tt.expectClosed { - t.Errorf("WriteMsg() stream closed = %v, want %v", tt.mockStream.closed, tt.expectClosed) - } - - if tt.packErr { - if len(tt.mockStream.data) != 0 { - t.Errorf("WriteMsg() data written to stream on pack error = %X, want empty", tt.mockStream.data) - } - } - }) - } -} - -func TestDoQWriter_Close(t *testing.T) { - tests := []struct { - name string - mockStream *mockQuicStream - expectErr bool - }{ - { - name: "successful close", - mockStream: &mockQuicStream{}, - expectErr: false, - }, - { - name: "stream close error", - mockStream: &mockQuicStream{ - closer: func() error { - return errors.New("stream close error") - }, - }, - expectErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - writer := &DoQWriter{stream: tt.mockStream} - err := writer.Close() - - if (err != nil) != tt.expectErr { - t.Errorf("Close() error = %v, expectErr %v", err, tt.expectErr) - } - if !tt.mockStream.closed { - t.Errorf("Close() stream not marked as closed") - } - }) - } -} diff --git a/core/dnsserver/register.go b/core/dnsserver/register.go index 73b63bb709..f289ceaa51 100644 --- a/core/dnsserver/register.go +++ b/core/dnsserver/register.go @@ -364,5 +364,3 @@ var ( // GracefulTimeout is the maximum duration of a graceful shutdown. GracefulTimeout time.Duration ) - -var _ caddy.GracefulServer = new(Server) diff --git a/core/dnsserver/server_grpc.go b/core/dnsserver/server_grpc.go index dbf85d77b3..cbff8c28a8 100644 --- a/core/dnsserver/server_grpc.go +++ b/core/dnsserver/server_grpc.go @@ -52,8 +52,8 @@ func NewServergRPC(addr string, group []*Config) (*ServergRPC, error) { return &ServergRPC{Server: s, tlsConfig: tlsConfig}, nil } -// Compile-time check to ensure Server implements the caddy.GracefulServer interface -var _ caddy.GracefulServer = &Server{} +// Compile-time check to ensure ServergRPC implements the caddy.GracefulServer interface +var _ caddy.GracefulServer = &ServergRPC{} // Serve implements caddy.TCPServer interface. func (s *ServergRPC) Serve(l net.Listener) error { @@ -181,4 +181,5 @@ 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 } +func (r *gRPCresponse) Network() string { return "" } func (r *gRPCresponse) WriteMsg(m *dns.Msg) error { r.Msg = m; return nil } diff --git a/core/dnsserver/server_https.go b/core/dnsserver/server_https.go index 09c7d62007..d4cb64be9c 100644 --- a/core/dnsserver/server_https.go +++ b/core/dnsserver/server_https.go @@ -88,8 +88,8 @@ func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) { return sh, nil } -// Compile-time check to ensure Server implements the caddy.GracefulServer interface -var _ caddy.GracefulServer = &Server{} +// Compile-time check to ensure ServerHTTPS implements the caddy.GracefulServer interface +var _ caddy.GracefulServer = &ServerHTTPS{} // Serve implements caddy.TCPServer interface. func (s *ServerHTTPS) Serve(l net.Listener) error { diff --git a/core/dnsserver/server_quic.go b/core/dnsserver/server_quic.go index 1a3b2c4566..2e42155a96 100644 --- a/core/dnsserver/server_quic.go +++ b/core/dnsserver/server_quic.go @@ -129,7 +129,10 @@ func (s *ServerQUIC) ServeQUIC() error { // serveQUICConnection handles a new QUIC connection. It waits for new streams // and passes them to serveQUICStream. -func (s *ServerQUIC) serveQUICConnection(conn quic.Connection) { +func (s *ServerQUIC) serveQUICConnection(conn *quic.Conn) { + if conn == nil { + return + } for { // In DoQ, one query consumes one stream. // The client MUST select the next available client-initiated bidirectional @@ -147,14 +150,21 @@ func (s *ServerQUIC) serveQUICConnection(conn quic.Connection) { // Use a bounded worker pool s.streamProcessPool <- struct{}{} // Acquire a worker slot, may block - go func(st quic.Stream, cn quic.Connection) { + go func(st *quic.Stream, cn *quic.Conn) { defer func() { <-s.streamProcessPool }() // Release worker slot s.serveQUICStream(st, cn) }(stream, conn) } } -func (s *ServerQUIC) serveQUICStream(stream quic.Stream, conn quic.Connection) { +func (s *ServerQUIC) serveQUICStream(stream *quic.Stream, conn *quic.Conn) { + if conn == nil { + return + } + if stream == nil { + s.closeQUICConn(conn, DoQCodeInternalError) + return + } buf, err := readDOQMessage(stream) // io.EOF does not really mean that there's any error, it is just @@ -249,7 +259,7 @@ func (s *ServerQUIC) Serve(l net.Listener) error { return nil } func (s *ServerQUIC) Listen() (net.Listener, error) { return nil, nil } // closeQUICConn quietly closes the QUIC connection. -func (s *ServerQUIC) closeQUICConn(conn quic.Connection, code quic.ApplicationErrorCode) { +func (s *ServerQUIC) closeQUICConn(conn *quic.Conn, code quic.ApplicationErrorCode) { if conn == nil { return } diff --git a/core/dnsserver/server_quic_test.go b/core/dnsserver/server_quic_test.go index 96674721cd..8deb11c7c2 100644 --- a/core/dnsserver/server_quic_test.go +++ b/core/dnsserver/server_quic_test.go @@ -2,14 +2,9 @@ package dnsserver import ( "bytes" - "context" "crypto/tls" - "encoding/binary" "errors" - "io" - "net" "testing" - "time" "github.com/miekg/dns" "github.com/quic-go/quic-go" @@ -373,74 +368,6 @@ func TestReadDOQMessage(t *testing.T) { } } -func TestDoQWriter(t *testing.T) { - mockStream := &mockQUICStream{} - localAddr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:53") - remoteAddr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:12345") - - writer := &DoQWriter{ - localAddr: localAddr, - remoteAddr: remoteAddr, - stream: mockStream, - } - - if writer.LocalAddr() != localAddr { - t.Errorf("LocalAddr() = %v, want %v", writer.LocalAddr(), localAddr) - } - - if writer.RemoteAddr() != remoteAddr { - t.Errorf("RemoteAddr() = %v, want %v", writer.RemoteAddr(), remoteAddr) - } - - testData := []byte("test message") - n, err := writer.Write(testData) - if err != nil { - t.Errorf("Write() failed: %v", err) - } - - expectedLen := len(testData) + 2 // +2 for length prefix - if n != expectedLen { - t.Errorf("Write() returned %d, want %d", n, expectedLen) - } - - // Verify the written data includes length prefix - written := mockStream.writtenData - if len(written) != expectedLen { - t.Errorf("Expected written data length %d, got %d", expectedLen, len(written)) - } - - // Check length prefix - expectedLength := uint16(len(testData)) - actualLength := binary.BigEndian.Uint16(written[:2]) - if actualLength != expectedLength { - t.Errorf("Expected length prefix %d, got %d", expectedLength, actualLength) - } - - // Check message content - if !bytes.Equal(written[2:], testData) { - t.Errorf("Expected message content %v, got %v", testData, written[2:]) - } - - // Test WriteMsg method - msg := new(dns.Msg) - msg.SetQuestion("example.com.", dns.TypeA) - msg.Id = 0 - - mockStream.reset() - err = writer.WriteMsg(msg) - if err != nil { - t.Errorf("WriteMsg() failed: %v", err) - } - - if !mockStream.closed { - t.Error("WriteMsg() should close the stream") - } - - if err := writer.TsigStatus(); err != nil { - t.Errorf("TsigStatus() returned error: %v", err) - } -} - func TestAddPrefix(t *testing.T) { tests := []struct { name string @@ -473,34 +400,3 @@ func TestAddPrefix(t *testing.T) { }) } } - -type mockQUICStream struct { - writtenData []byte - closed bool -} - -func (m *mockQUICStream) Write(data []byte) (int, error) { - m.writtenData = append(m.writtenData, data...) - return len(data), nil -} - -func (m *mockQUICStream) Read([]byte) (int, error) { return 0, io.EOF } - -func (m *mockQUICStream) Close() error { - m.closed = true - return nil -} - -func (m *mockQUICStream) reset() { - m.writtenData = nil - m.closed = false -} - -// Minimal implementation of other required methods -func (m *mockQUICStream) StreamID() quic.StreamID { return 0 } -func (m *mockQUICStream) SetReadDeadline(time.Time) error { return nil } -func (m *mockQUICStream) SetWriteDeadline(time.Time) error { return nil } -func (m *mockQUICStream) SetDeadline(time.Time) error { return nil } -func (m *mockQUICStream) Context() context.Context { return context.Background() } -func (m *mockQUICStream) CancelWrite(quic.StreamErrorCode) {} -func (m *mockQUICStream) CancelRead(quic.StreamErrorCode) {} diff --git a/core/dnsserver/server_tls.go b/core/dnsserver/server_tls.go index f2251efb49..4c6faa14cf 100644 --- a/core/dnsserver/server_tls.go +++ b/core/dnsserver/server_tls.go @@ -39,8 +39,8 @@ func NewServerTLS(addr string, group []*Config) (*ServerTLS, error) { return &ServerTLS{Server: s, tlsConfig: tlsConfig}, nil } -// Compile-time check to ensure Server implements the caddy.GracefulServer interface -var _ caddy.GracefulServer = &Server{} +// Compile-time check to ensure ServerTLS implements the caddy.GracefulServer interface +var _ caddy.GracefulServer = &ServerTLS{} // Serve implements caddy.TCPServer interface. func (s *ServerTLS) Serve(l net.Listener) error { diff --git a/coremain/run_test.go b/coremain/run_test.go index 7285aaf3c6..84ca7dfa5a 100644 --- a/coremain/run_test.go +++ b/coremain/run_test.go @@ -113,9 +113,7 @@ func TestConfLoader(t *testing.T) { func TestDefaultLoader(t *testing.T) { // The working directory matters because defaultLoader() looks for "Corefile" in the current directory tmpDir := t.TempDir() - if err := os.Chdir(tmpDir); err != nil { - t.Fatalf("Failed to change to temp directory: %v", err) - } + t.Chdir(tmpDir) // Test without Corefile input, err := defaultLoader("dns") diff --git a/coremain/version.go b/coremain/version.go index 9a980f28b5..71e9641794 100644 --- a/coremain/version.go +++ b/coremain/version.go @@ -2,7 +2,7 @@ package coremain // Various CoreDNS constants. const ( - CoreVersion = "1.12.2" + CoreVersion = "1.12.3" CoreName = "CoreDNS" serverType = "dns" ) diff --git a/go.mod b/go.mod index a22cbffbf6..072a8b342b 100644 --- a/go.mod +++ b/go.mod @@ -2,53 +2,56 @@ module github.com/coredns/coredns // Note this minimum version requirement. CoreDNS supports the last two // Go versions. This follows the upstream Go project support. -go 1.23.0 +go 1.24.0 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.2 github.com/apparentlymart/go-cidr v1.1.0 - github.com/aws/aws-sdk-go v1.55.7 - github.com/aws/aws-sdk-go-v2/config v1.29.15 - github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.5 + github.com/aws/aws-sdk-go-v2 v1.38.1 + github.com/aws/aws-sdk-go-v2/config v1.31.2 + github.com/aws/aws-sdk-go-v2/credentials v1.18.6 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 + github.com/aws/aws-sdk-go-v2/service/route53 v1.56.2 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.38.2 github.com/coredns/caddy v1.1.2-0.20241029205200-8de985351a98 github.com/dnstap/golang-dnstap v0.4.0 - github.com/expr-lang/expr v1.17.5 + github.com/expr-lang/expr v1.17.6 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/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 github.com/matttproud/golang_protobuf_extensions v1.0.4 - github.com/miekg/dns v1.1.66 + github.com/miekg/dns v1.1.68 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.11.0 - github.com/prometheus/client_golang v1.22.0 + github.com/oschwald/geoip2-golang v1.13.0 + github.com/prometheus/client_golang v1.23.0 github.com/prometheus/client_model v0.6.2 - github.com/prometheus/common v0.64.0 - github.com/quic-go/quic-go v0.52.0 - go.etcd.io/etcd/api/v3 v3.6.1 - go.etcd.io/etcd/client/v3 v3.6.1 + github.com/prometheus/common v0.65.0 + github.com/quic-go/quic-go v0.54.0 + go.etcd.io/etcd/api/v3 v3.6.4 + go.etcd.io/etcd/client/v3 v3.6.4 go.uber.org/automaxprocs v1.6.0 - golang.org/x/crypto v0.39.0 - golang.org/x/sys v0.33.0 - google.golang.org/api v0.236.0 - google.golang.org/grpc v1.73.0 - google.golang.org/protobuf v1.36.6 - gopkg.in/DataDog/dd-trace-go.v1 v1.74.0 - k8s.io/api v0.32.3 - k8s.io/apimachinery v0.32.3 - k8s.io/client-go v0.32.3 + golang.org/x/crypto v0.41.0 + golang.org/x/sys v0.35.0 + google.golang.org/api v0.248.0 + google.golang.org/grpc v1.75.0 + google.golang.org/protobuf v1.36.8 + k8s.io/api v0.33.4 + k8s.io/apimachinery v0.33.4 + k8s.io/client-go v0.33.4 k8s.io/klog/v2 v2.130.1 - sigs.k8s.io/mcs-api v0.1.1-0.20250224121229-6c631f4730d0 + sigs.k8s.io/mcs-api v0.2.0 ) require ( - cloud.google.com/go/auth v0.16.1 // indirect + cloud.google.com/go/auth v0.16.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.7.0 // indirect + cloud.google.com/go/compute/metadata v0.8.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect @@ -56,37 +59,33 @@ 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.11.2 // indirect - github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/proto v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/trace v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/util/log v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/util/scrubber v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/version v0.64.2 // 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.67.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/dd-trace-go/v2 v2.0.0 // indirect - github.com/DataDog/go-libddwaf/v3 v3.5.4 // indirect - github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250319104955-81009b9bad14 // 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.26.0 // 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/Microsoft/go-winio v0.6.2 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.68 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 // 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.12.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.20 // indirect - github.com/aws/smithy-go v1.22.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 // indirect + github.com/aws/smithy-go v1.22.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect @@ -106,21 +105,18 @@ require ( 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-task/slim-sprig/v3 v3.0.0 // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // 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.14.2 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kylelemons/godebug v1.1.0 // indirect @@ -128,7 +124,7 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // 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 @@ -140,7 +136,7 @@ require ( 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.15.1 // indirect + github.com/prometheus/procfs v0.16.1 // 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 @@ -151,39 +147,44 @@ require ( github.com/tklauser/numcpus v0.10.0 // 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.1 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/collector/component v1.27.0 // indirect - go.opentelemetry.io/collector/pdata v1.27.0 // indirect - go.opentelemetry.io/collector/pdata/pprofile v0.121.0 // indirect - go.opentelemetry.io/collector/semconv v0.123.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect - go.opentelemetry.io/otel v1.35.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/trace v1.35.0 // 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.37.0 // indirect + go.opentelemetry.io/otel/log v0.11.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.40.0 // indirect + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.43.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect - golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.33.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/time v0.12.0 // indirect + golang.org/x/tools v0.35.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 786ddcc1d9..7d63921783 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= -cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +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/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.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= -cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA= +cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -29,40 +29,40 @@ 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.11.2 h1:Q00pPMQzqMIw7jT2ObaORIxBzSly+deS0Ely9OZ/Bj0= -github.com/DataDog/appsec-internal-go v1.11.2/go.mod h1:9YppRCpElfGX+emXOKruShFYsdPq7WEPq/Fen4tYYpk= -github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.64.2 h1:wEW+nwoLKubvnLLaxMScYO+rEuHGXmvDsrSV9M3aWdU= -github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.64.2/go.mod h1:lzCtnMSGZm/3RMk5RBRW/6IuK1TNbDXx1ttHTxN5Ykc= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.2 h1:xyKB0aTD0S0wp17Egqr8gNUL8btuaKC2WK08NT0pCFQ= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.2/go.mod h1:izbemZjqzBn9upkZj8SyT9igSGPMALaQYgswJ0408vY= -github.com/DataDog/datadog-agent/pkg/proto v0.64.2 h1:JGnb24mKLi+wEJg/bo5FPf1wli3ca2+owIkACl4mwl4= -github.com/DataDog/datadog-agent/pkg/proto v0.64.2/go.mod h1:q324yHcBN5hIeCU8eoinM7lP9c7MOA2FTj7oeWAl3Pc= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.64.2 h1:bCRz9YBvQTJNeE+eAPLEcuz4p/2aStxAO9lgf1HsivI= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.64.2/go.mod h1:1AAhFoEuoXs8jfpj7EiGW6lsqvCYgQc0B0pRpYAPEW4= -github.com/DataDog/datadog-agent/pkg/trace v0.64.2 h1:vuwxRGRVnlFYFUoSK5ZV0sHqskJwxknP5/lV+WfkSSw= -github.com/DataDog/datadog-agent/pkg/trace v0.64.2/go.mod h1:e0wLYMuXKwS/yorq1FqTDGR9WFj9RzwCMwUrli7mCAw= -github.com/DataDog/datadog-agent/pkg/util/log v0.64.2 h1:Sx+L6L2h/HN4UZwAFQMYt4eHkaLHe6THj6GUADLgkm0= -github.com/DataDog/datadog-agent/pkg/util/log v0.64.2/go.mod h1:XDJfRmc5FwFNLDFHtOKX8AW8W1N8Yk+V/wPwj98Zi6Q= -github.com/DataDog/datadog-agent/pkg/util/scrubber v0.64.2 h1:5jGvehYy2VVYJCMED3Dj6zIZds4g0O8PMf5uIMAwoAY= -github.com/DataDog/datadog-agent/pkg/util/scrubber v0.64.2/go.mod h1:uzxlZdxJ2yZZ9k+hDM4PyG3tYacoeneZuh+PVk+IVAw= -github.com/DataDog/datadog-agent/pkg/version v0.64.2 h1:clAPToUGyhFWJIfN6pBR808YigQsDP6hNcpEcu8qbtU= -github.com/DataDog/datadog-agent/pkg/version v0.64.2/go.mod h1:DgOVsfSRaNV4GZNl/qgoZjG3hJjoYUNWPPhbfTfTqtY= +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.67.0 h1:tB+H/TFlFl97ON6v+r9PXPrM+X5qUTc+UPAWF9pA0Fc= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.67.0/go.mod h1:HuNrai9MbPj2ZciBLSfj5wQl8CJOOkrH5xzEPezRNT4= +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.0.0 h1:cHMEzD0Wcgtu+Rec9d1GuVgpIN5f+4vCaNzuFHJ0v+Y= -github.com/DataDog/dd-trace-go/v2 v2.0.0/go.mod h1:WBtf7TA9bWr5uA8DjOyw1qlSKe3bw9gN5nc0Ta9dHFE= -github.com/DataDog/go-libddwaf/v3 v3.5.4 h1:cLV5lmGhrUBnHG50EUXdqPQAlJdVCp9n3aQ5bDWJEAg= -github.com/DataDog/go-libddwaf/v3 v3.5.4/go.mod h1:HoLUHdj0NybsPBth/UppTcg8/DKA4g+AXuk8cZ6nuoo= -github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250319104955-81009b9bad14 h1:tc5aVw7OcMyfVmJnrY4IOeiV1RTSaBuJBqF14BXxzIo= -github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250319104955-81009b9bad14/go.mod h1:quaQJ+wPN41xEC458FCpTwyROZm3MzmTZ8q8XOXQiPs= +github.com/DataDog/dd-trace-go/v2 v2.2.2 h1:t7RCS6et5z+xrvM9dqUPtCGoNOWTj0pcApzbktMZi2k= +github.com/DataDog/dd-trace-go/v2 v2.2.2/go.mod h1:xvdSukALA8/NnVfTAnxqkZfLLO/6Vi4y5ooxfVy6dfk= +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.26.0 h1:GlvoS6hJN0uANUC3fjx72rOgM4StAKYo2HtQGaasC7s= -github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.26.0/go.mod h1:mYQmU7mbHH6DrCaS8N6GZcxwPoeNfyuopUoLQltwSzs= +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= @@ -72,36 +72,36 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo 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 v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= -github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= -github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= -github.com/aws/aws-sdk-go-v2/config v1.29.15 h1:I5XjesVMpDZXZEZonVfjI12VNMrYa38LtLnw4NtY5Ss= -github.com/aws/aws-sdk-go-v2/config v1.29.15/go.mod h1:tNIp4JIPonlsgaO5hxO372a6gjhN63aSWl2GVl5QoBQ= -github.com/aws/aws-sdk-go-v2/credentials v1.17.68 h1:cFb9yjI02/sWHBSYXAtkamjzCuRymvmeFmt0TC0MbYY= -github.com/aws/aws-sdk-go-v2/credentials v1.17.68/go.mod h1:H6E+jBzyqUu8u0vGaU6POkK3P0NylYEeRZ6ynBpMqIk= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= +github.com/aws/aws-sdk-go-v2 v1.38.1 h1:j7sc33amE74Rz0M/PoCpsZQ6OunLqys/m5antM0J+Z8= +github.com/aws/aws-sdk-go-v2 v1.38.1/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2/config v1.31.2 h1:NOaSZpVGEH2Np/c1toSeW0jooNl+9ALmsUTZ8YvkJR0= +github.com/aws/aws-sdk-go-v2/config v1.31.2/go.mod h1:17ft42Yb2lF6OigqSYiDAiUcX4RIkEMY6XxEMJsrAes= +github.com/aws/aws-sdk-go-v2/credentials v1.18.6 h1:AmmvNEYrru7sYNJnp3pf57lGbiarX4T9qU/6AZ9SucU= +github.com/aws/aws-sdk-go-v2/credentials v1.18.6/go.mod h1:/jdQkh1iVPa01xndfECInp1v1Wnp70v3K4MvtlLGVEc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 h1:lpdMwTzmuDLkgW7086jE94HweHCqG+uOJwHf3LZs7T0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 h1:IdCLsiiIj5YJ3AFevsewURCPV+YWUlOW8JiPhoAy8vg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 h1:j7vjtr1YIssWQOMeOWRbh3z8g2oY/xPjnZH2gLY4sGw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= 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.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.5 h1:QLY+ScpXXDEZFUcJ/fsVMa4+jnwLHdik1PBCXJpDvAA= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.5/go.mod h1:yGhDiLKguA3iFJYxbrQkQiNzuy+ddxesSZYWVeeEH5Q= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.20 h1:oIaQ1e17CSKaWmUTu62MtraRWVIosn/iONMuZt0gbqc= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.20/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= -github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= -github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= +github.com/aws/aws-sdk-go-v2/service/route53 v1.56.2 h1:6QKyfbweIsjt1kvE8rw+LeDxmCt1uvI8ywRe2cYOpQo= +github.com/aws/aws-sdk-go-v2/service/route53 v1.56.2/go.mod h1:Ro0zSeA7hRAhX04QgnUAc8MvvQO74wg/S15wzA/mxgo= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.38.2 h1:BvsTLbavBCIWhGav8Rm/vPPyyhDwkOMSi0pkGaohCag= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.38.2/go.mod h1:KwGTe+BJ29tKBIkVuZgDzlw70aS4BZxLJVqAjwnhfRQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 h1:ve9dYBB8CfJGTFqcQ3ZLAAb/KXWgYlgu/2R2TZL2Ko0= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 h1:pd9G9HQaM6UZAZh19pYOkpKSQkyQQ9ftnl/LttQOcGI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2/go.mod h1:eknndR9rU8UpE/OmFpqU78V1EcXPKFTTm5l/buZYgvM= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 h1:iV1Ko4Em/lkJIsoKyGfc0nQySi+v0Udxr6Igq+y9JZc= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0/go.mod h1:bEPcjW7IbolPfK67G1nilqWyoxYMSPrDiIQ3RdIdKgo= +github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= +github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= 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/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -121,8 +121,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dnstap/golang-dnstap v0.4.0 h1:KRHBoURygdGtBjDI2w4HifJfMAhhOqDuktAokaSa234= @@ -136,8 +136,8 @@ github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGex github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/expr-lang/expr v1.17.5 h1:i1WrMvcdLF249nSNlpQZN1S6NXuW9WaOfF5tPi3aw3k= -github.com/expr-lang/expr v1.17.5/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/expr-lang/expr v1.17.6 h1:1h6i8ONk9cexhDmowO/A64VPxHScu7qfSl2k8OlINec= +github.com/expr-lang/expr v1.17.6/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,10 +162,11 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En 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.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -185,8 +186,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -196,8 +197,8 @@ 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-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +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/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= @@ -205,18 +206,16 @@ 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.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +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/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-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/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 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/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -241,25 +240,26 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ 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/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= -github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= +github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= +github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= 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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +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.120.1 h1:lK/3zr73guK9apbXTcnDnYrC0YCQ25V3CIULYz3k2xU= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.120.1/go.mod h1:01TvyaK8x640crO2iFwW/6CFCZgNsOvOGH3B5J239m0= -github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.120.1 h1:TCyOus9tym82PD1VYtthLKMVMlVyRwtDI4ck4SR2+Ok= -github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.120.1/go.mod h1:Z/S1brD5gU2Ntht/bHxBVnGxXKTvZDr0dNv/riUzPmY= +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/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= @@ -268,8 +268,8 @@ 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.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w= -github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo= +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/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= @@ -287,22 +287,22 @@ 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.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +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_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.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= -github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= 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.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA= -github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= +github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= 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.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +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= @@ -343,54 +343,64 @@ 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.1 h1:yJ9WlDih9HT457QPuHt/TH/XtsdN2tubyxyQHSHPsEo= -go.etcd.io/etcd/api/v3 v3.6.1/go.mod h1:lnfuqoGsXMlZdTJlact3IB56o3bWp1DIlXPIGKRArto= -go.etcd.io/etcd/client/pkg/v3 v3.6.1 h1:CxDVv8ggphmamrXM4Of8aCC8QHzDM4tGcVr9p2BSoGk= -go.etcd.io/etcd/client/pkg/v3 v3.6.1/go.mod h1:aTkCp+6ixcVTZmrJGa7/Mc5nMNs59PEgBbq+HCmWyMc= -go.etcd.io/etcd/client/v3 v3.6.1 h1:KelkcizJGsskUXlsxjVrSmINvMMga0VWwFF0tSPGEP0= -go.etcd.io/etcd/client/v3 v3.6.1/go.mod h1:fCbPUdjWNLfx1A6ATo9syUmFVxqHH9bCnPLBZmnLmMY= +go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= +go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= +go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= +go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= +go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= +go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/collector/component v1.27.0 h1:6wk0K23YT9lSprX8BH9x5w8ssAORE109ekH/ix2S614= -go.opentelemetry.io/collector/component v1.27.0/go.mod h1:fIyBHoa7vDyZL3Pcidgy45cx24tBe7iHWne097blGgo= -go.opentelemetry.io/collector/component/componentstatus v0.120.0 h1:hzKjI9+AIl8A/saAARb47JqabWsge0kMp8NSPNiCNOQ= -go.opentelemetry.io/collector/component/componentstatus v0.120.0/go.mod h1:kbuAEddxvcyjGLXGmys3nckAj4jTGC0IqDIEXAOr3Ag= -go.opentelemetry.io/collector/component/componenttest v0.120.0 h1:vKX85d3lpxj/RoiFQNvmIpX9lOS80FY5svzOYUyeYX0= -go.opentelemetry.io/collector/component/componenttest v0.120.0/go.mod h1:QDLboWF2akEqAGyvje8Hc7GfXcrZvQ5FhmlWvD5SkzY= -go.opentelemetry.io/collector/consumer v1.26.0 h1:0MwuzkWFLOm13qJvwW85QkoavnGpR4ZObqCs9g1XAvk= -go.opentelemetry.io/collector/consumer v1.26.0/go.mod h1:I/ZwlWM0sbFLhbStpDOeimjtMbWpMFSoGdVmzYxLGDg= -go.opentelemetry.io/collector/consumer/consumertest v0.120.0 h1:iPFmXygDsDOjqwdQ6YZcTmpiJeQDJX+nHvrjTPsUuv4= -go.opentelemetry.io/collector/consumer/consumertest v0.120.0/go.mod h1:HeSnmPfAEBnjsRR5UY1fDTLlSrYsMsUjufg1ihgnFJ0= -go.opentelemetry.io/collector/consumer/xconsumer v0.120.0 h1:dzM/3KkFfMBIvad+NVXDV+mA+qUpHyu5c70TFOjDg68= -go.opentelemetry.io/collector/consumer/xconsumer v0.120.0/go.mod h1:eOf7RX9CYC7bTZQFg0z2GHdATpQDxI0DP36F9gsvXOQ= -go.opentelemetry.io/collector/pdata v1.27.0 h1:66yI7FYkUDia74h48Fd2/KG2Vk8DxZnGw54wRXykCEU= -go.opentelemetry.io/collector/pdata v1.27.0/go.mod h1:18e8/xDZsqyj00h/5HM5GLdJgBzzG9Ei8g9SpNoiMtI= -go.opentelemetry.io/collector/pdata/pprofile v0.121.0 h1:DFBelDRsZYxEaSoxSRtseAazsHJfqfC/Yl64uPicl2g= -go.opentelemetry.io/collector/pdata/pprofile v0.121.0/go.mod h1:j/fjrd7ybJp/PXkba92QLzx7hykUVmU8x/WJvI2JWSg= -go.opentelemetry.io/collector/pdata/testdata v0.120.0 h1:Zp0LBOv3yzv/lbWHK1oht41OZ4WNbaXb70ENqRY7HnE= -go.opentelemetry.io/collector/pdata/testdata v0.120.0/go.mod h1:PfezW5Rzd13CWwrElTZRrjRTSgMGUOOGLfHeBjj+LwY= -go.opentelemetry.io/collector/pipeline v0.123.0 h1:LDcuCrwhCTx2yROJZqhNmq2v0CFkCkUEvxvvcRW0+2c= -go.opentelemetry.io/collector/pipeline v0.123.0/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4= -go.opentelemetry.io/collector/processor v0.120.0 h1:No+I65ybBLVy4jc7CxcsfduiBrm7Z6kGfTnekW3hx1A= -go.opentelemetry.io/collector/processor v0.120.0/go.mod h1:4zaJGLZCK8XKChkwlGC/gn0Dj4Yke04gQCu4LGbJGro= -go.opentelemetry.io/collector/processor/processortest v0.120.0 h1:R+VSVSU59W0/mPAcyt8/h1d0PfWN6JI2KY5KeMICXvo= -go.opentelemetry.io/collector/processor/processortest v0.120.0/go.mod h1:me+IVxPsj4IgK99I0pgKLX34XnJtcLwqtgTuVLhhYDI= -go.opentelemetry.io/collector/processor/xprocessor v0.120.0 h1:mBznj/1MtNqmu6UpcoXz6a63tU0931oWH2pVAt2+hzo= -go.opentelemetry.io/collector/processor/xprocessor v0.120.0/go.mod h1:Nsp0sDR3gE+GAhi9d0KbN0RhOP+BK8CGjBRn8+9d/SY= -go.opentelemetry.io/collector/semconv v0.123.0 h1:hFjhLU1SSmsZ67pXVCVbIaejonkYf5XD/6u4qCQQPtc= -go.opentelemetry.io/collector/semconv v0.123.0/go.mod h1:te6VQ4zZJO5Lp8dM2XIhDxDiL45mwX0YAQQWRQ0Qr9U= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +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.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +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.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= 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= @@ -410,18 +420,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.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= -golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +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/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.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= 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= @@ -433,8 +443,8 @@ 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.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -444,8 +454,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -466,15 +476,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.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 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.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= 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= @@ -482,10 +492,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.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= 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= @@ -494,36 +504,36 @@ 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.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= 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= -google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0= -google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4= +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.248.0 h1:hUotakSkcwGdYUqzCRc5yGYsg4wXxpkKlW5ryVqvC1Y= +google.golang.org/api v0.248.0/go.mod h1:yAFUAF56Li7IuIQbTFoLwXTCI6XCFKueOlS7S9e4F9k= 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-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78= -google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= -google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0= -google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +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-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= +google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= +google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= 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.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= -gopkg.in/DataDog/dd-trace-go.v1 v1.74.0 h1:wScziU1ff6Bnyr8MEyxATPSLJdnLxKz3p6RsA8FUaek= -gopkg.in/DataDog/dd-trace-go.v1 v1.74.0/go.mod h1:ReNBsNfnsjVC7GsCe80zRcykL/n+nxvsNrg3NbjuleM= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= 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= @@ -533,30 +543,30 @@ 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/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= +k8s.io/api v0.33.4 h1:oTzrFVNPXBjMu0IlpA2eDDIU49jsuEorGHB4cvKupkk= +k8s.io/api v0.33.4/go.mod h1:VHQZ4cuxQ9sCUMESJV5+Fe8bGnqAARZ08tSTdHWfeAc= +k8s.io/apimachinery v0.33.4 h1:SOf/JW33TP0eppJMkIgQ+L6atlDiP/090oaX0y9pd9s= +k8s.io/apimachinery v0.33.4/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.4 h1:TNH+CSu8EmXfitntjUPwaKVPN0AYMbc9F1bBS8/ABpw= +k8s.io/client-go v0.33.4/go.mod h1:LsA0+hBG2DPwovjd931L/AoaezMPX9CmBgyVyBZmbCY= 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-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/mcs-api v0.1.1-0.20250224121229-6c631f4730d0 h1:LChl5QBr39XNzUjscGlfBJYjyclDru70cLujcC8Vn/M= -sigs.k8s.io/mcs-api v0.1.1-0.20250224121229-6c631f4730d0/go.mod h1:M1Zjh0Jn/Z5e/2JHsZyEeLMw0qGBBmkJqEOc+OceERY= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/mcs-api v0.2.0 h1:F8o/nIpQmog494Qwe94srDWjS3ltEu4y5IL9i3dB938= +sigs.k8s.io/mcs-api v0.2.0/go.mod h1:zZ5CK8uS6HaLkxY4HqsmcBHfzHuNMrY2uJy8T7jffK4= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +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/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/notes/coredns-1.12.3.md b/notes/coredns-1.12.3.md new file mode 100644 index 0000000000..35bacc8e79 --- /dev/null +++ b/notes/coredns-1.12.3.md @@ -0,0 +1,48 @@ ++++ +title = "CoreDNS-1.12.3 Release" +description = "CoreDNS-1.12.3 Release Notes." +tags = ["Release", "1.12.3", "Notes"] +release = "1.12.3" +date = "2024-08-05T00:00:00+00:00" +author = "coredns" ++++ + +This release improves plugin reliability and standards compliance, adding startup timeout to the Kubernetes +plugin, fallthrough to gRPC, and EDNS0 unset to rewrite. The file plugin now preserves SRV record case per +RFC 6763, route53 is updated to AWS SDK v2, and multiple race conditions in cache and connection handling in +forward are fixed. + +## Brought to You By + +blakebarnett +Brennan Kinney +Cameron Steel +Dave Brown +Dennis Simmons +Guillaume Jacquet +harshith-2411-2002 +houpo-bob +Oleg Guba +Sebastian Mayr +Stephen Kitt +Syed Azeez +Ville Vesilehto +Yong Tang +Yoofi Quansah + + +## Noteworthy Changes + +* plugin/auto: Return REFUSED when no next plugin is available (https://github.com/coredns/coredns/pull/7381) +* plugin/cache: Create a copy of a response to ensure original msg is never modified (https://github.com/coredns/coredns/pull/7357) +* plugin/cache: Fix data race when refreshing cached messages (https://github.com/coredns/coredns/pull/7398) +* plugin/cache: Fix data race when updating the TTL of cached messages (https://github.com/coredns/coredns/pull/7397) +* plugin/file: Return REFUSED when no next plugin is available (https://github.com/coredns/coredns/pull/7381) +* plugin/file: Preserve case in SRV record names and targets per RFC 6763 (https://github.com/coredns/coredns/pull/7402) +* plugin/forward: Handle cached connection closure in forward plugin (https://github.com/coredns/coredns/pull/7427) +* plugin/grpc: Add support for fallthrough to the grpc plugin (https://github.com/coredns/coredns/pull/7359) +* plugin/kubernetes: Add startup_timeout for kubernetes plugin (https://github.com/coredns/coredns/pull/7068) +* plugin/kubernetes: Properly create hostname from IPv6 (https://github.com/coredns/coredns/pull/7431) +* plugin/rewrite: Add EDNS0 unset action (https://github.com/coredns/coredns/pull/7380) +* plugin/route53: Port to AWS Go SDK v2 (https://github.com/coredns/coredns/pull/6588) +* plugin/test: Fix TXT record comparison logic for multi-string vs multi-record scenarios (https://github.com/coredns/coredns/pull/7413) diff --git a/plugin/auto/auto.go b/plugin/auto/auto.go index b2a7c76ed1..fa62d8f14a 100644 --- a/plugin/auto/auto.go +++ b/plugin/auto/auto.go @@ -51,6 +51,10 @@ func (a Auto) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i // Now the real zone. zone = plugin.Zones(a.Zones.Names()).Matches(qname) if zone == "" { + // If no next plugin is configured, it's more correct to return REFUSED as auto acts as an authoritative server + if a.Next == nil { + return dns.RcodeRefused, nil + } return plugin.NextOrFailure(a.Name(), a.Next, ctx, w, r) } diff --git a/plugin/auto/auto_test.go b/plugin/auto/auto_test.go index 243c7ebc89..9871d342d1 100644 --- a/plugin/auto/auto_test.go +++ b/plugin/auto/auto_test.go @@ -104,39 +104,44 @@ func TestAutoServeDNSZoneMatching(t *testing.T) { t.Parallel() tests := []struct { - name string - origins []string - names []string - qname string - hasZone bool + name string + origins []string + names []string + qname string + hasZone bool + shouldRefuse bool }{ { - name: "exact zone match", - origins: []string{"example.org."}, - names: []string{"example.org."}, - qname: "test.example.org.", - hasZone: true, + name: "exact zone match", + origins: []string{"example.org."}, + names: []string{"example.org."}, + qname: "test.example.org.", + hasZone: true, + shouldRefuse: false, }, { - name: "subdomain zone match", - origins: []string{"example.org."}, - names: []string{"example.org."}, - qname: "sub.test.example.org.", - hasZone: true, + name: "subdomain zone match", + origins: []string{"example.org."}, + names: []string{"example.org."}, + qname: "sub.test.example.org.", + hasZone: true, + shouldRefuse: false, }, { - name: "no origin match", - origins: []string{"other.org."}, - names: []string{"example.org."}, - qname: "test.example.org.", - hasZone: false, + name: "no origin match", + origins: []string{"other.org."}, + names: []string{"example.org."}, + qname: "test.example.org.", + hasZone: false, + shouldRefuse: false, }, { - name: "origin match but no name match", - origins: []string{"example.org."}, - names: []string{"other.org."}, - qname: "test.example.org.", - hasZone: false, + name: "origin match but no name match", + origins: []string{"example.org."}, + names: []string{"other.org."}, + qname: "test.example.org.", + hasZone: false, + shouldRefuse: true, }, } @@ -163,14 +168,18 @@ func TestAutoServeDNSZoneMatching(t *testing.T) { rec := dnstest.NewRecorder(&test.ResponseWriter{}) ctx := context.Background() - _, err := a.ServeDNS(ctx, rec, m) + code, err := a.ServeDNS(ctx, rec, m) if tt.hasZone { if err != nil { t.Errorf("Expected no error for zone match, got: %v", err) } } else { - if err == nil { + if tt.shouldRefuse { + if code != dns.RcodeRefused { + t.Errorf("Expected code %d, got %d", dns.RcodeRefused, code) + } + } else if err == nil { t.Errorf("Expected error for no zone match, got nil") } } diff --git a/plugin/cache/cache.go b/plugin/cache/cache.go index 6dc6dc0a21..a2ae9a3070 100644 --- a/plugin/cache/cache.go +++ b/plugin/cache/cache.go @@ -199,6 +199,18 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error { duration = computeTTL(msgTTL, w.minpttl, w.pttl) } + // Apply capped TTL to this reply to avoid jarring TTL experience 1799 -> 8 (e.g.) + ttl := uint32(duration.Seconds()) + res.Answer = filterRRSlice(res.Answer, ttl, false) + res.Ns = filterRRSlice(res.Ns, ttl, false) + res.Extra = filterRRSlice(res.Extra, ttl, false) + + if !w.do && !w.ad { + // unset AD bit if requester is not OK with DNSSEC + // But retain AD bit if requester set the AD bit in the request, per RFC6840 5.7-5.8 + res.AuthenticatedData = false + } + if hasKey && duration > 0 { if w.state.Match(res) { w.set(res, key, mt, duration) @@ -214,18 +226,6 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error { return nil } - // Apply capped TTL to this reply to avoid jarring TTL experience 1799 -> 8 (e.g.) - ttl := uint32(duration.Seconds()) - res.Answer = filterRRSlice(res.Answer, ttl, false) - res.Ns = filterRRSlice(res.Ns, ttl, false) - res.Extra = filterRRSlice(res.Extra, ttl, false) - - if !w.do && !w.ad { - // unset AD bit if requester is not OK with DNSSEC - // But retain AD bit if requester set the AD bit in the request, per RFC6840 5.7-5.8 - res.AuthenticatedData = false - } - return w.ResponseWriter.WriteMsg(res) } diff --git a/plugin/cache/dnssec.go b/plugin/cache/dnssec.go index ec5ff41cb9..da7e1e9b3e 100644 --- a/plugin/cache/dnssec.go +++ b/plugin/cache/dnssec.go @@ -3,8 +3,8 @@ package cache import "github.com/miekg/dns" // filterRRSlice filters out OPT RRs, and sets all RR TTLs to ttl. -// If dup is true the RRs in rrs are _copied_ into the slice that is -// returned. +// If dup is true the RRs in rrs are _copied_ before adjusting their +// TTL and the slice of copied RRs is returned. func filterRRSlice(rrs []dns.RR, ttl uint32, dup bool) []dns.RR { j := 0 rs := make([]dns.RR, len(rrs)) @@ -12,12 +12,12 @@ func filterRRSlice(rrs []dns.RR, ttl uint32, dup bool) []dns.RR { if r.Header().Rrtype == dns.TypeOPT { continue } - r.Header().Ttl = ttl if dup { rs[j] = dns.Copy(r) } else { rs[j] = r } + rs[j].Header().Ttl = ttl j++ } return rs[:j] diff --git a/plugin/file/closest.go b/plugin/file/closest.go index 86c90fccdc..7a8efd5d91 100644 --- a/plugin/file/closest.go +++ b/plugin/file/closest.go @@ -16,7 +16,7 @@ func (z *Zone) ClosestEncloser(qname string) (*tree.Elem, bool) { } qname = qname[offset:] - offset, end = dns.NextLabel(qname, offset) + offset, end = dns.NextLabel(qname, 0) } return z.Search(z.origin) diff --git a/plugin/file/closest_test.go b/plugin/file/closest_test.go index 40c04ff26c..282823fcc7 100644 --- a/plugin/file/closest_test.go +++ b/plugin/file/closest_test.go @@ -21,6 +21,7 @@ func TestClosestEncloser(t *testing.T) { {"blaat.www.miek.nl.", "www.miek.nl."}, {"www.blaat.miek.nl.", "miek.nl."}, {"blaat.a.miek.nl.", "a.miek.nl."}, + {"blaat.z.a.miek.nl.", "a.miek.nl."}, } for _, tc := range tests { diff --git a/plugin/file/file.go b/plugin/file/file.go index 8ff893ba8c..67b81e9a53 100644 --- a/plugin/file/file.go +++ b/plugin/file/file.go @@ -42,6 +42,10 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i // TODO(miek): match the qname better in the map zone := plugin.Zones(f.Zones.Names).Matches(qname) if zone == "" { + // If no next plugin is configured, it's more correct to return REFUSED as file acts as an authoritative server + if f.Next == nil { + return dns.RcodeRefused, nil + } return plugin.NextOrFailure(f.Name(), f.Next, ctx, w, r) } diff --git a/plugin/file/tree/less.go b/plugin/file/tree/less.go index 7421cf08d4..7793009018 100644 --- a/plugin/file/tree/less.go +++ b/plugin/file/tree/less.go @@ -2,6 +2,7 @@ package tree import ( "bytes" + "strings" "github.com/miekg/dns" ) @@ -27,8 +28,8 @@ func less(a, b string) int { // sadly this []byte will allocate... TODO(miek): check if this is needed // for a name, otherwise compare the strings. - ab := []byte(a[ai:aj]) - bb := []byte(b[bi:bj]) + ab := []byte(strings.ToLower(a[ai:aj])) + bb := []byte(strings.ToLower(b[bi:bj])) doDDD(ab) doDDD(bb) diff --git a/plugin/file/zone.go b/plugin/file/zone.go index 0125a10768..aeb2a593e2 100644 --- a/plugin/file/zone.go +++ b/plugin/file/zone.go @@ -73,7 +73,10 @@ func (z *Zone) CopyWithoutApex() *Zone { // Insert inserts r into z. func (z *Zone) Insert(r dns.RR) error { - r.Header().Name = strings.ToLower(r.Header().Name) + // r.Header().Name = strings.ToLower(r.Header().Name) + if r.Header().Rrtype != dns.TypeSRV { + r.Header().Name = strings.ToLower(r.Header().Name) + } switch h := r.Header().Rrtype; h { case dns.TypeNS: @@ -108,7 +111,7 @@ func (z *Zone) Insert(r dns.RR) error { case dns.TypeMX: r.(*dns.MX).Mx = strings.ToLower(r.(*dns.MX).Mx) case dns.TypeSRV: - r.(*dns.SRV).Target = strings.ToLower(r.(*dns.SRV).Target) + // r.(*dns.SRV).Target = strings.ToLower(r.(*dns.SRV).Target) } z.Tree.Insert(r) diff --git a/plugin/file/zone_test.go b/plugin/file/zone_test.go index aa42fd8705..f81a871ff3 100644 --- a/plugin/file/zone_test.go +++ b/plugin/file/zone_test.go @@ -1,6 +1,12 @@ package file -import "testing" +import ( + "testing" + + "github.com/coredns/coredns/plugin/file/tree" + + "github.com/miekg/dns" +) func TestNameFromRight(t *testing.T) { z := NewZone("example.org.", "stdin") @@ -28,3 +34,41 @@ func TestNameFromRight(t *testing.T) { } } } + +func TestInsertPreservesSRVCase(t *testing.T) { + z := NewZone("home.arpa.", "stdin") + + // SRV with mixed case and space-escaped instance name + srv, err := dns.NewRR(`Home\032Media._smb._tcp.home.arpa. 5 IN SRV 0 0 445 samba.home.arpa.`) + if err != nil { + t.Fatalf("Failed to parse SRV RR: %v", err) + } + + if err := z.Insert(srv); err != nil { + t.Fatalf("Insert failed: %v", err) + } + + found := false + err = z.Walk(func(elem *tree.Elem, rrsets map[uint16][]dns.RR) error { + for _, rrs := range rrsets { + for _, rr := range rrs { + if srvRR, ok := rr.(*dns.SRV); ok { + if srvRR.Hdr.Name == "Home\\032Media._smb._tcp.home.arpa." { + found = true + if srvRR.Target != "samba.home.arpa." { + t.Errorf("Expected SRV target to be 'samba.home.arpa.', got %q", srvRR.Target) + } + } + } + } + } + return nil + }) + if err != nil { + t.Fatalf("Tree walk failed: %v", err) + } + + if !found { + t.Errorf("SRV record with original case not found in tree") + } +} diff --git a/plugin/forward/dnstap.go b/plugin/forward/dnstap.go index 8195bb49d8..293dc10cf3 100644 --- a/plugin/forward/dnstap.go +++ b/plugin/forward/dnstap.go @@ -3,7 +3,7 @@ package forward import ( "context" "net" - "strconv" + "net/netip" "time" "github.com/coredns/coredns/plugin/dnstap/msg" @@ -16,11 +16,14 @@ import ( // toDnstap will send the forward and received message to the dnstap plugin. func toDnstap(ctx context.Context, f *Forward, host string, state request.Request, opts proxy.Options, reply *dns.Msg, start time.Time) { - h, p, _ := net.SplitHostPort(host) // this is preparsed and can't err here - port, _ := strconv.ParseUint(p, 10, 32) // same here - ip := net.ParseIP(h) + ap, _ := netip.ParseAddrPort(host) // this is preparsed and can't err here + ip := net.IP(ap.Addr().AsSlice()) + port := int(ap.Port()) - var ta net.Addr = &net.UDPAddr{IP: ip, Port: int(port)} + var ta net.Addr = &net.UDPAddr{ + IP: ip, + Port: port, + } t := state.Proto() switch { case opts.ForceTCP: @@ -30,7 +33,7 @@ func toDnstap(ctx context.Context, f *Forward, host string, state request.Reques } if t == "tcp" { - ta = &net.TCPAddr{IP: ip, Port: int(port)} + ta = &net.TCPAddr{IP: ip, Port: port} } for _, t := range f.tapPlugins { diff --git a/plugin/forward/forward.go b/plugin/forward/forward.go index d244218b56..0c95bafdfd 100644 --- a/plugin/forward/forward.go +++ b/plugin/forward/forward.go @@ -16,7 +16,7 @@ import ( "github.com/coredns/coredns/plugin/dnstap" "github.com/coredns/coredns/plugin/metadata" clog "github.com/coredns/coredns/plugin/pkg/log" - "github.com/coredns/coredns/plugin/pkg/proxy" + proxyPkg "github.com/coredns/coredns/plugin/pkg/proxy" "github.com/coredns/coredns/request" "github.com/miekg/dns" @@ -36,7 +36,7 @@ const ( type Forward struct { concurrent int64 // atomic counters need to be first in struct for proper alignment - proxies []*proxy.Proxy + proxies []*proxyPkg.Proxy p Policy hcInterval time.Duration @@ -52,7 +52,7 @@ type Forward struct { maxConcurrent int64 failfastUnhealthyUpstreams bool - opts proxy.Options // also here for testing + opts proxyPkg.Options // also here for testing // ErrLimitExceeded indicates that a query was rejected because the number of concurrent queries has exceeded // the maximum allowed (maxConcurrent) @@ -65,18 +65,18 @@ type Forward struct { // New returns a new Forward. func New() *Forward { - f := &Forward{maxfails: 2, tlsConfig: new(tls.Config), expire: defaultExpire, p: new(random), from: ".", hcInterval: hcInterval, opts: proxy.Options{ForceTCP: false, PreferUDP: false, HCRecursionDesired: true, HCDomain: "."}} + f := &Forward{maxfails: 2, tlsConfig: new(tls.Config), expire: defaultExpire, p: new(random), from: ".", hcInterval: hcInterval, opts: proxyPkg.Options{ForceTCP: false, PreferUDP: false, HCRecursionDesired: true, HCDomain: "."}} return f } // SetProxy appends p to the proxy list and starts healthchecking. -func (f *Forward) SetProxy(p *proxy.Proxy) { +func (f *Forward) SetProxy(p *proxyPkg.Proxy) { f.proxies = append(f.proxies, p) p.Start(f.hcInterval) } // SetProxyOptions setup proxy options -func (f *Forward) SetProxyOptions(opts proxy.Options) { +func (f *Forward) SetProxyOptions(opts proxyPkg.Options) { f.opts = opts } @@ -163,7 +163,7 @@ func (f *Forward) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg for { ret, err = proxy.Connect(ctx, state, opts) - if err == ErrCachedClosed { // Remote side closed conn, can only happen with TCP. + if err == proxyPkg.ErrCachedClosed { // Remote side closed conn, can only happen with TCP. continue } // Retry with TCP if truncated and prefer_udp configured. @@ -254,7 +254,7 @@ func (f *Forward) ForceTCP() bool { return f.opts.ForceTCP } func (f *Forward) PreferUDP() bool { return f.opts.PreferUDP } // List returns a set of proxies to be used for this client depending on the policy in f. -func (f *Forward) List() []*proxy.Proxy { return f.p.List(f.proxies) } +func (f *Forward) List() []*proxyPkg.Proxy { return f.p.List(f.proxies) } var ( // ErrNoHealthy means no healthy proxies left. diff --git a/plugin/header/README.md b/plugin/header/README.md index 9a855c722b..a27a1b9cb4 100644 --- a/plugin/header/README.md +++ b/plugin/header/README.md @@ -13,12 +13,12 @@ The modifications are made transparently for the client and subsequent plugins. ~~~ header { - [SELECTOR] ACTION FLAGS... - [SELECTOR] ACTION FLAGS... + SELECTOR ACTION FLAGS... + SELECTOR ACTION FLAGS... } ~~~ -* **SELECTOR** defines if the action should be applied on `query` or `response`. In future CoreDNS version the selector will be mandatory. For backwards compatibility the action will be applied on `response` if the selector is undefined. +* **SELECTOR** defines if the action should be applied on `query` or `response`. * **ACTION** 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: diff --git a/plugin/header/setup.go b/plugin/header/setup.go index 9c1bdeced6..2a7761bb32 100644 --- a/plugin/header/setup.go +++ b/plugin/header/setup.go @@ -38,14 +38,6 @@ func parse(c *caddy.Controller) ([]Rule, []Rule, error) { var action string switch selector { - case "set", "clear": - log.Warningf("The selector for header rule in line %d isn't explicit defined. "+ - "Assume rule applies for selector 'response'. This syntax is deprecated. "+ - "In future versions of CoreDNS the selector must be explicit defined.", - c.Line()) - - action = selector - selector = "response" case "query", "response": if c.NextArg() { action = c.Val() diff --git a/plugin/header/setup_test.go b/plugin/header/setup_test.go index 36b7995e4f..48d23335d7 100644 --- a/plugin/header/setup_test.go +++ b/plugin/header/setup_test.go @@ -14,24 +14,18 @@ func TestSetupHeader(t *testing.T) { expectedErrContent string }{ {`header {}`, true, "Wrong argument count or unexpected line ending after"}, - {`header { - set -}`, true, "invalid length for flags, at least one should be provided"}, {`header { foo }`, true, "invalid selector=foo should be query or response"}, + {`header { + response set +}`, true, "invalid length for flags, at least one should be provided"}, {`header { query foo }`, true, "invalid length for flags, at least one should be provided"}, {`header { query foo rd }`, true, "unknown flag action=foo, should be set or clear"}, - {`header { - set ra -}`, false, ""}, - {`header { - clear ra - }`, false, ""}, {`header { query set rd }`, false, ""}, @@ -39,8 +33,8 @@ func TestSetupHeader(t *testing.T) { response set aa }`, false, ""}, {`header { - set ra aa - clear rd + response set ra aa + query clear rd }`, false, ""}, } diff --git a/plugin/kubernetes/kubernetes.go b/plugin/kubernetes/kubernetes.go index 8adc80c806..5bf064c3c5 100644 --- a/plugin/kubernetes/kubernetes.go +++ b/plugin/kubernetes/kubernetes.go @@ -351,7 +351,11 @@ func endpointHostname(addr object.EndpointAddress, endpointNameMode bool) string return strings.ReplaceAll(addr.IP, ".", "-") } if strings.Contains(addr.IP, ":") { - return strings.ReplaceAll(addr.IP, ":", "-") + ipv6Hostname := strings.ReplaceAll(addr.IP, ":", "-") + if strings.HasSuffix(ipv6Hostname, "-") { + return ipv6Hostname + "0" + } + return ipv6Hostname } return "" } diff --git a/plugin/kubernetes/kubernetes_test.go b/plugin/kubernetes/kubernetes_test.go index 6b5a3cb769..0a517420d6 100644 --- a/plugin/kubernetes/kubernetes_test.go +++ b/plugin/kubernetes/kubernetes_test.go @@ -30,6 +30,8 @@ func TestEndpointHostname(t *testing.T) { {"10.11.12.13", "epname", "epname", "hello-abcde", false}, {"10.11.12.13", "epname", "epname", "hello-abcde", true}, {"10.11.12.13", "", "hello-abcde", "hello-abcde", true}, + {"2001:db8:3333:4444:5555:6666:7777:8888", "", "2001-db8-3333-4444-5555-6666-7777-8888", "", false}, + {"2001:db8:3333:4444:5555:6666::", "", "2001-db8-3333-4444-5555-6666--0", "", false}, } for _, test := range tests { result := endpointHostname(object.EndpointAddress{IP: test.ip, Hostname: test.hostname, TargetRefName: test.podName}, test.endpointNameMode) diff --git a/plugin/loadbalance/README.md b/plugin/loadbalance/README.md index fe29b19fc9..e8777785b2 100644 --- a/plugin/loadbalance/README.md +++ b/plugin/loadbalance/README.md @@ -2,7 +2,7 @@ ## Name -*loadbalance* - randomizes the order of A, AAAA and MX records. +*loadbalance* - randomizes the order of A, AAAA and MX records and optionally prefers specific subnets. ## Description @@ -18,6 +18,7 @@ implementations (like glibc) are particular about that. ~~~ loadbalance [round_robin | weighted WEIGHTFILE] { reload DURATION + prefer CIDR [CIDR...] } ~~~ * `round_robin` policy randomizes the order of A, AAAA, and MX records applying a uniform probability distribution. This is the default load balancing policy. @@ -26,6 +27,8 @@ loadbalance [round_robin | weighted WEIGHTFILE] { (top) A/AAAA record in the answer. Note that it does not shuffle all the records in the answer, it is only concerned about the first A/AAAA record returned in the answer. +Additionally, the plugin supports subnet-based ordering using the `prefer` directive, which reorders A/AAAA records so that IPs from preferred subnets appear first. + * **WEIGHTFILE** is the file containing the weight values assigned to IPs for various domain names. If the path is relative, the path from the **root** plugin will be prepended to it. The format is explained below in the *Weightfile* section. * **DURATION** interval to reload `WEIGHTFILE` and update weight assignments if there are changes in the file. The default value is `30s`. A value of `0s` means to not scan for changes and reload. @@ -88,3 +91,17 @@ www.example.com 100.64.1.3 2 ~~~ +### Subnet Prioritization + +Prioritize IPs from 10.9.20.0/24 and 192.168.1.0/24: + +```corefile +. { + loadbalance round_robin { + prefer 10.9.20.0/24 192.168.1.0/24 + } + forward . 1.1.1.1 +} +``` + +If the DNS response includes multiple A/AAAA records, the plugin will reorder them to place the ones matching preferred subnets first. diff --git a/plugin/loadbalance/prefer.go b/plugin/loadbalance/prefer.go new file mode 100644 index 0000000000..44b3d9c73a --- /dev/null +++ b/plugin/loadbalance/prefer.go @@ -0,0 +1,76 @@ +package loadbalance + +import ( + "net" + + "github.com/miekg/dns" +) + +func reorderPreferredSubnets(msg *dns.Msg, subnets []*net.IPNet) *dns.Msg { + msg.Answer = reorderRecords(msg.Answer, subnets) + msg.Extra = reorderRecords(msg.Extra, subnets) + return msg +} + +func reorderRecords(records []dns.RR, subnets []*net.IPNet) []dns.RR { + var cname, address, mx, rest []dns.RR + + for _, r := range records { + switch r.Header().Rrtype { + case dns.TypeCNAME: + cname = append(cname, r) + case dns.TypeA, dns.TypeAAAA: + address = append(address, r) + case dns.TypeMX: + mx = append(mx, r) + default: + rest = append(rest, r) + } + } + + sorted := sortBySubnetPriority(address, subnets) + + out := append([]dns.RR{}, cname...) + out = append(out, sorted...) + out = append(out, mx...) + out = append(out, rest...) + return out +} + +func sortBySubnetPriority(records []dns.RR, subnets []*net.IPNet) []dns.RR { + matched := make([]dns.RR, 0, len(records)) + seen := make(map[int]bool) + + for _, subnet := range subnets { + for i, r := range records { + if seen[i] { + continue + } + ip := extractIP(r) + if ip != nil && subnet.Contains(ip) { + matched = append(matched, r) + seen[i] = true + } + } + } + + unmatched := make([]dns.RR, 0, len(records)-len(matched)) + for i, r := range records { + if !seen[i] { + unmatched = append(unmatched, r) + } + } + + return append(matched, unmatched...) +} + +func extractIP(rr dns.RR) net.IP { + switch r := rr.(type) { + case *dns.A: + return r.A + case *dns.AAAA: + return r.AAAA + default: + return nil + } +} diff --git a/plugin/loadbalance/prefer_test.go b/plugin/loadbalance/prefer_test.go new file mode 100644 index 0000000000..12537c2f8a --- /dev/null +++ b/plugin/loadbalance/prefer_test.go @@ -0,0 +1,96 @@ +package loadbalance + +import ( + "net" + "testing" + + "github.com/coredns/coredns/plugin/test" + + "github.com/miekg/dns" +) + +func TestSortPreferred(t *testing.T) { + records := []dns.RR{ + test.A("example.org. 300 IN A 10.9.30.1"), + test.A("example.org. 300 IN A 10.9.20.5"), + test.A("example.org. 300 IN A 192.168.1.2"), + test.A("example.org. 300 IN A 10.10.0.1"), + test.A("example.org. 300 IN A 10.9.20.3"), + test.A("example.org. 300 IN A 172.16.0.1"), + test.AAAA("example.org. 300 IN AAAA 2001:db8::1"), + test.AAAA("example.org. 300 IN AAAA 2001:db8:abcd::1"), + test.AAAA("example.org. 300 IN AAAA fd00::1"), + test.CNAME("example.org. 300 IN CNAME alias.example.org."), + } + + subnets := []*net.IPNet{} + cidrs := []string{"2001:db8::/32", "10.9.20.0/24", "10.9.30.0/24"} + for _, cidr := range cidrs { + _, subnet, err := net.ParseCIDR(cidr) + if err != nil { + t.Fatalf("Failed to parse CIDR: %v", err) + } + subnets = append(subnets, subnet) + } + + msg := &dns.Msg{Answer: records} + reorderPreferredSubnets(msg, subnets) + sorted := msg.Answer + + expectedOrder := []string{ + "alias.example.org.", + "2001:db8::1", + "2001:db8:abcd::1", + "10.9.20.5", + "10.9.20.3", + "10.9.30.1", + "192.168.1.2", + "10.10.0.1", + "172.16.0.1", + "fd00::1", + } + + if len(sorted) != len(expectedOrder) { + t.Fatalf("Expected %d records, got %d", len(expectedOrder), len(sorted)) + } + + for i, rr := range sorted { + expected := expectedOrder[i] + switch r := rr.(type) { + case *dns.CNAME: + if r.Target != expected { + t.Errorf("Record %d: expected CNAME %s, got %s", i, expected, r.Target) + } + case *dns.A: + if r.A.String() != expected { + t.Errorf("Record %d: expected A IP %s, got %s", i, expected, r.A.String()) + } + case *dns.AAAA: + if r.AAAA.String() != expected { + t.Errorf("Record %d: expected AAAA IP %s, got %s", i, expected, r.AAAA.String()) + } + default: + t.Errorf("Record %d: unexpected RR type %T", i, r) + } + } +} + +func TestExtractIP(t *testing.T) { + a := test.A("example.org. 300 IN A 10.0.0.1") + ip := extractIP(a) + if ip.String() != "10.0.0.1" { + t.Errorf("Expected 10.0.0.1, got %s", ip.String()) + } + + aaaa := test.AAAA("example.org. 300 IN AAAA ::1") + ip = extractIP(aaaa) + if ip.String() != "::1" { + t.Errorf("Expected ::1, got %s", ip.String()) + } + + cname := test.CNAME("example.org. 300 IN CNAME other.org.") + ip = extractIP(cname) + if ip != nil { + t.Errorf("Expected nil for CNAME, got %v", ip) + } +} diff --git a/plugin/loadbalance/setup.go b/plugin/loadbalance/setup.go index 6a84e31fd0..b1ded1aa65 100644 --- a/plugin/loadbalance/setup.go +++ b/plugin/loadbalance/setup.go @@ -3,6 +3,7 @@ package loadbalance import ( "errors" "fmt" + "net" "path/filepath" "time" @@ -24,6 +25,7 @@ type lbFuncs struct { onStartUpFunc func() error onShutdownFunc func() error weighted *weightedRR // used in unit tests only + preferSubnets []*net.IPNet } func setup(c *caddy.Controller) error { @@ -39,65 +41,90 @@ func setup(c *caddy.Controller) error { c.OnShutdown(lb.onShutdownFunc) } + shuffle := lb.shuffleFunc + if len(lb.preferSubnets) > 0 { + original := shuffle + shuffle = func(res *dns.Msg) *dns.Msg { + return reorderPreferredSubnets(original(res), lb.preferSubnets) + } + } + dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { - return LoadBalance{Next: next, shuffle: lb.shuffleFunc} + return LoadBalance{Next: next, shuffle: shuffle} }) return nil } -// func parse(c *caddy.Controller) (string, *weightedRR, error) { func parse(c *caddy.Controller) (*lbFuncs, error) { config := dnsserver.GetConfig(c) + lb := &lbFuncs{} for c.Next() { args := c.RemainingArgs() if len(args) == 0 { - return &lbFuncs{shuffleFunc: randomShuffle}, nil - } - switch args[0] { - case ramdomShufflePolicy: - if len(args) > 1 { - return nil, c.Errf("unknown property for %s", args[0]) - } - return &lbFuncs{shuffleFunc: randomShuffle}, nil - case weightedRoundRobinPolicy: - if len(args) < 2 { - return nil, c.Err("missing weight file argument") - } + lb.shuffleFunc = randomShuffle + } else { + switch args[0] { + case ramdomShufflePolicy: + if len(args) > 1 { + return nil, c.Errf("unknown property for %s", args[0]) + } + lb.shuffleFunc = randomShuffle - if len(args) > 2 { - return nil, c.Err("unexpected argument(s)") + case weightedRoundRobinPolicy: + if len(args) < 2 { + return nil, c.Err("missing weight file argument") + } + if len(args) > 2 { + return nil, c.Err("unexpected argument(s)") + } + weightFileName := args[1] + if !filepath.IsAbs(weightFileName) && config.Root != "" { + weightFileName = filepath.Join(config.Root, weightFileName) + } + reload := 30 * time.Second + for c.NextBlock() { + switch c.Val() { + case "reload": + t := c.RemainingArgs() + if len(t) < 1 { + return nil, c.Err("reload duration value is missing") + } + if len(t) > 1 { + return nil, c.Err("unexpected argument") + } + var err error + reload, err = time.ParseDuration(t[0]) + if err != nil { + return nil, c.Errf("invalid reload duration '%s'", t[0]) + } + default: + return nil, c.Errf("unknown property '%s'", c.Val()) + } + } + *lb = *createWeightedFuncs(weightFileName, reload) + default: + return nil, fmt.Errorf("unknown policy: %s", args[0]) } + } - weightFileName := args[1] - if !filepath.IsAbs(weightFileName) && config.Root != "" { - weightFileName = filepath.Join(config.Root, weightFileName) - } - reload := 30 * time.Second // default reload period - for c.NextBlock() { - switch c.Val() { - case "reload": - t := c.RemainingArgs() - if len(t) < 1 { - return nil, c.Err("reload duration value is missing") - } - if len(t) > 1 { - return nil, c.Err("unexpected argument") - } - var err error - reload, err = time.ParseDuration(t[0]) + for c.NextBlock() { + switch c.Val() { + case "prefer": + cidrs := c.RemainingArgs() + for _, cidr := range cidrs { + _, subnet, err := net.ParseCIDR(cidr) if err != nil { - return nil, c.Errf("invalid reload duration '%s'", t[0]) + return nil, c.Errf("invalid CIDR %q: %v", cidr, err) } - default: - return nil, c.Errf("unknown property '%s'", c.Val()) + lb.preferSubnets = append(lb.preferSubnets, subnet) } + default: + return nil, c.Errf("unknown property '%s'", c.Val()) } - return createWeightedFuncs(weightFileName, reload), nil - default: - return nil, fmt.Errorf("unknown policy: %s", args[0]) } } - return nil, c.ArgErr() + + return lb, nil } diff --git a/plugin/metrics/metrics.go b/plugin/metrics/metrics.go index 6a9e65272d..129561e0a6 100644 --- a/plugin/metrics/metrics.go +++ b/plugin/metrics/metrics.go @@ -98,7 +98,12 @@ func (m *Metrics) OnStartup() error { m.mux.Handle("/metrics", promhttp.HandlerFor(m.Reg, promhttp.HandlerOpts{})) // creating some helper variables to avoid data races on m.srv and m.ln - server := &http.Server{Handler: m.mux} + server := &http.Server{ + Handler: m.mux, + ReadTimeout: 5 * time.Second, + WriteTimeout: 5 * time.Second, + IdleTimeout: 5 * time.Second, + } m.srv = server go func() { diff --git a/plugin/metrics/metrics_test.go b/plugin/metrics/metrics_test.go index bd72bf1f40..09172a2895 100644 --- a/plugin/metrics/metrics_test.go +++ b/plugin/metrics/metrics_test.go @@ -2,7 +2,9 @@ package metrics import ( "context" + "net" "testing" + "time" "github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin/pkg/dnstest" @@ -80,3 +82,48 @@ func TestMetrics(t *testing.T) { } } } + +func TestMetricsHTTPTimeout(t *testing.T) { + met := New("localhost:0") + if err := met.OnStartup(); err != nil { + t.Fatalf("Failed to start metrics handler: %s", err) + } + defer met.OnFinalShutdown() + + // Use context with timeout to prevent test from hanging indefinitely + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + done := make(chan error, 1) + + go func() { + conn, err := net.Dial("tcp", ListenAddr) + if err != nil { + done <- err + return + } + defer conn.Close() + + // Send partial HTTP request and then stop sending data + // This will cause the server to wait for more data and hit ReadTimeout + partialRequest := "GET /metrics HTTP/1.1\r\nHost: " + ListenAddr + "\r\nContent-Length: 100\r\n\r\n" + _, err = conn.Write([]byte(partialRequest)) + if err != nil { + done <- err + return + } + + // Now just wait - server should timeout trying to read the remaining data + // If server has no ReadTimeout, this will hang indefinitely + buffer := make([]byte, 1024) + _, err = conn.Read(buffer) + done <- err + }() + + select { + case <-done: + t.Log("HTTP request timed out by server") + case <-ctx.Done(): + t.Error("HTTP request did not time out") + } +} diff --git a/plugin/pkg/fall/fall.go b/plugin/pkg/fall/fall.go index 898c8db76b..b4b9329f2f 100644 --- a/plugin/pkg/fall/fall.go +++ b/plugin/pkg/fall/fall.go @@ -13,6 +13,8 @@ package fall import ( + "slices" + "github.com/coredns/coredns/plugin" ) @@ -48,15 +50,7 @@ func (f *F) SetZonesFromArgs(zones []string) { // Equal returns true if f and g are equal. func (f *F) Equal(g F) bool { - if len(f.Zones) != len(g.Zones) { - return false - } - for i := range f.Zones { - if f.Zones[i] != g.Zones[i] { - return false - } - } - return true + return slices.Equal(f.Zones, g.Zones) } // Zero returns a zero valued F. diff --git a/plugin/plugin.go b/plugin/plugin.go index b415a5533f..43c1e65478 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -67,7 +67,7 @@ func (f HandlerFunc) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns. func (f HandlerFunc) Name() string { return "handlerfunc" } // Error returns err with 'plugin/name: ' prefixed to it. -func Error(name string, err error) error { return fmt.Errorf("%s/%s: %s", "plugin", name, err) } +func Error(name string, err error) error { return fmt.Errorf("%s/%s: %w", "plugin", name, err) } // NextOrFailure calls next.ServeDNS when next is not nil, otherwise it will return, a ServerFailure and a `no next plugin found` error. func NextOrFailure(name string, next Handler, ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { diff --git a/plugin/pprof/pprof_test.go b/plugin/pprof/pprof_test.go new file mode 100644 index 0000000000..6bea4e94dc --- /dev/null +++ b/plugin/pprof/pprof_test.go @@ -0,0 +1,163 @@ +package pprof + +import ( + "fmt" + "net/http" + "strings" + "testing" + "time" +) + +func TestHandlerStartup(t *testing.T) { + h := &handler{ + addr: ":0", // Use available port + rateBloc: 5, + } + + err := h.Startup() + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + defer h.Shutdown() + + if h.ln == nil { + t.Fatal("Expected listener to be set") + } + + if h.mux == nil { + t.Fatal("Expected mux to be set") + } + + // Verify the server is actually listening + addr := h.ln.Addr().String() + if addr == "" { + t.Fatal("Expected non-empty address") + } +} + +func TestHandlerShutdown(t *testing.T) { + h := &handler{ + addr: ":0", + rateBloc: 1, + } + + // Start the handler + err := h.Startup() + if err != nil { + t.Fatalf("Expected no error during startup, got: %v", err) + } + + // Verify listener exists + if h.ln == nil { + t.Fatal("Expected listener to be set after startup") + } + + // Shutdown and verify no error + err = h.Shutdown() + if err != nil { + t.Errorf("Expected no error during shutdown, got: %v", err) + } +} + +func TestHandlerShutdownWithoutStartup(t *testing.T) { + h := &handler{} + + // Shutdown without startup should not error + err := h.Shutdown() + if err != nil { + t.Errorf("Expected no error when shutting down without startup, got: %v", err) + } +} + +func TestHandlerPprofEndpoints(t *testing.T) { + h := &handler{ + addr: ":0", + rateBloc: 1, + } + + err := h.Startup() + if err != nil { + t.Fatalf("Expected no error during startup, got: %v", err) + } + defer h.Shutdown() + + // Wait a bit for the server to fully start + time.Sleep(100 * time.Millisecond) + + baseURL := fmt.Sprintf("http://%s", h.ln.Addr().String()) + + testCases := []struct { + path string + expectedStatus int + }{ + {"/debug/pprof/", http.StatusOK}, // Index page + {"/debug/pprof/cmdline", http.StatusOK}, // Cmdline + {"/debug/pprof/symbol", http.StatusOK}, // Symbol + } + + for _, tc := range testCases { + url := baseURL + tc.path + resp, err := http.Get(url) + if err != nil { + t.Errorf("Error making request to %s: %v", url, err) + continue + } + defer resp.Body.Close() + + if resp.StatusCode != tc.expectedStatus { + t.Errorf("Expected status %d for %s, got %d", tc.expectedStatus, tc.path, resp.StatusCode) + } + } +} + +func TestHandlerPprofRedirect(t *testing.T) { + h := &handler{ + addr: ":0", + rateBloc: 1, + } + + err := h.Startup() + if err != nil { + t.Fatalf("Expected no error during startup, got: %v", err) + } + defer h.Shutdown() + + // Wait a bit for the server to fully start + time.Sleep(100 * time.Millisecond) + + // Create a client that doesn't follow redirects + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + + url := fmt.Sprintf("http://%s/debug/pprof", h.ln.Addr().String()) + resp, err := client.Get(url) + if err != nil { + t.Fatalf("Error making request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusFound { + t.Errorf("Expected status %d, got %d", http.StatusFound, resp.StatusCode) + } + + location := resp.Header.Get("Location") + if !strings.HasSuffix(location, "/debug/pprof/") { + t.Errorf("Expected redirect to end with '/debug/pprof/', got: %s", location) + } +} + +func TestHandlerStartupInvalidAddress(t *testing.T) { + h := &handler{ + addr: "invalid-address-format", + rateBloc: 1, + } + + err := h.Startup() + if err == nil { + t.Fatal("Expected error for invalid address format") + defer h.Shutdown() + } +} diff --git a/plugin/pprof/setup_test.go b/plugin/pprof/setup_test.go index 500a400d04..0c48a59f83 100644 --- a/plugin/pprof/setup_test.go +++ b/plugin/pprof/setup_test.go @@ -29,6 +29,12 @@ func TestPProf(t *testing.T) { {`pprof { block 20 30 }`, true}, + {`pprof { + block invalid + }`, true}, + {`pprof { + unknown_property + }`, true}, {`pprof pprof`, true}, } diff --git a/plugin/rewrite/README.md b/plugin/rewrite/README.md index 9740f9d5a7..a86d9cccb1 100644 --- a/plugin/rewrite/README.md +++ b/plugin/rewrite/README.md @@ -394,11 +394,12 @@ The values of FROM and TO can be any of the following, text value or numeric: ## EDNS0 Options -Using the FIELD edns0, you can set, append, or replace specific EDNS0 options in the request. +Using the FIELD edns0, you can set, append, replace, or unset specific EDNS0 options in the request. * `replace` will modify any "matching" option with the specified option. The criteria for "matching" varies based on EDNS0 type. * `append` will add the option only if no matching option exists * `set` will modify a matching option or add one if none is found +* `unset` will remove the matching option if one exists Currently supported are `EDNS0_LOCAL`, `EDNS0_NSID` and `EDNS0_SUBNET`. @@ -444,10 +445,17 @@ some-plugin rewrite edns0 local set 0xffee {some-plugin/some-label} ~~~ +A local option may be removed by unsetting its code. Example: + +~~~ +rewrite edns0 local unset 0xffee +~~~ + ### EDNS0_NSID This has no fields; it will add an NSID option with an empty string for the NSID. If the option already exists -and the action is `replace` or `set`, then the NSID in the option will be set to the empty string. +and the action is `replace` or `set`, then the NSID in the option will be set to the empty string. +The option can be removed with the `unset` action. ### EDNS0_SUBNET @@ -463,6 +471,12 @@ rewrite edns0 subnet set 24 56 * If the query's source IP address is an IPv4 address, the first 24 bits in the IP will be the network subnet. * If the query's source IP address is an IPv6 address, the first 56 bits in the IP will be the network subnet. +This option can be removed by using `unset`: + +~~~ +rewrite edns0 subnet unset +~~~ + ### EDNS0 Revert Using the `revert` flag, you can revert the changes made by this rewrite call, so the response will not contain this option. diff --git a/plugin/rewrite/edns0.go b/plugin/rewrite/edns0.go index 44e4579193..f4155fd4bb 100644 --- a/plugin/rewrite/edns0.go +++ b/plugin/rewrite/edns0.go @@ -80,10 +80,25 @@ func setupEdns0Opt(r *dns.Msg) *dns.OPT { return o } +func unsetEdns0Option(opt *dns.OPT, code uint16) { + var newOpts []dns.EDNS0 + for _, o := range opt.Option { + if o.Option() != code { + newOpts = append(newOpts, o) + } + } + opt.Option = newOpts +} + // Rewrite will alter the request EDNS0 NSID option func (rule *edns0NsidRule) Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result) { o := setupEdns0Opt(state.Req) + if rule.action == Unset { + unsetEdns0Option(o, dns.EDNS0NSID) + return nil, RewriteDone + } + var resp ResponseRules for _, s := range o.Option { @@ -118,6 +133,11 @@ func (rule *edns0NsidRule) Mode() string { return rule.mode } func (rule *edns0LocalRule) Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result) { o := setupEdns0Opt(state.Req) + if rule.action == Unset { + unsetEdns0Option(o, rule.code) + return nil, RewriteDone + } + var resp ResponseRules for _, s := range o.Option { @@ -162,6 +182,8 @@ func newEdns0Rule(mode string, args ...string) (Rule, error) { case Append: case Replace: case Set: + case Unset: + return newEdns0UnsetRule(mode, action, ruleType, args...) default: return nil, fmt.Errorf("invalid action: %q", action) } @@ -198,6 +220,28 @@ func newEdns0Rule(mode string, args ...string) (Rule, error) { } } +func newEdns0UnsetRule(mode string, action string, ruleType string, args ...string) (Rule, error) { + switch ruleType { + case "local": + if len(args) != 3 { + return nil, fmt.Errorf("local unset action requires exactly two arguments") + } + return newEdns0LocalRule(mode, action, args[2], "", false) + case "nsid": + if len(args) != 2 { + return nil, fmt.Errorf("nsid unset action requires exactly one argument") + } + return &edns0NsidRule{mode, action, false}, nil + case "subnet": + if len(args) != 2 { + return nil, fmt.Errorf("subnet unset action requires exactly one argument") + } + return &edns0SubnetRule{mode, 0, 0, action, false}, nil + default: + return nil, fmt.Errorf("invalid rule type %q", ruleType) + } +} + func newEdns0LocalRule(mode, action, code, data string, revert bool) (*edns0LocalRule, error) { c, err := strconv.ParseUint(code, 0, 16) if err != nil { @@ -393,6 +437,11 @@ func (rule *edns0SubnetRule) fillEcsData(state request.Request, ecs *dns.EDNS0_S func (rule *edns0SubnetRule) Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result) { o := setupEdns0Opt(state.Req) + if rule.action == Unset { + unsetEdns0Option(o, dns.EDNS0SUBNET) + return nil, RewriteDone + } + var resp ResponseRules for _, s := range o.Option { @@ -433,6 +482,7 @@ const ( Replace = "replace" Set = "set" Append = "append" + Unset = "unset" ) // Supported local EDNS0 variables diff --git a/plugin/rewrite/rewrite_test.go b/plugin/rewrite/rewrite_test.go index 74f596acf6..94f2e15d47 100644 --- a/plugin/rewrite/rewrite_test.go +++ b/plugin/rewrite/rewrite_test.go @@ -65,9 +65,12 @@ func TestNewRule(t *testing.T) { {[]string{"class", "XY", "WV"}, true, nil}, {[]string{"class", "IN", "WV"}, true, nil}, {[]string{"edns0"}, true, nil}, + {[]string{"edns0", "unknown-rule-type", "set"}, true, nil}, + {[]string{"edns0", "unknown-rule-type", "unset"}, true, nil}, {[]string{"edns0", "local"}, true, nil}, {[]string{"edns0", "local", "set"}, true, nil}, {[]string{"edns0", "local", "set", "0xffee"}, true, nil}, + {[]string{"edns0", "local", "set", "invalid-uint", "abcdefg"}, true, nil}, {[]string{"edns0", "local", "set", "65518", "abcdefg"}, false, reflect.TypeOf(&edns0LocalRule{})}, {[]string{"edns0", "local", "set", "0xffee", "abcdefg"}, false, reflect.TypeOf(&edns0LocalRule{})}, {[]string{"edns0", "local", "set", "0xffee", "abcdefg", "revert"}, false, reflect.TypeOf(&edns0LocalRule{})}, @@ -75,6 +78,9 @@ func TestNewRule(t *testing.T) { {[]string{"edns0", "local", "append", "0xffee", "abcdefg", "revert"}, false, reflect.TypeOf(&edns0LocalRule{})}, {[]string{"edns0", "local", "replace", "0xffee", "abcdefg"}, false, reflect.TypeOf(&edns0LocalRule{})}, {[]string{"edns0", "local", "replace", "0xffee", "abcdefg", "revert"}, false, reflect.TypeOf(&edns0LocalRule{})}, + {[]string{"edns0", "local", "unset", "0xffee"}, false, reflect.TypeOf(&edns0LocalRule{})}, + {[]string{"edns0", "local", "unset", "0xffee", "abcdefg"}, true, reflect.TypeOf(&edns0LocalRule{})}, + {[]string{"edns0", "local", "unset", "0xffee", "revert"}, true, reflect.TypeOf(&edns0LocalRule{})}, {[]string{"edns0", "local", "foo", "0xffee", "abcdefg"}, true, nil}, {[]string{"edns0", "local", "set", "0xffee", "0xabcdefg"}, true, nil}, {[]string{"edns0", "nsid", "set", "junk"}, true, nil}, @@ -84,7 +90,10 @@ func TestNewRule(t *testing.T) { {[]string{"edns0", "nsid", "append", "revert"}, false, reflect.TypeOf(&edns0NsidRule{})}, {[]string{"edns0", "nsid", "replace"}, false, reflect.TypeOf(&edns0NsidRule{})}, {[]string{"edns0", "nsid", "replace", "revert"}, false, reflect.TypeOf(&edns0NsidRule{})}, + {[]string{"edns0", "nsid", "unset"}, false, reflect.TypeOf(&edns0NsidRule{})}, + {[]string{"edns0", "nsid", "unset", "revert"}, true, reflect.TypeOf(&edns0NsidRule{})}, {[]string{"edns0", "nsid", "foo"}, true, nil}, + {[]string{"edns0", "local", "set", "invalid-uint", "{qname}"}, true, nil}, {[]string{"edns0", "local", "set", "0xffee", "{dummy}"}, true, nil}, {[]string{"edns0", "local", "set", "0xffee", "{qname}"}, false, reflect.TypeOf(&edns0VariableRule{})}, {[]string{"edns0", "local", "set", "0xffee", "{qtype}"}, false, reflect.TypeOf(&edns0VariableRule{})}, @@ -123,6 +132,9 @@ func TestNewRule(t *testing.T) { {[]string{"edns0", "subnet", "append", "24", "56", "revert"}, false, reflect.TypeOf(&edns0SubnetRule{})}, {[]string{"edns0", "subnet", "replace", "24", "56"}, false, reflect.TypeOf(&edns0SubnetRule{})}, {[]string{"edns0", "subnet", "replace", "24", "56", "revert"}, false, reflect.TypeOf(&edns0SubnetRule{})}, + {[]string{"edns0", "subnet", "unset"}, false, reflect.TypeOf(&edns0SubnetRule{})}, + {[]string{"edns0", "subnet", "unset", "24", "56"}, true, reflect.TypeOf(&edns0SubnetRule{})}, + {[]string{"edns0", "subnet", "unset", "revert"}, true, reflect.TypeOf(&edns0SubnetRule{})}, {[]string{"unknown-action", "name", "a.com", "b.com"}, true, nil}, {[]string{"stop", "name", "a.com", "b.com"}, false, reflect.TypeOf(&exactNameRule{})}, {[]string{"continue", "name", "a.com", "b.com"}, false, reflect.TypeOf(&exactNameRule{})}, @@ -157,9 +169,11 @@ func TestNewRule(t *testing.T) { {[]string{"stop", "edns0", "subnet", "set", "24", "56"}, false, reflect.TypeOf(&edns0SubnetRule{})}, {[]string{"stop", "edns0", "subnet", "append", "24", "56"}, false, reflect.TypeOf(&edns0SubnetRule{})}, {[]string{"stop", "edns0", "subnet", "replace", "24", "56"}, false, reflect.TypeOf(&edns0SubnetRule{})}, + {[]string{"stop", "edns0", "subnet", "unset"}, false, reflect.TypeOf(&edns0SubnetRule{})}, {[]string{"continue", "edns0", "subnet", "set", "24", "56"}, false, reflect.TypeOf(&edns0SubnetRule{})}, {[]string{"continue", "edns0", "subnet", "append", "24", "56"}, false, reflect.TypeOf(&edns0SubnetRule{})}, {[]string{"continue", "edns0", "subnet", "replace", "24", "56"}, false, reflect.TypeOf(&edns0SubnetRule{})}, + {[]string{"continue", "edns0", "subnet", "unset"}, false, reflect.TypeOf(&edns0SubnetRule{})}, } for i, tc := range tests { @@ -1046,3 +1060,101 @@ func TestRewriteEDNS0Revert(t *testing.T) { } } } + +func TestRewriteEDNS0Unset(t *testing.T) { + rw := Rewrite{ + Next: plugin.HandlerFunc(msgPrinter), + RevertPolicy: NewRevertPolicy(false, false), + } + + tests := []struct { + fromOpts []dns.EDNS0 + args []string + toOpts []dns.EDNS0 + }{ + { + []dns.EDNS0{}, + []string{"local", "unset", "0xffee"}, + []dns.EDNS0{}, + }, + { + []dns.EDNS0{&dns.EDNS0_LOCAL{Code: 0xffee, Data: []byte{0xab, 0xcd, 0xef}}}, + []string{"local", "unset", "0xffee"}, + []dns.EDNS0{}, + }, + { + []dns.EDNS0{&dns.EDNS0_LOCAL{Code: 0xffee, Data: []byte{0xab, 0xcd, 0xef}}}, + []string{"local", "unset", "0xffed"}, + []dns.EDNS0{&dns.EDNS0_LOCAL{Code: 0xffee, Data: []byte{0xab, 0xcd, 0xef}}}, + }, + { + []dns.EDNS0{&dns.EDNS0_NSID{Code: dns.EDNS0NSID, Nsid: ""}}, + []string{"nsid", "unset"}, + []dns.EDNS0{}, + }, + { + []dns.EDNS0{}, + []string{"nsid", "unset"}, + []dns.EDNS0{}, + }, + { + []dns.EDNS0{&dns.EDNS0_SUBNET{Code: 0x8, + Family: 0x1, + SourceNetmask: 0x0, + SourceScope: 0x0, + Address: []byte{0x00, 0x00, 0x00, 0x00}, + }}, + []string{"subnet", "unset"}, + []dns.EDNS0{}, + }, + { + []dns.EDNS0{}, + []string{"subnet", "unset"}, + []dns.EDNS0{}, + }, + { + []dns.EDNS0{&dns.EDNS0_LOCAL{Code: 0xffee, Data: []byte("foobar")}, &dns.EDNS0_NSID{Code: dns.EDNS0NSID, Nsid: ""}}, + []string{"nsid", "unset"}, + []dns.EDNS0{&dns.EDNS0_LOCAL{Code: 0xffee, Data: []byte("foobar")}}, + }, + { + []dns.EDNS0{&dns.EDNS0_LOCAL{Code: 0xffee, Data: []byte("foobar")}, &dns.EDNS0_NSID{Code: dns.EDNS0NSID, Nsid: ""}}, + []string{"local", "unset", "0xffee"}, + []dns.EDNS0{&dns.EDNS0_NSID{Code: dns.EDNS0NSID, Nsid: ""}}, + }, + { + []dns.EDNS0{&dns.EDNS0_LOCAL{Code: 0xffee, Data: []byte("foobar")}, &dns.EDNS0_NSID{Code: dns.EDNS0NSID, Nsid: ""}}, + []string{"subnet", "unset"}, + []dns.EDNS0{&dns.EDNS0_LOCAL{Code: 0xffee, Data: []byte("foobar")}, &dns.EDNS0_NSID{Code: dns.EDNS0NSID, Nsid: ""}}, + }, + } + + ctx := context.TODO() + for i, tc := range tests { + m := new(dns.Msg) + m.SetQuestion("example.com.", dns.TypeA) + m.Question[0].Qclass = dns.ClassINET + o := m.IsEdns0() + if tc.fromOpts != nil { + if o == nil { + m.SetEdns0(4096, true) + o = m.IsEdns0() + } + o.Option = append(o.Option, tc.fromOpts...) + } + + r, err := newEdns0Rule("stop", tc.args...) + if err != nil { + t.Errorf("Error creating test rule: %s", err) + continue + } + rw.Rules = []Rule{r} + + rec := dnstest.NewRecorder(&test.ResponseWriter{}) + rw.ServeDNS(ctx, rec, m) + + if !optsEqual(o.Option, tc.toOpts) { + t.Errorf("Test %d: Expected %v but got %v", i, tc.toOpts, o) + } + } +} diff --git a/plugin/route53/route53.go b/plugin/route53/route53.go index 3d3c0f44a9..fc1f06d16d 100644 --- a/plugin/route53/route53.go +++ b/plugin/route53/route53.go @@ -17,9 +17,9 @@ import ( "github.com/coredns/coredns/plugin/pkg/upstream" "github.com/coredns/coredns/request" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/route53" - "github.com/aws/aws-sdk-go/service/route53/route53iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/route53" + "github.com/aws/aws-sdk-go-v2/service/route53/types" "github.com/miekg/dns" ) @@ -29,7 +29,7 @@ type Route53 struct { Fall fall.F zoneNames []string - client route53iface.Route53API + client route53Client upstream *upstream.Upstream refresh time.Duration @@ -50,12 +50,12 @@ type zones map[string][]*zone // does exist, and returns a new *Route53. In addition to this, upstream is use // for doing recursive queries against CNAMEs. Returns error if it cannot // verify any given domain name/zone id pair. -func New(ctx context.Context, c route53iface.Route53API, keys map[string][]string, refresh time.Duration) (*Route53, error) { +func New(ctx context.Context, c route53Client, keys map[string][]string, refresh time.Duration) (*Route53, error) { zones := make(map[string][]*zone, len(keys)) zoneNames := make([]string, 0, len(keys)) for dns, hostedZoneIDs := range keys { for _, hostedZoneID := range hostedZoneIDs { - _, err := c.ListHostedZonesByNameWithContext(ctx, &route53.ListHostedZonesByNameInput{ + _, err := c.ListHostedZonesByName(ctx, &route53.ListHostedZonesByNameInput{ DNSName: aws.String(dns), HostedZoneId: aws.String(hostedZoneID), }) @@ -211,19 +211,19 @@ func maybeUnescape(s string) (string, error) { } } -func updateZoneFromRRS(rrs *route53.ResourceRecordSet, z *file.Zone) error { +func updateZoneFromRRS(rrs *types.ResourceRecordSet, z *file.Zone) error { for _, rr := range rrs.ResourceRecords { - n, err := maybeUnescape(aws.StringValue(rrs.Name)) + n, err := maybeUnescape(aws.ToString(rrs.Name)) if err != nil { - return fmt.Errorf("failed to unescape `%s' name: %v", aws.StringValue(rrs.Name), err) + return fmt.Errorf("failed to unescape `%s' name: %v", aws.ToString(rrs.Name), err) } - v, err := maybeUnescape(aws.StringValue(rr.Value)) + v, err := maybeUnescape(aws.ToString(rr.Value)) if err != nil { - return fmt.Errorf("failed to unescape `%s' value: %v", aws.StringValue(rr.Value), err) + return fmt.Errorf("failed to unescape `%s' value: %v", aws.ToString(rr.Value), err) } // Assemble RFC 1035 conforming record to pass into dns scanner. - rfc1035 := fmt.Sprintf("%s %d IN %s %s", n, aws.Int64Value(rrs.TTL), aws.StringValue(rrs.Type), v) + rfc1035 := fmt.Sprintf("%s %d IN %s %s", n, aws.ToInt64(rrs.TTL), rrs.Type, v) r, err := dns.NewRR(rfc1035) if err != nil { return fmt.Errorf("failed to parse resource record: %v", err) @@ -253,21 +253,28 @@ func (h *Route53) updateZones(ctx context.Context) error { newZ.Upstream = h.upstream in := &route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String(hostedZone.id), - MaxItems: aws.String("1000"), + MaxItems: aws.Int32(1000), } - err = h.client.ListResourceRecordSetsPagesWithContext(ctx, in, - func(out *route53.ListResourceRecordSetsOutput, last bool) bool { - for _, rrs := range out.ResourceRecordSets { - if err := updateZoneFromRRS(rrs, newZ); err != nil { - // Maybe unsupported record type. Log and carry on. - log.Warningf("Failed to process resource record set: %v", err) - } + complete := false + var out *route53.ListResourceRecordSetsOutput + for out, err = h.client.ListResourceRecordSets(ctx, in); !complete; out, err = h.client.ListResourceRecordSets(ctx, in) { + if err != nil { + err = fmt.Errorf("failed to list resource records for %v:%v from route53: %v", zName, hostedZone.id, err) + return + } + for _, rrs := range out.ResourceRecordSets { + if err := updateZoneFromRRS(&rrs, newZ); err != nil { + // Maybe unsupported record type. Log and carry on. + log.Warningf("Failed to process resource record set: %v", err) } - return true - }) - if err != nil { - err = fmt.Errorf("failed to list resource records for %v:%v from route53: %v", zName, hostedZone.id, err) - return + } + if out.IsTruncated { + in.StartRecordName = out.NextRecordName + in.StartRecordType = out.NextRecordType + in.StartRecordIdentifier = out.NextRecordIdentifier + } else { + complete = true + } } h.zMu.Lock() (*z[i]).z = newZ diff --git a/plugin/route53/route53_test.go b/plugin/route53/route53_test.go index d9b2fa102c..538f05a3f8 100644 --- a/plugin/route53/route53_test.go +++ b/plugin/route53/route53_test.go @@ -12,28 +12,28 @@ import ( "github.com/coredns/coredns/plugin/test" crequest "github.com/coredns/coredns/request" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/route53" - "github.com/aws/aws-sdk-go/service/route53/route53iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/route53" + "github.com/aws/aws-sdk-go-v2/service/route53/types" "github.com/miekg/dns" ) type fakeRoute53 struct { - route53iface.Route53API + route53Client } -func (fakeRoute53) ListHostedZonesByNameWithContext(_ aws.Context, input *route53.ListHostedZonesByNameInput, _ ...request.Option) (*route53.ListHostedZonesByNameOutput, error) { +func (fakeRoute53) ListHostedZonesByName(_ context.Context, input *route53.ListHostedZonesByNameInput, optFns ...func(*route53.Options)) (*route53.ListHostedZonesByNameOutput, error) { return nil, nil } -func (fakeRoute53) ListResourceRecordSetsPagesWithContext(_ aws.Context, in *route53.ListResourceRecordSetsInput, fn func(*route53.ListResourceRecordSetsOutput, bool) bool, _ ...request.Option) error { - if aws.StringValue(in.HostedZoneId) == "0987654321" { - return errors.New("bad. zone is bad") +func (fakeRoute53) ListResourceRecordSets(_ context.Context, in *route53.ListResourceRecordSetsInput, optFns ...func(*route53.Options)) (*route53.ListResourceRecordSetsOutput, error) { + if aws.ToString(in.HostedZoneId) == "0987654321" { + return nil, errors.New("bad. zone is bad") } - rrsResponse := map[string][]*route53.ResourceRecordSet{} + rrsResponse := map[string][]types.ResourceRecordSet{} for _, r := range []struct { - rType, name, value, hostedZoneID string + rType types.RRType + name, value, hostedZoneID string }{ {"A", "example.org.", "1.2.3.4", "1234567890"}, {"A", "www.example.org", "1.2.3.4", "1234567890"}, @@ -54,11 +54,11 @@ func (fakeRoute53) ListResourceRecordSetsPagesWithContext(_ aws.Context, in *rou } { rrs, ok := rrsResponse[r.hostedZoneID] if !ok { - rrs = make([]*route53.ResourceRecordSet, 0) + rrs = make([]types.ResourceRecordSet, 0) } - rrs = append(rrs, &route53.ResourceRecordSet{Type: aws.String(r.rType), + rrs = append(rrs, types.ResourceRecordSet{Type: r.rType, Name: aws.String(r.name), - ResourceRecords: []*route53.ResourceRecord{ + ResourceRecords: []types.ResourceRecord{ { Value: aws.String(r.value), }, @@ -68,12 +68,10 @@ func (fakeRoute53) ListResourceRecordSetsPagesWithContext(_ aws.Context, in *rou rrsResponse[r.hostedZoneID] = rrs } - if ok := fn(&route53.ListResourceRecordSetsOutput{ - ResourceRecordSets: rrsResponse[aws.StringValue(in.HostedZoneId)], - }, true); !ok { - return errors.New("paging function return false") - } - return nil + return &route53.ListResourceRecordSetsOutput{ + ResourceRecordSets: rrsResponse[aws.ToString(in.HostedZoneId)], + IsTruncated: false, + }, nil } func TestRoute53(t *testing.T) { diff --git a/plugin/route53/setup.go b/plugin/route53/setup.go index 2fbd374cd1..857158053c 100644 --- a/plugin/route53/setup.go +++ b/plugin/route53/setup.go @@ -14,12 +14,11 @@ import ( "github.com/coredns/coredns/plugin/pkg/fall" clog "github.com/coredns/coredns/plugin/pkg/log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/defaults" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/route53" - "github.com/aws/aws-sdk-go/service/route53/route53iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" + "github.com/aws/aws-sdk-go-v2/service/route53" ) var log = clog.NewWithPlugin("route53") @@ -27,8 +26,27 @@ var log = clog.NewWithPlugin("route53") func init() { plugin.Register("route53", setup) } // exposed for testing -var f = func(opts session.Options) route53iface.Route53API { - return route53.New(session.Must(session.NewSessionWithOptions(opts))) +type route53Client interface { + ActivateKeySigningKey(ctx context.Context, params *route53.ActivateKeySigningKeyInput, optFns ...func(*route53.Options)) (*route53.ActivateKeySigningKeyOutput, error) + ListHostedZonesByName(ctx context.Context, params *route53.ListHostedZonesByNameInput, optFns ...func(*route53.Options)) (*route53.ListHostedZonesByNameOutput, error) + ListResourceRecordSets(ctx context.Context, params *route53.ListResourceRecordSetsInput, optFns ...func(*route53.Options)) (*route53.ListResourceRecordSetsOutput, error) +} + +var f = func(ctx context.Context, cfgOpts []func(*config.LoadOptions) error, clientOpts []func(*route53.Options)) (route53Client, error) { + cfg, err := config.LoadDefaultConfig(ctx, cfgOpts...) + if err != nil { + return nil, err + } + // If no region is specified, retrieve one from IMDS (SDK v1 used the AWS global partition as a fallback, v2 doesn't) + if cfg.Region == "" { + imdsClient := imds.NewFromConfig(cfg) + region, err := imdsClient.GetRegion(ctx, &imds.GetRegionInput{}) + if err != nil { + return nil, fmt.Errorf("failed to get region from IMDS: %w", err) + } + cfg.Region = region.Region + } + return route53.NewFromConfig(cfg, clientOpts...), nil } func setup(c *caddy.Controller) error { @@ -43,7 +61,8 @@ func setup(c *caddy.Controller) error { // * Shared Credentials file // * Shared Configuration file (if AWS_SDK_LOAD_CONFIG is set to truthy value) // * EC2 Instance Metadata (credentials only) - opts := session.Options{} + cfgOpts := []func(*config.LoadOptions) error{} + clientOpts := []func(*route53.Options){} var fall fall.F refresh := time.Duration(1) * time.Minute // default update frequency to 1 minute @@ -74,11 +93,13 @@ func setup(c *caddy.Controller) error { if len(v) < 2 { return plugin.Error("route53", c.Errf("invalid access key: '%v'", v)) } - opts.Config.Credentials = credentials.NewStaticCredentials(v[0], v[1], "") + cfgOpts = append(cfgOpts, config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(v[0], v[1], ""))) log.Warningf("Save aws_access_key in Corefile has been deprecated, please use other authentication methods instead") case "aws_endpoint": if c.NextArg() { - opts.Config.Endpoint = aws.String(c.Val()) + clientOpts = append(clientOpts, func(o *route53.Options) { + o.BaseEndpoint = aws.String(c.Val()) + }) } else { return plugin.Error("route53", c.ArgErr()) } @@ -86,17 +107,18 @@ func setup(c *caddy.Controller) error { c.RemainingArgs() // eats args case "credentials": if c.NextArg() { - opts.Profile = c.Val() + cfgOpts = append(cfgOpts, config.WithSharedConfigProfile(c.Val())) } else { return c.ArgErr() } if c.NextArg() { - opts.SharedConfigFiles = []string{c.Val()} + sharedConfigFiles := []string{c.Val()} // If AWS_SDK_LOAD_CONFIG is set also load ~/.aws/config to stay consistent // with default SDK behavior. if ok, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG")); ok { - opts.SharedConfigFiles = append(opts.SharedConfigFiles, defaults.SharedConfigFilename()) + sharedConfigFiles = append(sharedConfigFiles, config.DefaultSharedConfigFilename()) } + cfgOpts = append(cfgOpts, config.WithSharedConfigFiles(sharedConfigFiles)) } case "fallthrough": fall.SetZonesFromArgs(c.RemainingArgs()) @@ -122,8 +144,12 @@ func setup(c *caddy.Controller) error { } } - client := f(opts) ctx, cancel := context.WithCancel(context.Background()) + client, err := f(ctx, cfgOpts, clientOpts) + if err != nil { + cancel() + return plugin.Error("route53", c.Errf("failed to create route53 client: %v", err)) + } h, err := New(ctx, client, keys, refresh) if err != nil { cancel() diff --git a/plugin/route53/setup_test.go b/plugin/route53/setup_test.go index 5d2792f5f3..c8bb3cc2f8 100644 --- a/plugin/route53/setup_test.go +++ b/plugin/route53/setup_test.go @@ -1,17 +1,18 @@ package route53 import ( + "context" "testing" "github.com/coredns/caddy" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/route53/route53iface" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/route53" ) func TestSetupRoute53(t *testing.T) { - f = func(opts session.Options) route53iface.Route53API { - return fakeRoute53{} + f = func(_ context.Context, _ []func(*config.LoadOptions) error, _ []func(*route53.Options)) (route53Client, error) { + return fakeRoute53{}, nil } tests := []struct { diff --git a/plugin/test/helpers.go b/plugin/test/helpers.go index f99790a236..a7094a7b6e 100644 --- a/plugin/test/helpers.go +++ b/plugin/test/helpers.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "sort" + "strings" "github.com/miekg/dns" ) @@ -206,11 +207,12 @@ func Section(tc Case, sec sect, rr []dns.RR) error { return fmt.Errorf("RR %d should have a Address of %q, but has %q", i, section[i].(*dns.AAAA).AAAA.String(), x.AAAA.String()) } case *dns.TXT: - for j, txt := range x.Txt { - if txt != section[i].(*dns.TXT).Txt[j] { - return fmt.Errorf("RR %d should have a Txt of %q, but has %q", i, section[i].(*dns.TXT).Txt[j], txt) - } + actualTxt := strings.Join(x.Txt, "") + expectedTxt := strings.Join(section[i].(*dns.TXT).Txt, "") + if actualTxt != expectedTxt { + return fmt.Errorf("RR %d should have a TXT value of %q, but has %q", i, expectedTxt, actualTxt) } + case *dns.HINFO: if x.Cpu != section[i].(*dns.HINFO).Cpu { return fmt.Errorf("RR %d should have a Cpu of %s, but has %s", i, section[i].(*dns.HINFO).Cpu, x.Cpu) diff --git a/plugin/test/responsewriter.go b/plugin/test/responsewriter.go index 32167008ab..7c6f100681 100644 --- a/plugin/test/responsewriter.go +++ b/plugin/test/responsewriter.go @@ -39,6 +39,9 @@ func (t *ResponseWriter) RemoteAddr() net.Addr { return &net.UDPAddr{IP: ip, Port: port, Zone: t.Zone} } +// Network implements dns.ResponseWriter interface. +func (t *ResponseWriter) Network() string { return "" } + // WriteMsg implements dns.ResponseWriter interface. func (t *ResponseWriter) WriteMsg(m *dns.Msg) error { return nil } diff --git a/plugin/test/testdata/txtrecordsplit.test b/plugin/test/testdata/txtrecordsplit.test new file mode 100644 index 0000000000..dd97fe0475 --- /dev/null +++ b/plugin/test/testdata/txtrecordsplit.test @@ -0,0 +1,15 @@ +; This record has two separate TXT records +example.org. 3600 IN TXT "record1" +example.org. 3600 IN TXT "record2" + +; This record has a single TXT record split into two chunks (>255 bytes total) +long.example.org. 3600 IN TXT "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + +-- QNAME example.org. QTYPE TXT +;; ANSWER +example.org. 3600 IN TXT "record1" +example.org. 3600 IN TXT "record2" + +-- QNAME long.example.org. QTYPE TXT +;; ANSWER +long.example.org. 3600 IN TXT "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" diff --git a/plugin/test/testdata_test.go b/plugin/test/testdata_test.go new file mode 100644 index 0000000000..a0e91b6f0d --- /dev/null +++ b/plugin/test/testdata_test.go @@ -0,0 +1,22 @@ +package test + +import ( + "os" + "testing" +) + +func RunTestFile(t *testing.T, filename string) { + t.Helper() + + f, err := os.Open(filename) + if err != nil { + t.Fatalf("failed to open test file: %v", err) + } + defer f.Close() + + t.Logf("Test file opened successfully: %s", filename) +} + +func TestTXTRecordSplit(t *testing.T) { + RunTestFile(t, "testdata/txtrecordsplit.test") +} diff --git a/plugin/trace/setup.go b/plugin/trace/setup.go index 8672dcc535..5721368fbe 100644 --- a/plugin/trace/setup.go +++ b/plugin/trace/setup.go @@ -25,6 +25,7 @@ func setup(c *caddy.Controller) error { }) c.OnStartup(t.OnStartup) + c.OnShutdown(t.OnShutdown) return nil } diff --git a/plugin/trace/trace.go b/plugin/trace/trace.go index f7409679d5..f3d0155b69 100644 --- a/plugin/trace/trace.go +++ b/plugin/trace/trace.go @@ -19,6 +19,8 @@ import ( _ "github.com/coredns/coredns/plugin/pkg/trace" // Plugin the trace package. "github.com/coredns/coredns/request" + "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" + "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" "github.com/miekg/dns" ot "github.com/opentracing/opentracing-go" otext "github.com/opentracing/opentracing-go/ext" @@ -26,10 +28,6 @@ import ( zipkinot "github.com/openzipkin-contrib/zipkin-go-opentracing" "github.com/openzipkin/zipkin-go" zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentracer" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" ) const ( @@ -70,7 +68,7 @@ type trace struct { Next plugin.Handler Endpoint string EndpointType string - tracer ot.Tracer + zipkinTracer ot.Tracer serviceEndpoint string serviceName string clientServer bool @@ -84,7 +82,7 @@ type trace struct { } func (t *trace) Tracer() ot.Tracer { - return t.tracer + return t.zipkinTracer } // OnStartup sets up the tracer @@ -95,15 +93,14 @@ func (t *trace) OnStartup() error { case "zipkin": err = t.setupZipkin() case "datadog": - tracer := opentracer.New( + tracer.Start( tracer.WithAgentAddr(t.Endpoint), tracer.WithDebugMode(clog.D.Value()), tracer.WithGlobalTag(ext.SpanTypeDNS, true), - tracer.WithServiceName(t.serviceName), + tracer.WithService(t.serviceName), tracer.WithAnalyticsRate(t.datadogAnalyticsRate), tracer.WithLogger(&loggerAdapter{log}), ) - t.tracer = tracer t.tagSet = tagByProvider["datadog"] default: err = fmt.Errorf("unknown endpoint type: %s", t.EndpointType) @@ -112,6 +109,14 @@ func (t *trace) OnStartup() error { return err } +// OnShutdown cleans up the tracer +func (t *trace) OnShutdown() error { + if t.EndpointType == "datadog" { + tracer.Stop() + } + return nil +} + func (t *trace) setupZipkin() error { var opts []zipkinhttp.ReporterOption opts = append(opts, zipkinhttp.Logger(stdlog.New(&loggerAdapter{log}, "", 0))) @@ -137,7 +142,7 @@ func (t *trace) setupZipkin() error { if err != nil { return err } - t.tracer = zipkinot.Wrap(tracer) + t.zipkinTracer = zipkinot.Wrap(tracer) t.tagSet = tagByProvider["default"] return err @@ -148,16 +153,42 @@ func (t *trace) Name() string { return "trace" } // ServeDNS implements the plugin.Handle interface. func (t *trace) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { - trace := false + shouldTrace := false if t.every > 0 { queryNr := atomic.AddUint64(&t.count, 1) - if queryNr%t.every == 0 { - trace = true + shouldTrace = true } } + + if t.EndpointType == "datadog" { + return t.serveDNSDatadog(ctx, w, r, shouldTrace) + } + return t.serveDNSZipkin(ctx, w, r, shouldTrace) +} + +func (t *trace) serveDNSDatadog(ctx context.Context, w dns.ResponseWriter, r *dns.Msg, shouldTrace bool) (int, error) { + if !shouldTrace { + return plugin.NextOrFailure(t.Name(), t.Next, ctx, w, r) + } + + span, spanCtx := tracer.StartSpanFromContext(ctx, defaultTopLevelSpanName) + defer span.Finish() + + metadata.SetValueFunc(ctx, metaTraceIdKey, func() string { return span.Context().TraceID() }) + + req := request.Request{W: w, Req: r} + rw := dnstest.NewRecorder(w) + status, err := plugin.NextOrFailure(t.Name(), t.Next, spanCtx, rw, r) + + t.setDatadogSpanTags(span, req, rw, status, err) + + return status, err +} + +func (t *trace) serveDNSZipkin(ctx context.Context, w dns.ResponseWriter, r *dns.Msg, shouldTrace bool) (int, error) { span := ot.SpanFromContext(ctx) - if !trace || span != nil { + if !shouldTrace || span != nil { return plugin.NextOrFailure(t.Name(), t.Next, ctx, w, r) } @@ -172,17 +203,39 @@ func (t *trace) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) span = t.Tracer().StartSpan(defaultTopLevelSpanName, otext.RPCServerOption(spanCtx)) defer span.Finish() - switch spanCtx := span.Context().(type) { - case zipkinot.SpanContext: + if spanCtx, ok := span.Context().(zipkinot.SpanContext); ok { metadata.SetValueFunc(ctx, metaTraceIdKey, func() string { return spanCtx.TraceID.String() }) - case ddtrace.SpanContext: - metadata.SetValueFunc(ctx, metaTraceIdKey, func() string { return fmt.Sprint(spanCtx.TraceID()) }) } rw := dnstest.NewRecorder(w) ctx = ot.ContextWithSpan(ctx, span) status, err := plugin.NextOrFailure(t.Name(), t.Next, ctx, rw, r) + t.setZipkinSpanTags(span, req, rw, status, err) + + return status, err +} + +// setDatadogSpanTags sets span tags using DataDog v2 API +func (t *trace) setDatadogSpanTags(span *tracer.Span, req request.Request, rw *dnstest.Recorder, status int, err error) { + span.SetTag(t.tagSet.Name, req.Name()) + span.SetTag(t.tagSet.Type, req.Type()) + span.SetTag(t.tagSet.Proto, req.Proto()) + span.SetTag(t.tagSet.Remote, req.IP()) + rc := rw.Rcode + if !plugin.ClientWrite(status) { + rc = status + } + span.SetTag(t.tagSet.Rcode, rcode.ToString(rc)) + if err != nil { + span.SetTag("error.message", err.Error()) + span.SetTag("error", true) + span.SetTag("error.type", "dns_error") + } +} + +// setZipkinSpanTags sets span tags for Zipkin/OpenTracing spans +func (t *trace) setZipkinSpanTags(span ot.Span, req request.Request, rw *dnstest.Recorder, status int, err error) { span.SetTag(t.tagSet.Name, req.Name()) span.SetTag(t.tagSet.Type, req.Type()) span.SetTag(t.tagSet.Proto, req.Proto()) @@ -196,9 +249,8 @@ func (t *trace) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) } span.SetTag(t.tagSet.Rcode, rcode.ToString(rc)) if err != nil { + // Use OpenTracing error handling otext.Error.Set(span, true) span.LogFields(otlog.Event("error"), otlog.Error(err)) } - - return status, err } diff --git a/plugin/trace/trace_test.go b/plugin/trace/trace_test.go index 28bdaf51c5..ce78bfdc1f 100644 --- a/plugin/trace/trace_test.go +++ b/plugin/trace/trace_test.go @@ -5,6 +5,7 @@ import ( "errors" "net/http" "net/http/httptest" + "strings" "testing" "github.com/coredns/caddy" @@ -15,9 +16,10 @@ import ( "github.com/coredns/coredns/plugin/test" "github.com/coredns/coredns/request" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/miekg/dns" "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/mocktracer" + openTracingMock "github.com/opentracing/opentracing-go/mocktracer" ) func TestStartup(t *testing.T) { @@ -83,7 +85,7 @@ func TestTrace(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { w := dnstest.NewRecorder(&test.ResponseWriter{}) - m := mocktracer.New() + m := openTracingMock.New() tr := &trace{ Next: test.HandlerFunc(func(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { if plugin.ClientWrite(tc.status) { @@ -93,9 +95,9 @@ func TestTrace(t *testing.T) { } return tc.status, tc.err }), - every: 1, - tracer: m, - tagSet: defaultTagSet, + every: 1, + zipkinTracer: m, + tagSet: defaultTagSet, } ctx := context.TODO() if _, err := tr.ServeDNS(ctx, w, tc.question); err != nil && tc.err == nil { @@ -138,7 +140,7 @@ func TestTrace(t *testing.T) { func TestTrace_DOH_TraceHeaderExtraction(t *testing.T) { w := dnstest.NewRecorder(&test.ResponseWriter{}) - m := mocktracer.New() + m := openTracingMock.New() tr := &trace{ Next: test.HandlerFunc(func(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { if plugin.ClientWrite(dns.RcodeSuccess) { @@ -148,8 +150,8 @@ func TestTrace_DOH_TraceHeaderExtraction(t *testing.T) { } return dns.RcodeSuccess, nil }), - every: 1, - tracer: m, + every: 1, + zipkinTracer: m, } q := new(dns.Msg).SetQuestion("example.net.", dns.TypeA) @@ -166,9 +168,163 @@ func TestTrace_DOH_TraceHeaderExtraction(t *testing.T) { fs := m.FinishedSpans() rootCoreDNSspan := fs[1] - rootCoreDNSTraceID := rootCoreDNSspan.Context().(mocktracer.MockSpanContext).TraceID - outsideSpanTraceID := outsideSpan.Context().(mocktracer.MockSpanContext).TraceID + rootCoreDNSTraceID := rootCoreDNSspan.Context().(openTracingMock.MockSpanContext).TraceID + outsideSpanTraceID := outsideSpan.Context().(openTracingMock.MockSpanContext).TraceID if rootCoreDNSTraceID != outsideSpanTraceID { t.Errorf("Unexpected traceID: rootSpan.TraceID: want %v, got %v", rootCoreDNSTraceID, outsideSpanTraceID) } } + +func TestStartup_Datadog(t *testing.T) { + m, err := traceParse(caddy.NewTestController("dns", `trace datadog localhost:8126`)) + if err != nil { + t.Errorf("Error parsing test input: %s", err) + return + } + if m.Name() != "trace" { + t.Errorf("Wrong name from GetName: %s", m.Name()) + } + + // Test that we can start and stop the DataDog tracer without errors + err = m.OnStartup() + if err != nil { + t.Errorf("Error starting DataDog tracing plugin: %s", err) + return + } + + if m.tagSet != tagByProvider["datadog"] { + t.Errorf("TagSet for DataDog hasn't been correctly initialized") + } + + // Test shutdown + err = m.OnShutdown() + if err != nil { + t.Errorf("Error shutting down DataDog tracing plugin: %s", err) + } +} + +func TestTrace_DataDog(t *testing.T) { + // Test the complete DataDog tracing flow using mocktracer + mt := mocktracer.Start() + defer mt.Stop() + + cases := []struct { + name string + rcode int + status int + question *dns.Msg + err error + }{ + { + name: "NXDOMAIN", + rcode: dns.RcodeNameError, + status: dns.RcodeSuccess, + question: new(dns.Msg).SetQuestion("example.org.", dns.TypeA), + }, + { + name: "NOERROR", + rcode: dns.RcodeSuccess, + status: dns.RcodeSuccess, + question: new(dns.Msg).SetQuestion("example.net.", dns.TypeCNAME), + }, + { + name: "SERVFAIL with error", + rcode: dns.RcodeServerFailure, + status: dns.RcodeSuccess, + question: new(dns.Msg).SetQuestion("example.net.", dns.TypeA), + err: errors.New("test error"), + }, + } + + datadogTagSet := tagByProvider["datadog"] + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + // Reset spans for each test + mt.Reset() + + w := dnstest.NewRecorder(&test.ResponseWriter{}) + tr := &trace{ + Next: test.HandlerFunc(func(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + if plugin.ClientWrite(tc.status) { + m := new(dns.Msg) + m.SetRcode(r, tc.rcode) + w.WriteMsg(m) + } + return tc.status, tc.err + }), + every: 1, + EndpointType: "datadog", + tagSet: datadogTagSet, + } + + ctx := context.TODO() + if _, err := tr.ServeDNS(ctx, w, tc.question); err != nil && tc.err == nil { + t.Fatalf("Error during tr.ServeDNS(ctx, w, %v): %v", tc.question, err) + } + + spans := mt.FinishedSpans() + if len(spans) == 0 { + t.Fatal("Expected at least one span, got none") + } + + // Find the DNS span + var dnsSpan *mocktracer.Span + for _, span := range spans { + if span.OperationName() == defaultTopLevelSpanName { + dnsSpan = span + break + } + } + + if dnsSpan == nil { + t.Fatal("Could not find DNS span with operation name 'servedns'") + } + + req := request.Request{W: w, Req: tc.question} + + // Test DataDog-specific tags + if dnsSpan.Tag(datadogTagSet.Name) != req.Name() { + t.Errorf("Unexpected span tag: span.Tag(%v): want %v, got %v", + datadogTagSet.Name, req.Name(), dnsSpan.Tag(datadogTagSet.Name)) + } + if dnsSpan.Tag(datadogTagSet.Type) != req.Type() { + t.Errorf("Unexpected span tag: span.Tag(%v): want %v, got %v", + datadogTagSet.Type, req.Type(), dnsSpan.Tag(datadogTagSet.Type)) + } + if dnsSpan.Tag(datadogTagSet.Proto) != req.Proto() { + t.Errorf("Unexpected span tag: span.Tag(%v): want %v, got %v", + datadogTagSet.Proto, req.Proto(), dnsSpan.Tag(datadogTagSet.Proto)) + } + if dnsSpan.Tag(datadogTagSet.Remote) != req.IP() { + t.Errorf("Unexpected span tag: span.Tag(%v): want %v, got %v", + datadogTagSet.Remote, req.IP(), dnsSpan.Tag(datadogTagSet.Remote)) + } + if dnsSpan.Tag(datadogTagSet.Rcode) != rcode.ToString(tc.rcode) { + t.Errorf("Unexpected span tag: span.Tag(%v): want %v, got %v", + datadogTagSet.Rcode, rcode.ToString(tc.rcode), dnsSpan.Tag(datadogTagSet.Rcode)) + } + + // Test DataDog v2 error handling + if tc.err != nil { + errorMsg := dnsSpan.Tag("error.message") + if errorMsg == nil { + t.Error("Expected error.message tag to be set") + } else if !strings.Contains(errorMsg.(string), "test error") { + t.Errorf("Expected error.message to contain 'test error', got %v", errorMsg) + } + + // Check error type tag + errorType := dnsSpan.Tag("error.type") + if errorType == nil { + t.Error("Expected error.type tag to be set") + } + } + + // Verify trace ID exists (mocktracer uses uint64) + traceID := dnsSpan.TraceID() + if traceID == 0 { + t.Error("Expected non-zero trace ID") + } + }) + } +} diff --git a/test/auto_test.go b/test/auto_test.go index a2aedeb2ca..ea98b1c91f 100644 --- a/test/auto_test.go +++ b/test/auto_test.go @@ -32,8 +32,8 @@ func TestAuto(t *testing.T) { if err != nil { t.Fatal("Expected to receive reply, but didn't") } - if resp.Rcode != dns.RcodeServerFailure { - t.Fatalf("Expected reply to be a SERVFAIL, got %d", resp.Rcode) + if resp.Rcode != dns.RcodeRefused { + t.Fatalf("Expected reply to be REFUSED, got %d", resp.Rcode) } // Write db.example.org to get example.org. @@ -59,8 +59,8 @@ func TestAuto(t *testing.T) { if err != nil { t.Fatal("Expected to receive reply, but didn't") } - if resp.Rcode != dns.RcodeServerFailure { - t.Fatalf("Expected reply to be a SERVFAIL, got %d", resp.Rcode) + if resp.Rcode != dns.RcodeRefused { + t.Fatalf("Expected reply to be REFUSED, got %d", resp.Rcode) } } @@ -93,8 +93,8 @@ func TestAutoNonExistentZone(t *testing.T) { if err != nil { t.Fatal("Expected to receive reply, but didn't") } - if resp.Rcode != dns.RcodeServerFailure { - t.Fatalf("Expected reply to be a SERVFAIL, got %d", resp.Rcode) + if resp.Rcode != dns.RcodeRefused { + t.Fatalf("Expected reply to be REFUSED, got %d", resp.Rcode) } } diff --git a/test/multisocket_test.go b/test/multisocket_test.go index 36da89a640..0ed7ace18a 100644 --- a/test/multisocket_test.go +++ b/test/multisocket_test.go @@ -4,12 +4,21 @@ import ( "fmt" "net" "testing" + "time" "github.com/miekg/dns" ) -// These tests need a fixed port, because :0 selects a random port for each socket, but we need all sockets to be on -// the same port. +// pickPort returns a free TCP port on 127.0.0.1 and closes the probe listener. +func pickPort(t *testing.T) int { + t.Helper() + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("probe listen failed: %v", err) + } + defer ln.Close() + return ln.Addr().(*net.TCPAddr).Port +} func TestMultisocket(t *testing.T) { tests := []struct { @@ -55,10 +64,11 @@ func TestMultisocket(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { s, err := CoreDNSServer(test.corefile) - defer s.Stop() if err != nil { t.Fatalf("Could not get CoreDNS serving instance: %s", err) } + defer s.Stop() + // check number of servers if len(s.Servers()) != test.expectedServers { t.Fatalf("Expected %d servers, got %d", test.expectedServers, len(s.Servers())) @@ -82,50 +92,68 @@ func TestMultisocket(t *testing.T) { } } +// NOTE: restart uses a different port to avoid transient EADDRINUSE / shutdown races +// when TCP/UDP from the previous instance haven’t fully torn down yet. func TestMultisocket_Restart(t *testing.T) { tests := []struct { name string numSocketsBefore int numSocketsAfter int }{ - { - name: "increase", - numSocketsBefore: 1, - numSocketsAfter: 2, - }, - { - name: "decrease", - numSocketsBefore: 2, - numSocketsAfter: 1, - }, - { - name: "no changes", - numSocketsBefore: 2, - numSocketsAfter: 2, - }, + {name: "increase", numSocketsBefore: 1, numSocketsAfter: 2}, + {name: "decrease", numSocketsBefore: 2, numSocketsAfter: 1}, + {name: "no changes", numSocketsBefore: 2, numSocketsAfter: 2}, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - corefile := `.:5058 { + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + port1 := pickPort(t) + port2 := pickPort(t) // restart onto a different free port + coreTmpl := `.:%d { multisocket %d }` - srv, err := CoreDNSServer(fmt.Sprintf(corefile, test.numSocketsBefore)) + + srv, err := CoreDNSServer(fmt.Sprintf(coreTmpl, port1, tc.numSocketsBefore)) if err != nil { - t.Fatalf("Could not get CoreDNS serving instance: %s", err) + t.Fatalf("Could not get CoreDNS serving instance: %v", err) } - if test.numSocketsBefore != len(srv.Servers()) { - t.Fatalf("Expected %d servers, got %d", test.numSocketsBefore, len(srv.Servers())) + if got := len(srv.Servers()); got != tc.numSocketsBefore { + t.Fatalf("Expected %d servers, got %d", tc.numSocketsBefore, got) } - newSrv, err := srv.Restart(NewInput(fmt.Sprintf(corefile, test.numSocketsAfter))) - if err != nil { - t.Fatalf("Could not get CoreDNS serving instance: %s", err) - } - if test.numSocketsAfter != len(newSrv.Servers()) { - t.Fatalf("Expected %d servers, got %d", test.numSocketsAfter, len(newSrv.Servers())) + resultCh := make(chan int, 1) + errCh := make(chan error, 1) + stopCh := make(chan struct{}) + + // Do the restart in a goroutine; return only the server count. + go func() { + newSrv, rerr := srv.Restart(NewInput(fmt.Sprintf(coreTmpl, port2, tc.numSocketsAfter))) + if rerr != nil { + errCh <- rerr + return + } + resultCh <- len(newSrv.Servers()) + <-stopCh + newSrv.Stop() + }() + + select { + case got := <-resultCh: + if got != tc.numSocketsAfter { + close(stopCh) // still stop the new instance + t.Fatalf("Expected %d servers, got %d", tc.numSocketsAfter, got) + } + close(stopCh) // now safe to stop the new instance + case rerr := <-errCh: + // Restart failed; stop the original instance. + srv.Stop() + t.Fatalf("Restart failed: %v", rerr) + case <-time.After(30 * time.Second): + // Timeout; stop the original instance. + srv.Stop() + t.Fatalf("Restart timed out after 30s (ports :%d→:%d, %d→%d sockets)", + port1, port2, tc.numSocketsBefore, tc.numSocketsAfter) } - newSrv.Stop() }) } } diff --git a/test/quic_test.go b/test/quic_test.go index 1bc06a24cb..e8d673d74d 100644 --- a/test/quic_test.go +++ b/test/quic_test.go @@ -153,7 +153,7 @@ func TestQUICStreamLimits(t *testing.T) { var mu sync.Mutex // Create a slice to store all the streams so we can keep them open - streams := make([]quic.Stream, 0, streamCount) + streams := make([]*quic.Stream, 0, streamCount) streamsMu := sync.Mutex{} // Attempt to open exactly the configured number of streams