# DNS
[](https://github.com/gsmlg-dev/ex_dns/actions/workflows/release.yml)
[](https://hex.pm/packages/ex_dns)
[](https://hexdocs.pm/ex_dns)
A pure Elixir DNS library that provides comprehensive DNS protocol message parsing, zone management, and resource record handling according to DNS RFC standards.
## Features
- **Complete DNS Protocol Implementation**: Full DNS message parsing and serialization
- **20+ Resource Record Types**: Support for A, AAAA, CNAME, MX, TXT, DNSSEC records, and more
- **Zone Management**: Authoritative, stub, forward, and cache zone support
- **DNSSEC Support**: Basic DNSSEC signing and validation capabilities
- **Binary Protocol Handling**: Efficient binary parsing with domain name compression
- **Type Safety**: Comprehensive type specifications throughout the codebase
- **Protocol-Based Architecture**: Consistent behavior via `DNS.Parameter` and `String.Chars` protocols
## Installation
Add `ex_dns` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:ex_dns, "~> 0.4.0"}
]
end
```
## Quick Start
### DNS Message Parsing
```elixir
# Parse a DNS message from binary data
message = DNS.Message.from_iodata(binary_data)
# Create a new DNS query
message = DNS.Message.new()
|> DNS.Message.add_question(%DNS.Message.Question{
name: DNS.Message.Domain.new("example.com"),
type: DNS.ResourceRecordType.new(:a),
class: DNS.Class.new(:in)
})
# Convert to binary for network transmission
binary_data = DNS.Parameter.to_iodata(message)
# Display as human-readable string
IO.puts(to_string(message))
```
### Zone Management
```elixir
# Create a new authoritative zone
zone = DNS.Zone.new("example.com", :authoritative)
# Add records interactively
{:ok, zone} = DNS.Zone.Editor.create_zone_interactive("example.com",
type: :authoritative,
soa: [
mname: "ns1.example.com",
rname: "admin.example.com",
serial: 2024010101,
refresh: 3600,
retry: 1800,
expire: 604800,
minimum: 300
],
ns: ["ns1.example.com", "ns2.example.com"],
a: [{"@", "192.168.1.10"}, {"www", "192.168.1.10"}]
)
# Export zone to BIND format
{:ok, zone_file} = DNS.Zone.Editor.export_zone("example.com", format: :bind)
```
## Architecture
### Core Components
#### DNS.Message Protocol System
The library uses a protocol-based architecture where all DNS entities implement:
- **`DNS.Parameter`**: Binary serialization/deserialization for network transmission
- **`String.Chars`**: Human-readable string representations
#### DNS.Message Hierarchy
```
DNS.Message
├── DNS.Message.Header # Message header (ID, flags, counts)
├── DNS.Message.Question # Query section (QNAME, QTYPE, QCLASS)
├── DNS.Message.Record # Resource records (name, type, class, TTL, data)
└── DNS.Message.Record.Data/* # 20+ specific record type implementations
├── A, AAAA, CNAME, MX, TXT
├── DNSSEC records (DNSKEY, RRSIG, DS, NSEC, NSEC3)
└── Modern records (HTTPS, SVCB, TLSA, CAA)
```
#### DNS.Zone Management
```
DNS.Zone
├── DNS.Zone.Manager # CRUD operations and lifecycle management
├── DNS.Zone.Store # ETS-based persistent storage
├── DNS.Zone.Cache # TTL-based caching with expiration
├── DNS.Zone.Loader # Zone file loading from various sources
├── DNS.Zone.FileParser # BIND format zone file parsing
├── DNS.Zone.Validator # Zone validation and diagnostics
└── DNS.Zone.DNSSEC # DNSSEC signing and validation
```
### Supported Record Types
The library supports over 20 DNS record types including:
- **Basic Records**: A, AAAA, CNAME, MX, NS, PTR, TXT, SOA
- **Service Records**: SRV, SSHFP, TLSA
- **DNSSEC Records**: DNSKEY, RRSIG, DS, NSEC, NSEC3, NSEC3PARAM
- **Modern Records**: HTTPS, SVCB, CAA
- **Experimental/Deprecated**: Various historical and experimental types
## Usage Examples
### Working with DNS Messages
```elixir
# Create a DNS query for an A record
query = DNS.Message.new()
|> DNS.Message.add_question(%DNS.Message.Question{
name: DNS.Message.Domain.new("example.com"),
type: DNS.ResourceRecordType.new(:a),
class: DNS.Class.new(:in)
})
# Parse response
response = DNS.Message.from_iodata(response_binary)
# Extract answer records
answers = response.anlist
# => [%DNS.Message.Record{name: "example.com", type: :a, data: %{ip: {93, 184, 216, 34}}}]
```
### Zone File Operations
```elixir
# Load zone from BIND format file
{:ok, zone} = DNS.Zone.Loader.load_zone_from_file("example.com", "example.com.zone")
# Parse zone from string
zone_content = """
$TTL 3600
$ORIGIN example.com.
@ IN SOA ns1.example.com. admin.example.com. (
2024010101 ; serial
3600 ; refresh
1800 ; retry
604800 ; expire
300 ; minimum
)
@ IN NS ns1.example.com.
www IN A 192.168.1.100
"""
{:ok, zone} = DNS.Zone.Loader.load_zone_from_string(zone_content)
```
### Record Management
```elixir
# Add various record types
{:ok, zone} = DNS.Zone.Editor.add_record("example.com", :a,
name: "www.example.com",
ip: {192, 168, 1, 100},
ttl: 300
)
{:ok, zone} = DNS.Zone.Editor.add_record("example.com", :mx,
name: "example.com",
preference: 10,
exchange: "mail.example.com"
)
{:ok, zone} = DNS.Zone.Editor.add_record("example.com", :txt,
name: "example.com",
text: "v=spf1 mx ~all"
)
# Search records
{:ok, a_records} = DNS.Zone.Editor.search_records("example.com", type: :a)
{:ok, www_records} = DNS.Zone.Editor.search_records("example.com", name: "www.example.com")
```
### DNSSEC Operations
```elixir
# Enable DNSSEC for a zone
case DNS.Zone.Editor.enable_dnssec("example.com") do
{:ok, signed_zone} ->
IO.puts("DNSSEC enabled successfully")
{:error, reason} ->
IO.puts("DNSSEC setup failed: #{reason}")
end
# Manual zone signing
case DNS.Zone.DNSSEC.sign_zone(zone,
algorithm: :rsasha256,
key_size: 2048,
nsec3_enabled: true
) do
{:ok, signed_zone} ->
IO.puts("Zone signed successfully")
{:error, reason} ->
IO.puts("Signing failed: #{reason}")
end
```
### Zone Validation
```elixir
# Validate zone configuration
case DNS.Zone.Validator.validate_zone(zone) do
{:ok, result} ->
IO.puts("Zone is valid: #{result.zone_name}")
{:error, result} ->
IO.puts("Zone has errors: #{inspect(result.errors)}")
end
# Generate comprehensive diagnostics
diagnostics = DNS.Zone.Validator.generate_diagnostics(zone)
IO.inspect(diagnostics.statistics)
IO.inspect(diagnostics.security_assessment)
IO.inspect(diagnostics.recommendations)
```
## Development
### Testing
```bash
# Run all tests
mix test
# Run specific test file
mix test test/dns/message_test.exs
# Run tests including WIP tagged tests
mix test --include wip
# Run tests with detailed output
mix test --trace
```
### Code Quality
```bash
# Format code
mix format
# Check if code is formatted
mix format --check-formatted
# Run static code analysis
mix credo
# Run type checking
mix dialyzer
```
### Manual Testing Scripts
```bash
# Test all String.Chars implementations
elixir test_all_string_chars.exs
# Test zone system functionality
elixir test_zone_system.exs
```
## Performance Considerations
### Domain Name Compression
Domain name compression is implemented in `DNS.Message.Domain.parse_domain_from_message/2` with security measures to prevent compression loop attacks.
### Binary Pattern Matching
The library heavily utilizes Elixir's pattern matching on binaries for efficient DNS protocol parsing, particularly in performance-critical paths.
### ETS-Based Storage
Zone management uses ETS tables for high-concurrency in-memory storage with separate tables for zone data and metadata.
## Security Notes
### Current Limitations
- DNSSEC implementation uses placeholder cryptographic functions (production use requires proper crypto implementations)
- Domain compression depth limits should be enforced in production
- Record length fields (rdlength) require validation to prevent memory exhaustion attacks
### Recommendations
- Validate all binary input data before processing
- Implement rate limiting for DNS message processing
- Use proper cryptographic libraries for DNSSEC operations
- Monitor for compression loop attacks in domain name parsing
## Contributing
1. Fork the repository
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a Pull Request
## License
This project is licensed under the MIT License - see the LICENSE file for details.
## References
- [IANA DNS Parameters](https://www.iana.org/assignments/dns-parameters/)
- [RFC 1035 - Domain Names - Implementation and Specification](https://tools.ietf.org/html/rfc1035)
- [RFC 6891 - Extension Mechanisms for DNS (EDNS0)](https://tools.ietf.org/html/rfc6891)
- [RFC 4034 - Resource Records for the DNS Security Extensions](https://tools.ietf.org/html/rfc4034)
- [RFC 9460 - Service Binding and Parameter Specification via the DNS (SVCB and HTTPS)](https://tools.ietf.org/html/rfc9460)