DNS API server and PowerDNS remote backend for the IBP GeoDNS System v2, providing geographic load balancing with health-aware routing.
IBP GeoDNS is the core DNS component that integrates with PowerDNS to provide:
- Geographic routing based on MaxMind GeoIP data
- Dynamic A/AAAA responses with 30-second TTL
- Health-aware routing using official monitor consensus
- ACME challenge support for SSL certificates
- Usage accounting with MySQL persistence
This repository builds only the DNS service. The monitor and collator are separate binaries in their own repositories and interact with GeoDNS through shared libraries, NATS, MySQL, and the monitor /results API.
- PowerDNS Remote Backend: Full implementation of PowerDNS JSON protocol
- Geographic Load Balancing: Routes users to nearest healthy infrastructure provider
- IPv4/IPv6 Dual Stack: Independent health tracking and routing for both protocols
- Dynamic & Static Records: Service records updated based on health; static NS/TXT from config
- Usage Analytics: Tracks queries by date, domain, member, country, ASN, and network
- ACME Support: Fetches TXT records via HTTP for SSL certificate validation
The DNS API implements these PowerDNS remote backend methods:
initialize- Backend initializationlookup- Dynamic DNS queries (A/AAAA with geo-routing)list- Static record enumerationgetDomainInfo- Zone metadatagetAllDomains- All zones servedgetAllDomainMetadata- Zone metadatagetDomainKeys- DNSSEC keysgetMemberEvents- Member outage history
- Extract client IP and determine location via MaxMind
- Query official monitor snapshot for member status
- Filter members:
- Skip if
Member.Override=true - Skip if offline (per consensus)
- Skip if missing required IP version
- Skip if
- Calculate geographic distance to each healthy member
- Return IP of closest member with 30s TTL
{
"System": {
"WorkDir": "/path/to/workdir/",
"LogLevel": "Info",
"ConfigUrls": {
"StaticDNSConfig": "https://raw.githubusercontent.com/.../geodns-static.json",
"MembersConfig": "https://raw.githubusercontent.com/.../members_professional.json",
"ServicesConfig": "https://raw.githubusercontent.com/.../services_rpc.json"
},
"ConfigReloadTime": 3600,
"MinimumOfflineTime": 900
},
"Nats": {
"NodeID": "DNS-NODE-1",
"Url": "nats://server1:4222,nats://server2:4222",
"User": "dns-user",
"Pass": "__SET_ME__"
},
"Mysql": {
"Host": "localhost",
"Port": "3306",
"User": "ibpdns",
"Pass": "__SET_ME__",
"DB": "ibpdns"
},
"Maxmind": {
"MaxmindDBPath": "/path/to/maxmind/",
"AccountID": "your-account-id",
"LicenseKey": "__SET_ME__"
},
"DnsApi": {
"ListenAddress": "0.0.0.0",
"ListenPort": "6100",
"MonitorAddress": "127.0.0.1",
"MonitorPort": "6101",
"RefreshIntervalSeconds": 30
}
}ConfigReloadTime is an integer number of seconds, for example 300 or 3600.
# pdns.conf
launch=remote
remote-connection-string=http:url=http://localhost:6100/dnsPowerDNS remote backend protocol. Handles all DNS queries and zone management.
Request:
{
"method": "lookup",
"parameters": {
"qname": "rpc.dotters.network",
"qtype": "A",
"remote": "203.0.113.45"
}
}Response:
{
"result": [
{
"qname": "rpc.dotters.network",
"qtype": "A",
"content": "198.51.100.10",
"ttl": 30,
"auth": true
}
]
}Triggers manual usage flush to MySQL for specified date.
- A/AAAA: Geographic routing to nearest healthy member
- TTL: 30 seconds for dynamic responses
- NS: Nameserver records from remote config
- TXT: Static text records
- SOA: Serial uses current UTC timestamp
- ACME challenges:
_acme-challenge.*fetched via HTTP- Maximum 3 retry attempts
- 512-byte response limit
- 5-second timeout per attempt
The system tracks DNS queries with these dimensions:
- Temporal: Date/time of query
- Geographic: Country, ASN, network (via MaxMind)
- Service: Domain queried, member selected
- Protocol: IPv4 vs IPv6
Data flow:
- In-memory aggregation during operation
- Automatic flush every 5 minutes
- Manual flush via
/processendpoint - MySQL persistence for reporting
IBP GeoDNS polls the monitor API every 30 seconds to update its routing snapshot:
- Fetches from
http://monitor:6101/results - Updates official health status
- Routes only to members marked online
Health is tracked independently for IPv4 and IPv6, allowing partial availability.
- Go 1.24.x or higher
- MySQL 5.7+
- NATS cluster access
- MaxMind GeoLite2 license
go build -o ibp-geodns ./src/IBPDns.go./ibp-geodns -config=/path/to/ibpdns.jsonFROM golang:1.24-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o geodns ./src/IBPDns.go
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/geodns /geodns
ENTRYPOINT ["/geodns"]Key tables:
dns_usage: Query statistics and aggregationsmember_events: Outage tracking and historydns_cache: Response caching (optional)
Fatal: Critical failuresError: Request failures, backend errorsWarn: Configuration issues, fallback behaviorInfo: Startup, config reloads, routing decisionsDebug: Detailed request/response, distance calculations
- Query rate by type (A/AAAA)
- Member selection distribution
- Geographic query origins
- Cache hit rates
- Response times
- Never expose credentials in configs (use
__SET_ME__placeholders) - TLS verification for remote config fetches
- ACME response size limits prevent abuse
- Member override mechanism for maintenance
Core libraries:
github.com/ibp-network/ibp-geodns-libs- Shared componentsgolang.org/x/net/publicsuffix- TLD extraction- PowerDNS 4.x - Authoritative DNS server
See LICENSE file in repository root.