mirror of
https://github.com/coturn/coturn.git
synced 2026-10-24 00:08:57 +03:00
TURN/STUN long-term auth answers the first unauthenticated request with
a 401 Unauthorized carrying REALM/NONCE. On UDP, where source addresses
are spoofable and the 401 is larger than the request that triggers it,
the server becomes a reflection/amplification vector: an attacker forges
a victim's source IP and bounces amplified 401s at it.
This adds an opt-in mitigation that caps how many UDP 401 responses the
server emits toward any single source IP per second. Past the cap the
server stays silent, denying both the reflection and the amplification.
Authenticated relay traffic is untouched — only requests that reach the
401 branch spend budget.
Flags (off by default):
--unauthorized-ratelimit Enable the mitigation (UDP only).
--unauthorized-ratelimit-rps=<n> Max 401 responses per source IP per
second. Default 10.
Implementation:
- Lock-free, fixed 4096-bucket direct-mapped table (~80 KiB, no
malloc/free, no lock, no list scan on the hot path); the source IP
appears only as a 32-bit tag, never as a pointer. The port is stripped
from the key so an attacker cannot evade the limit by rotating the
source port. A fixed 1-second window backs the per-second limit.
- Colliding addresses share the live bucket budget instead of receiving
a fresh allowance, so hash collisions can never expand reflected output.
- Drop and collision diagnostics are each latched to one log line per
(bucket, window) to avoid log amplification.
- Portable 32-bit atomics over C11 <stdatomic.h> with an MSVC
Interlocked* fallback; the on/off flag and the per-second threshold are
pointers into turn_params so every relay thread sees live CLI values
without per-thread copies.
Observability (Prometheus):
- turn_unauthenticated_401_{requests,responses,dropped_responses}
- turn_ratelimit_{hash_collisions,occupied_buckets,total_buckets}
Tests & docs:
- Unity unit test (tests/test_ratelimit.c) covering live-bucket
collisions, occupancy tracking, and the collision counter.
- End-to-end positive/negative system test (run_tests_ratelimit_401.sh)
and a Prometheus counter test (run_tests_prom.sh).
- A 401-response-flood load harness under examples/loadtest/.
- docs/401-ratelimit.md design note, plus man page, README, Prometheus
docs, and the example/Docker turnserver.conf entries.
122 lines
4.3 KiB
Markdown
122 lines
4.3 KiB
Markdown
# Prometheus setup
|
|
|
|
coturn exposes a Prometheus metrics endpoint (default `:9641/metrics`) when
|
|
started with `--prometheus`.
|
|
|
|
## Vendored Prometheus client
|
|
|
|
coturn ships a minimal, self-contained Prometheus client under
|
|
[`src/prometheus`](../src/prometheus) and builds it straight from those
|
|
sources.
|
|
|
|
The vendored client implements the slice of the API coturn uses —
|
|
counters, gauges, a single default registry, and the text-exposition
|
|
serializer. Histograms, summaries, custom registries and a bundled HTTP
|
|
handler are out of scope; coturn serves the endpoint with its own
|
|
libmicrohttpd handler in
|
|
[`src/apps/relay/prom_server.c`](../src/apps/relay/prom_server.c).
|
|
|
|
The exporter's only external dependency is **libmicrohttpd**.
|
|
|
|
## Install libmicrohttpd
|
|
|
|
### Ubuntu / Debian
|
|
|
|
```
|
|
sudo apt install libmicrohttpd-dev
|
|
```
|
|
|
|
### macOS (Homebrew)
|
|
|
|
```
|
|
brew install libmicrohttpd
|
|
```
|
|
|
|
### From source
|
|
|
|
[libmicrohttpd](https://www.gnu.org/software/libmicrohttpd/) — download from
|
|
https://git.gnunet.org/libmicrohttpd.git
|
|
|
|
```
|
|
git clone https://git.gnunet.org/libmicrohttpd.git
|
|
cd libmicrohttpd
|
|
./autogen.sh
|
|
./configure --prefix=`pwd`/install --disable-doc --disable-examples \
|
|
--disable-tools
|
|
make install
|
|
```
|
|
|
|
## Build
|
|
|
|
The exporter is always compiled in; libmicrohttpd is a required build
|
|
dependency (provided by vcpkg on Windows). The runtime `--prometheus` flag
|
|
controls whether it is started. To point CMake at a non-standard libmicrohttpd
|
|
install prefix, set `MicroHTTPD_ROOT`:
|
|
|
|
```
|
|
cmake -S . -B build -DMicroHTTPD_ROOT=/path/to/libmicrohttpd/install
|
|
cmake --build build
|
|
```
|
|
|
|
The exporter is always compiled in (libmicrohttpd is a required build
|
|
dependency); the runtime `--prometheus` flag controls whether it is started.
|
|
|
|
## HTTPS (optional)
|
|
|
|
By default the metrics endpoint is served over plain HTTP. To serve it over
|
|
HTTPS instead, pass `--prometheus-tls` (requires libmicrohttpd built with TLS
|
|
support). `--prometheus-tls` implies `--prometheus`, so it enables the exporter
|
|
on its own — there is no need to pass both. The certificate and key default to
|
|
the server's own `--cert` / `--pkey`; override them with `--prometheus-cert` /
|
|
`--prometheus-key`:
|
|
|
|
```
|
|
# Reuse the server's TLS material:
|
|
turnserver --prometheus-tls --cert server.pem --pkey server.key
|
|
|
|
# Or use a dedicated certificate for the metrics endpoint:
|
|
turnserver --prometheus-tls \
|
|
--prometheus-cert metrics.pem --prometheus-key metrics.key
|
|
```
|
|
|
|
Then scrape with `https://<host>:9641/metrics`. If `--prometheus-tls` is set
|
|
but no certificate/key can be loaded, the exporter logs an error and does not
|
|
start.
|
|
|
|
## UDP 401 mitigation metrics
|
|
|
|
When the optional UDP 401 response rate limit is enabled, use:
|
|
|
|
```
|
|
unauthorized-ratelimit
|
|
unauthorized-ratelimit-rps=10
|
|
prometheus
|
|
```
|
|
|
|
The rate limit is disabled by default. It applies only to UDP `401 Unauthorized`
|
|
responses, which can otherwise be used in spoofed-source reflection attacks.
|
|
|
|
When Prometheus is enabled, the exporter provides the following counters for
|
|
this path whether or not mitigation is enabled. The dropped response counter
|
|
increments only when `unauthorized-ratelimit` suppresses responses.
|
|
|
|
| Metric | Type | Meaning |
|
|
|---|---|---|
|
|
| `turn_unauthenticated_401_requests` | counter | UDP requests requiring a `401 Unauthorized` response. |
|
|
| `turn_unauthenticated_401_responses` | counter | UDP `401 Unauthorized` responses emitted. |
|
|
| `turn_unauthenticated_401_dropped_responses` | counter | UDP `401` responses suppressed by the rate limit. |
|
|
|
|
The rate-limit hash table is also instrumented. These values are computed
|
|
lazily when Prometheus scrapes `/metrics`, so they add no cost to the hot path:
|
|
|
|
| Metric | Type | Meaning |
|
|
|---|---|---|
|
|
| `turn_ratelimit_hash_collisions` | counter | Requests whose source hashed to a bucket already owned by a different live address (distinct sources sharing a budget — the mitigation's false-positive surface). |
|
|
| `turn_ratelimit_occupied_buckets` | gauge | Buckets currently holding a live (non-expired) window. |
|
|
| `turn_ratelimit_total_buckets` | gauge | Table capacity in buckets. |
|
|
|
|
`turn_ratelimit_occupied_buckets / turn_ratelimit_total_buckets` is the table
|
|
load factor; a sustained high ratio or a climbing `turn_ratelimit_hash_collisions`
|
|
rate means distinct attackers are colliding into shared buckets. See
|
|
[docs/401-ratelimit.md](401-ratelimit.md) for the full design.
|