Commit Graph

1646 Commits

Author SHA1 Message Date
Yong Tang
8f7b2a66ea plugin/cache: Fix timed stale caused refreshes (#8587) 2026-09-30 01:18:21 -07:00
Yong Tang
9fbbdd2698 plugin/tsig: reject non-final TSIG records (#8585)
This PR returns FORMERR before dispatching requests that contain a non-final TSIG.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-29 20:32:06 -07:00
Yong Tang
6ad382b53d plugin/etcd: Stop target stripping at the end of a name (#8584)
Stops stripping when the next-label operation reaches the end sentinel in DNS

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-29 20:11:44 -07:00
Yong Tang
23ba070a81 plugin/pkg/proxyproto: preserve the UDP peer for LOCAL (#8581)
This PR consumes LOCAL headers without replacing or caching the actual UDP peer address.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-29 01:19:37 -07:00
Yong Tang
d821a74af8 plugin/grpc: close clients on shutdown (#8582)
This PR closes from the plugin shutdown hook

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-29 01:19:28 -07:00
Yong Tang
594d6c9121 plugin/file: Fix race condition in file plugin closer (#8583)
This PR fixes race condition in file plugin closer

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-29 01:19:07 -07:00
llucas
0e9d7f4d05 plugin/forward ensure forward sets the DOH host (#8470)
* ensure forward sets the DOH host

Signed-off-by: ccie57654 <ccie57654@proton.me>

* added DoHHost value test

Signed-off-by: ccie57654 <ccie57654@proton.me>

---------

Signed-off-by: ccie57654 <ccie57654@proton.me>
2026-09-28 05:40:16 -07:00
jxj
72160e6e20 plugin/file: track zone mtime for reload_by_mtime (#8556)
* plugin/file: track zone mtime for reload_by_mtime

Signed-off-by: git-jxj <65210887+git-jxj@users.noreply.github.com>

* plugin/file: capture initial mtime before parsing

Signed-off-by: git-jxj <65210887+git-jxj@users.noreply.github.com>

* plugin/file: keep unloaded zones retryable after open error

Signed-off-by: git-jxj <65210887+git-jxj@users.noreply.github.com>

---------

Signed-off-by: git-jxj <65210887+git-jxj@users.noreply.github.com>
2026-09-28 00:22:39 -07:00
Arunesh Dwivedi
f781f97334 fix: return error from zipkin NewEndpoint in trace setup (#8577) 2026-09-27 16:35:03 -07:00
Amila Senadheera
95484f76ed rewrite/cname: point to config instead of copying (#8568)
Signed-off-by: Amila Senadheera <amilaruk1995@gmail.com>
2026-09-23 17:02:02 -07:00
Yong Tang
d5c1188843 plugin/rewrite: Limit rewrite cname recursion (#8570)
This PR limit rewrite cname recursion with the existing DNS server loop counter.
The issu was that rewrite cname can recurse indefinitely through internal lookups, causing crash at the end

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-22 06:23:20 -07:00
houyuwushang
5aa4dc2941 plugin/dynupdate: add durable authenticated RFC 2136 updates (#8520)
* plugin/dynupdate: add authenticated RFC 2136 updates

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* plugin/dynupdate: fix README test fixtures

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* test: format README fixture map

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* plugin/dynupdate: persist updates and bound writable zones

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* plugin/dynupdate: preserve middleware and fix interoperability fixtures

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* test(dynupdate): validate Kea lifecycle and bounded zone costs

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* plugin/dynupdate: reject duplicate directives and harden client fixtures

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* plugin/dynupdate: fix update routing and startup validation

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

---------

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-09-22 00:53:26 -07:00
Yong Tang
8d66643935 core: Reject conflicting TLS policies on shared listeners. (#8565)
* core: Reject conflicting TLS policies on shared listeners.

This PR tries to fix the issue when multiple zones share a DoT listener, CoreDNS can apply one sibling block’s tls.Config to all zones, allowing weaker TLS or client-auth settings to override a stricter zone.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Fix ACME

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

---------

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-21 23:56:27 -07:00
Yong Tang
5cb7cdc914 plugin/forward: Treat forward upstream hostnames as absolute FQDNs to avoid search-domain resolution. (#8563) 2026-09-19 21:37:34 -07:00
houyuwushang
ce5ee05bee plugin/forward: bound DoT connection setup for retries (#8543)
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-09-18 16:56:31 -07:00
Saleh
8f2d1cb7f4 plugin/cache: don't cache or panic on responses with no question (#8467)
An upstream may return a NOERROR message with an empty question section
(some plugins emit this during prefetch). response.Typify classifies it
as NoError, so key falls through to m.Question[0] and panics, taking
down the server. Skip caching such a malformed response and log a
warning instead.

Fixes #6051

Signed-off-by: Saleh <root@lr0.org>
2026-09-18 16:56:04 -07:00
Ilya Kulakov
25eb456b57 plugin/file: fix less is not up to RFC 1034 and 4034 (#8503)
* plugin/file: fix less to follow RFC 1034 and RFC 4034 matching and ordering requirements

- Ensure comparison is left-justified
- Ensure case folding applies only to A-Z
- Decode \DDD without allocations

Signed-off-by: Ilya Kulakov <kulakov.ilya@gmail.com>

* plugin/file: faster exit for less when a == b

Avoid two calls and two reslices.

Signed-off-by: Ilya Kulakov <kulakov.ilya@gmail.com>

* plugin/file: consolidate less tests

Signed-off-by: Ilya Kulakov <kulakov.ilya@gmail.com>

* plugin/file: exit less early when there are no more labels

Signed-off-by: Ilya Kulakov <kulakov.ilya@gmail.com>

* plugin/file: match dns.PackDomainName in handling \-escapes

Compare unterminated names as root-terminating

Signed-off-by: Ilya Kulakov <kulakov.ilya@gmail.com>

* plugin/file: More tests of less.

Signed-off-by: Ilya Kulakov <kulakov.ilya@gmail.com>

---------

Signed-off-by: Ilya Kulakov <kulakov.ilya@gmail.com>
2026-09-16 17:51:15 -07:00
houyuwushang
b93e449b2f Add opt-in JSON logging with structured DNS query fields (#8553)
* plugin/pkg/log: add opt-in JSON logging backend

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* plugin/log: emit typed query records in JSON mode

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

* coremain: expose process-wide JSON logging

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>

---------

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-09-16 17:50:39 -07:00
houyuwushang
84a93a0b89 plugin/file: reject SOA owners that do not match the zone (#8555)
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-09-16 17:49:58 -07:00
Baltasar Blanco
14ed42bd1f plugin/hosts: don't drop over-long fields silently (#8551)
#8496 fixed a silent truncation here and named the invariant in its own commit
message: entries were dropped and the hosts file simply looked shorter than it
is, with nothing in the log.

#8516 replaced that mechanism with a streaming parser bounded by maxFieldSize.
The error log #8496 added is still in parse(), but it can no longer report a
dropped entry: bufio.ErrBufferFull is consumed by the read loop, so only a real
I/O error reaches it. A field over maxFieldSize is discarded in lineParser with
no log at all, and when that field is the address the whole line goes with it.

Report both cases, once per dropped field, with the line number and the source
the entries came from.

Signed-off-by: Baltasar Blanco <baltasarblanco.dev@gmail.com>
2026-09-15 19:24:23 -07:00
Sakıp Han Dursun
8de7a8b89d fix(kubernetes): include structured key/value context in client-go logs (#8490) 2026-09-15 00:42:44 -07:00
Saleh
b0b317fdd6 plugin/dnstap: tap deferred error responses (#8549)
When the plugin chain returns an error rcode without writing a response
(it falls off the end, or returns SERVFAIL/REFUSED/FORMERR/NOTIMP), the
server generates and sends the error to the client after dnstap's ServeDNS
returns, so ResponseWriter.WriteMsg is never called and no CLIENT_RESPONSE
dnstap message is emitted. dnstap consumers then see a CLIENT_QUERY with no
matching CLIENT_RESPONSE.

Synthesize the deferred response and tap it as a CLIENT_RESPONSE, mirroring
the deferred-response handling already added to plugin/log.

Fixes #6532

Signed-off-by: Saleh <root@lr0.org>
2026-09-14 17:25:11 -07:00
Paco Cartones
22351a0d3c fix(metrics): release listener on TLS startup failure (#8527) 2026-09-13 17:57:30 -07:00
Ilya Kulakov
5bd1701376 plugin/tls: document that dig supports DoT (#8539) 2026-09-13 17:56:16 -07:00
Yong Tang
19adcd8b96 Fix etcd library update issue (#8542)
This PR fixes etcd library update issue in 8492 where additional lint fix
is needed to take the latest etcd dependency.

This PR supersede 8492.

This PR closes 8492.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-10 23:59:33 -07:00
houyuwushang
b51e6d254b plugin/azure: allow startup with unavailable zones (#8524)
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-09-10 20:54:12 -07:00
Yong Tang
4382b80a35 core: upgrade Go requirement to 1.26.0 (#8466)
* core: upgrade Go requirement to 1.26.0

As golang 1.27 has been released, this PR
- Bump Go version requirement to 1.26.0
- Update Go build version to 1.27.0

This is also for solving the issue encountered in 8092 of k8s update

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Bump golang ci

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Fix

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Fix

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Fix

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Migrate faillint to forbidigo, as failint has not bee updated for more than a year

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

---------

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-10 19:34:44 -07:00
Paco Cartones
5ac0ca4fad fix(ready): release lock before server shutdown (#8526)
Signed-off-by: Paco Cartones <pacocartones@users.noreply.github.com>
Co-authored-by: Paco Cartones <pacocartones@users.noreply.github.com>
2026-09-08 13:15:00 -07:00
Baltasar Blanco
dea2f90f24 plugin/file: return SERVFAIL on self-referential CNAME loops (#8475)
A CNAME whose target is its own owner name is chased by externalLookup
until the depth cap, appending the same record on every pass. The reply
was NOERROR with the CNAME repeated ten times.

Self-referential DNAME already returns SERVFAIL, as do wildcard CNAME
loops. Return SERVFAIL here too. The check runs on the CNAME chase path
only, so normal responses are unaffected.

Fixes #6421

Signed-off-by: baltasarblanco <baltablanco9008@gmail.com>
2026-09-08 12:21:54 -07:00
houyuwushang
e1d3fe6bc6 plugin/forward: support DNS-over-QUIC upstreams (#8474)
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-09-07 21:51:18 -07:00
Baltasar Blanco
71a60e140b plugin/loadbalance: validate the response before dereferencing it in WriteMsg (#8523) 2026-09-07 20:50:54 -07:00
sam lockart
9fb1859b23 fix(reload): broadcast shutdown signal (#8504)
* fix(reload): broadcast shutdown signal

Signed-off-by: alam0rt <sam@samlockart.com>

* fix(reload): scope shutdown state to instances

Signed-off-by: alam0rt <sam@samlockart.com>

---------

Signed-off-by: alam0rt <sam@samlockart.com>
2026-09-06 19:40:07 -07:00
myohannes
2b8c305203 plugin/https: Add max_streams to limit HTTP/2 concurrent streams (#8522)
Add a max_streams option to the *https* plugin to limit the number of
concurrent HTTP/2 streams per DoH connection. This lets operators cap
per-connection concurrency (guarding against resource exhaustion) or
raise it above the Go default for high-fan-in clients that multiplex
many requests over a single connection.

Semantics match the existing *https3* plugin's max_streams:
- omitted  -> Go HTTP/2 server default is used
- 0        -> use the underlying HTTP/2 transport default
- positive -> advertise exactly that many concurrent streams
- negative -> rejected at config parse time

The limit is applied via the standard library http.Server.HTTP2
(HTTP2Config.MaxConcurrentStreams) so it is advertised in the server's
SETTINGS frame.

Signed-off-by: Mekias Yohannes <mmyohannes@gmail.com>
2026-09-06 19:16:44 -07:00
Paco Cartones
558c9757a9 plugin/hosts: parse hosts files with bufio.Reader (#8516) 2026-09-05 17:39:42 -07:00
Zhao Jianing
b564fcd869 plugin/autopath: Fixes a nil pointer dereference panic in autopath during search path walk (#8517)
* plugin/autopath: Fixes a nil pointer dereference panic in autopath during search path walk

When a plugin later in the chain returns a ClientWrite rcode without
writing a response (for example acl's drop action, which returns
(dns.RcodeSuccess, nil) without calling WriteMsg), autopath dereferences
a nil nw.Msg at nw.Msg.Rcode and panics. The final fallback
w.WriteMsg(firstReply) can also receive a nil firstReply for the same
reason.

Skip search path elements that produced no message, and only write the
first reply when it is non-nil. This mirrors the nil guards recently
added in plugin/minimal (#8506), plugin/dns64 (#8511) and plugin/cache
(#8512).

Signed-off-by: zjncs <18910855655@163.com>

* plugin/autopath: silence unused-parameter lint and assert no client write

Address review feedback on #8517: rename the unused 'w' parameter in
TestAutoPathNilMsgFromNext to '_w' so the revive unused-parameter check
passes, and assert that the recorder receives no message so the intended
drop/no-client-write behavior is explicit.

Signed-off-by: zjncs <18910855655@163.com>

---------

Signed-off-by: zjncs <18910855655@163.com>
2026-09-05 02:20:27 -07:00
houyuwushang
b6987aeb4a request: stop echoing unhandled EDNS options (#8514)
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-09-04 18:14:53 -07:00
houyuwushang
895eab37e8 plugin/kubernetes: isolate NS address test fixtures (#8513)
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-09-04 18:14:27 -07:00
Zhao Jianing
99b203f6bb plugin/k8s_external: Fixes a nil pointer dereference panic when upstream lookup returns no response (#8518)
* plugin/k8s_external: Fixes a nil pointer dereference panic when upstream lookup returns no response

When a CNAME-hosted service is resolved, k8s_external performs internal
upstream lookups for the target name. Upstream.Lookup can return a nil
message with a nil error when the internal self-query's plugin chain
returns a ClientWrite rcode without writing a response (for example
acl's drop action), and the a/aaaa/srv handlers then dereference
resp.Answer on a nil resp and panic.

Guard all four lookups with err == nil && resp != nil, matching the nil
checks already used in plugin/backend_lookup.go and the guard recently
added to plugin/dns64 (#8511).

Signed-off-by: zjncs <18910855655@163.com>

* plugin/k8s_external: silence unused-parameter lint in nil upstream test

The CI lint flagged the test handler's unused 'w' parameter. Rename it
to '_' so golangci-lint (revive unused-parameter) passes. No behavior
change.

Signed-off-by: zjncs <18910855655@163.com>

---------

Signed-off-by: zjncs <18910855655@163.com>
2026-09-04 18:03:47 -07:00
Zhao Jianing
fe9dffcd13 plugin/rewrite: Fixes a nil pointer dereference panic in ResponseReverter.WriteMsg (#8519)
ResponseReverter.WriteMsg calls res1.Copy() without checking res1 for
nil, so any plugin further down the chain that writes a nil response
(for example a handler returning (dns.RcodeSuccess, nil) after
w.WriteMsg(nil)) panics here.

Return an error instead, mirroring the nil guard recently added to
plugin/cache's ResponseWriter.WriteMsg (#8512).

Signed-off-by: zjncs <18910855655@163.com>
2026-09-04 18:02:52 -07:00
Yong Tang
c2e309e2e4 plugin/cache: Prevents a nil pointer dereference panic in the cache prefetch (#8512)
* plugin/cache: Prevents a nil pointer dereference panic in the cache prefetch

This PR prevents a nil pointer dereference panic in the cache prefetch, by
adding nil guards

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Address comment

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

---------

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-03 01:11:33 -07:00
Ilya Kulakov
c942ca7c36 plugin: use Zones.Contains when any match suffices (#8505) 2026-09-02 23:59:58 -07:00
Yong Tang
f1d835aa51 plugin/dns64: Fixes a nil pointer dereference panic in dns64 during response (#8511)
This PR fixes a nil pointer dereference panic in dns64 during response,
when the internal A-record upstream re-lookup returns a nil response.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-02 21:07:28 -07:00
Yong Tang
88ab058ba2 plugin/minimal: Fixes a nil pointer dereference panic in minimal prefetch response processing (#8506)
* plugin/minimal: Fixes a nil pointer dereference panic in minimal prefetch response processing

This PR fixes a nil pointer dereference panic in minimal prefetch response processing

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Fix lint

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

---------

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2026-09-02 07:58:49 -07:00
Paco Cartones
85aa27cd9c plugin/hosts: don't drop entries after an over-long line (#8496)
bufio.Scanner stops at the first line longer than its 64KiB default
buffer and reports bufio.ErrTooLong from Err(). parse() never checked
Err(), so that line and every entry after it were dropped silently: the
hosts file simply looked shorter than it is, with nothing in the log.

Raise the scanner's limit to 1MiB (the scanner still grows its buffer
lazily, so nothing is preallocated up front) and log an error if the
scan does stop early, so the truncation is at least visible.

Signed-off-by: Paco Cartones <pacocartones@users.noreply.github.com>
Co-authored-by: Paco Cartones <pacocartones@users.noreply.github.com>
2026-09-01 00:01:04 -07:00
houyuwushang
789b8d1665 plugin/tsig: expose validated TSIG key identity (#8471)
Store the normalized key name in the request context only after successful TSIG verification. This lets downstream plugins distinguish unsigned requests from authenticated requests and authorize by key without relying on the stripped TSIG RR or exposing secret material.

Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-08-26 14:13:48 -07:00
houyuwushang
b8720090b5 plugin/etcd: allow disabling legacy apex fallback (#8468)
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-08-23 17:56:12 -07:00
Michée lengronne
3b9f85bb71 feat(siit): Initial version (#8188)
* feat(siit): Initial version

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* cleaner readme

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* linting and generating

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* improving README and removing a useless case

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* improvements

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* improvements

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* linting

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* New fixes

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* improvements

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

* improvements

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>

---------

Signed-off-by: Michée Lengronne <michee.lengronne@coppint.com>
2026-08-23 17:55:27 -07:00
Baltasar Blanco
234f5fd378 plugin/cache: stop setting AA on answers served from cache (#8419)
* plugin/cache: stop setting AA on answers served from cache

toMsg hardcoded m1.Authoritative = true, so a reply rebuilt from a cache entry claimed authority the answer that populated it never had.

The hardcoding was a workaround for legacy stub resolvers that dropped non-authoritative answers, but it only ever ran on the cache hit path: the same query still returned AA=0 on every miss and after every TTL expiry, so those clients were never actually protected.

Signed-off-by: baltasarblanco <baltablanco9008@gmail.com>

* plugin/cache: pin the AA=1 side of the cache round trip

Signed-off-by: baltasarblanco <baltablanco9008@gmail.com>

* plugin/cache: assert AA=0 on verified stale refresh and prove the cache hit

Signed-off-by: baltasarblanco <baltablanco9008@gmail.com>

* plugin/cache: count backend calls in TestCachePreservesAA

Signed-off-by: baltasarblanco <baltablanco9008@gmail.com>

---------

Signed-off-by: baltasarblanco <baltablanco9008@gmail.com>
2026-08-23 17:54:41 -07:00
houyuwushang
4b26cced32 plugin/etcd: avoid apex fallback on backend errors (#8465)
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
2026-08-20 02:24:12 -07:00
Manuel Rüger
992d4c20db plugin/loadbalance: reduce roundRobin allocations for homogeneous address sets (#8375)
* perf(loadbalance): fast-path zero-allocation roundRobin for homogeneous record sets

Signed-off-by: Manuel Rüger <manuel@rueg.eu>

* plugin/loadbalance: copy before shuffling in the fast path

The fast path shuffled the caller's slice in place, which is not safe.
roundRobin must not modify its input: a backend may hand back a slice it
owns rather than one built for the response. plugin/file does exactly that
- Lookup returns elem.Type(qtype), which is the zone tree's own []dns.RR -
so an in-place shuffle reorders the zone itself, visible to every other
query and racing with the ones running concurrently.

Copy the records into a fresh slice and shuffle that instead. This is still
a single allocation rather than the four slices the partitioning path builds,
so most of the gain is kept:

    name          old time/op    new time/op    delta
    RoundRobin      353 ns         244 ns       -31%

    name          old alloc/op   new alloc/op   delta
    RoundRobin      118 B           54 B        -54%

    name          old allocs/op  new allocs/op  delta
    RoundRobin        5              4          -20%

Also reorder the type check so a response led by a CNAME is rejected on the
first record instead of scanning the whole answer section first.

TestRoundRobinDoesNotMutateInput pins the contract; it fails against the
in-place version.

Signed-off-by: Manuel Rüger <manuel@rueg.eu>

---------

Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2026-08-19 20:27:35 -07:00