DNSTap logging library for Elixir - capture and export DNS query/response data using the DNSTap protocol and Frame Streams format.
- π¦ Frame Streams Protocol - Full implementation of uni-directional and bi-directional Frame Streams
- π Multiple Output Types - File, Unix socket, and TCP output support
- β‘ High Performance - Built on GenStage with backpressure control
- π Automatic Reconnection - Exponential backoff for TCP/Unix socket connections
- π― Protocol Buffers - Efficient DNSTap message encoding
- π Production Ready - Comprehensive test coverage and error handling
Add elixir_dnstap to your list of dependencies in mix.exs:
def deps do
[
{:elixir_dnstap, "~> 0.1.0"}
]
endConfigure DNSTap output in your config/config.exs:
config :elixir_dnstap,
enabled: true,
output: [
type: :file,
path: "log/dnstap.fstrm"
]config :elixir_dnstap,
enabled: true,
output: [
type: :tcp,
host: "127.0.0.1",
port: 6000,
timeout: 5000,
bidirectional: true,
reconnect: true,
reconnect_interval: 1000,
max_reconnect_interval: 60_000,
max_reconnect_attempts: :infinity
]config :elixir_dnstap,
enabled: true,
output: [
type: :unix_socket,
path: "/tmp/dnstap.sock"
]Add ElixirDnstap.Supervisor to your application's supervision tree:
defmodule MyApp.Application do
use Application
def start(_type, _args) do
children = [
# ... other children
ElixirDnstap.Supervisor
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end# Log a DNS client query
ElixirDnstap.log_client_query(
query_packet,
socket_family: :inet,
socket_protocol: :udp,
query_address: {127, 0, 0, 1},
query_port: 12345,
response_address: {8, 8, 8, 8},
response_port: 53
)
# Log a DNS client response
ElixirDnstap.log_client_response(
response_packet,
socket_family: :inet,
socket_protocol: :udp,
query_address: {127, 0, 0, 1},
query_port: 12345,
response_address: {8, 8, 8, 8},
response_port: 53
)ElixirDnstap uses a GenStage pipeline for efficient message processing:
DNS Messages β Producer β BufferStage β WriterConsumer β Writer (File/TCP/Unix Socket)
β β β
Backpressure Encoding Frame Streams
- Producer - Receives DNS messages and manages backpressure
- BufferStage - Encodes messages to Protocol Buffers and Frame Streams
- WriterConsumer - Consumes encoded frames and writes to output
- Writers - Handle specific output types (File, TCP, Unix Socket)
ElixirDnstap implements the Frame Streams protocol:
START β DATA* β STOP
Receiver: READY
Sender: ACCEPT β START β DATA* β FINISH
# Get dependencies
mix deps.get
# Install lefthook git hooks
lefthook installThis project uses Lefthook for git hooks. On commit, the following checks are automatically run:
mix format- Auto-format codemix test --cover- Run tests with coveragemix credo --strict- Check code quality
To skip hooks temporarily:
LEFTHOOK=0 git commit -m "message"# Run tests
mix test
# Run tests with coverage
mix test --cover
# Check code quality
mix credo --strict
# Type checking
mix dialyzer
# Generate documentation
mix docsUse the dnstap command-line tool to read DNSTap files:
# Read Frame Streams file
dnstap -r log/dnstap.fstrm
# Listen on TCP socket
dnstap -l 127.0.0.1:6000 -w output.fstrmElixirDnstap is designed for high-throughput DNS logging:
- Backpressure control prevents memory overflow
- Batch processing of frames
- Asynchronous I/O operations
- Automatic reconnection with exponential backoff
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
This library implements the DNSTap protocol specification and Frame Streams format for capturing DNS traffic data