The DNS Zone List API provides access to your BIND DNS zones through authenticated web endpoints. Use this API to discover available zones, retrieve zone metadata, and view DNS records. This is designed for the upcoming DNS zone editor.
Base URL: https://tools.tornevall.net/dns
Authentication: Session-based (for web UI) or Token-based (for API integrations)
For web applications and dashboard use:
/login with your credentialscredentials: 'include' in JavaScript fetchFor programmatic access:
/dns/tokens)curl -H "Authorization: Bearer dns_secret_xxxxx" https://tools.tornevall.net/api/dns/zones
Token system is similar to Cloudflare's API tokens - each zone gets its own secret + zone key pair.
credentials: 'include' works/dns/editor in the web interfaceSee the Access Control section to grant zone permissions to users.
You need:
Request a token in the DNS Editor UI. Tokens include:
Tokens are managed per-zone, similar to Cloudflare's zone API tokens.
Note: This API requires session-based or token-based authentication. It is designed for:
Each user can have different roles for different zones:
As an admin, you can grant specific users access to specific zones:
/admin/dns/zone/{zoneName}Database Table: dns_zone_permissions
-- Grant user_id=5 'owner' access to tornevall.net zone
INSERT INTO dns_zone_permissions (user_id, zone, role, created_at, updated_at)
VALUES (5, 'tornevall.net', 'owner', NOW(), NOW());
-- Grant user_id=3 'editor' access to example.com zone
INSERT INTO dns_zone_permissions (user_id, zone, role, created_at, updated_at)
VALUES (3, 'example.com', 'editor', NOW(), NOW());
Each zone can have one active API token consisting of:
dns_secret_abc123...)zone_xyz789...)Users with Owner or Editor roles can:
/dns/tokensAdmins can:
/admin/dns/zone/{zone}Endpoint: GET /dns/zones
Description: Returns a list of all editable zones discovered from BIND configuration files.
Requirements:
is_admin = true)Request:
# In a browser (automatic session handling)
curl -X GET "https://tools.tornevall.net/dns/zones" \
--cookie "path/to/cookie_jar.txt"
Response (Success):
{
"ok": true,
"count": 3,
"zones": [
{
"zone": "tornevall.net",
"file": "master/tornevall/tornevall.net",
"key": "tornevall.net"
},
{
"zone": "example.com",
"file": "master/example/example.com",
"key": "example.com"
},
{
"zone": "10.10.10.in-addr.arpa",
"file": "master/reverse/10.10.10.in-addr.arpa",
"key": "10.10.10.in-addr.arpa"
}
]
}
Response (Forbidden - No Permission):
{
"ok": false,
"reason": "forbidden"
}
Status Codes:
200 OK - Request successful403 Forbidden - User lacks admin privileges or zone access404 Not Found - Required paths missing on serverNotes:
.conf filesEndpoint: GET /dns/zones/{zoneName}
Description: Retrieves metadata and parsed records for a specific zone. Admin users can access any zone; non-admin users are currently denied (permission framework placeholder for future zone-level permissions).
Parameters:
zoneName (string, required) - The zone name (e.g., tornevall.net)Requirements:
is_admin = true)dns_zone_permissions) will allow granular per-user zone accessRequest:
# In a browser (automatic session handling)
curl -X GET "https://tools.tornevall.net/dns/zones/tornevall.net" \
--cookie "path/to/cookie_jar.txt"
Response (Success):
{
"ok": true,
"zone": "tornevall.net",
"named": {
"file": "master/tornevall/tornevall.net",
"key": "tornevall.net"
},
"zoneData": [
{
"name": "tornevall.net",
"ttl": "3600",
"class": "IN",
"type": "SOA",
"rdata": "ns1.tornevall.net. admin.tornevall.net. 2026021301 10800 3600 604800 3600",
"rawLine": "tornevall.net 3600 IN SOA ns1.tornevall.net. admin.tornevall.net. 2026021301 10800 3600 604800 3600"
},
{
"name": "tornevall.net",
"ttl": "3600",
"class": "IN",
"type": "NS",
"rdata": "ns1.tornevall.net.",
"rawLine": "tornevall.net 3600 IN NS ns1.tornevall.net."
},
{
"name": "www.tornevall.net",
"ttl": "3600",
"class": "IN",
"type": "A",
"rdata": "192.168.1.100",
"rawLine": "www.tornevall.net 3600 IN A 192.168.1.100"
},
{
"name": "mail.tornevall.net",
"ttl": "3600",
"class": "IN",
"type": "A",
"rdata": "192.168.1.101",
"rawLine": "mail.tornevall.net 3600 IN A 192.168.1.101"
},
{
"name": "tornevall.net",
"ttl": "3600",
"class": "IN",
"type": "MX",
"rdata": "10 mail.tornevall.net.",
"rawLine": "tornevall.net 3600 IN MX 10 mail.tornevall.net."
}
]
}
Response (Zone Not Found):
{
"ok": false,
"reason": "zone_not_found"
}
Response (Forbidden):
{
"ok": false,
"reason": "forbidden"
}
Response (Missing Required Paths):
{
"ok": false,
"reason": "required_paths_missing_or_unreadable"
}
Status Codes:
200 OK - Zone found and details retrieved403 Forbidden - User lacks permission to access zone404 Not Found - Zone not found or required paths missingAccess Control:
Notes:
zoneData field is optional and will be null if the zone file cannot be read$INCLUDE or $GENERATE support)Each parsed DNS record in zoneData contains:
| Field | Type | Description |
|---|---|---|
name |
string | Record owner name (@ expands to zone origin, empty inherits from previous) |
ttl |
string | null | Time-to-live in seconds (null if using default TTL) |
class |
string | DNS class: IN, CH, or HS (defaults to IN) |
type |
string | Record type: A, AAAA, CNAME, MX, NS, SOA, TXT, etc. |
rdata |
string | Record data (e.g., IP address, hostname, text) |
rawLine |
string | Original line from zone file (for reference/debugging) |
The API parses zone files with the following features:
$TTL directive; are stripped$ORIGIN directive recognizedThe parser conservatively excludes:
$INCLUDE directives$GENERATE directivesNote: If you need advanced parsing, consider requesting an enhanced version.
| Reason | Status | Description |
|---|---|---|
forbidden |
403 | User lacks permission to access zones or this zone |
zone_not_found |
404 | Requested zone doesn't exist |
required_paths_missing_or_unreadable |
404 | Server not properly configured (contact admin) |
Simply navigate to:
https://tools.tornevall.net/dns/zones
You'll get JSON output of all available zones (if you're logged in as an admin).
#!/bin/bash
# First, login via the login endpoint or use existing session cookies
COOKIE_JAR="/tmp/cookies.txt"
# Login
curl -X POST "https://tools.tornevall.net/login" \
--cookie-jar "$COOKIE_JAR" \
-d "email=admin@example.com&password=yourpassword"
# List zones
curl -X GET "https://tools.tornevall.net/dns/zones" \
--cookie "$COOKIE_JAR" \
-s | jq .
Output:
{
"ok": true,
"count": 2,
"zones": [
{
"zone": "tornevall.net",
"file": "master/tornevall/tornevall.net",
"key": "tornevall.net"
}
]
}
#!/bin/bash
COOKIE_JAR="/tmp/cookies.txt"
ZONE="tornevall.net"
# Get all records
RESPONSE=$(curl -X GET "https://tools.tornevall.net/dns/zones/${ZONE}" \
--cookie "$COOKIE_JAR" \
-s)
# Filter MX records
echo "$RESPONSE" | jq '.zoneData[] | select(.type == "MX")'
Output:
{
"name": "tornevall.net",
"ttl": "3600",
"class": "IN",
"type": "MX",
"rdata": "10 mail.tornevall.net.",
"rawLine": "tornevall.net 3600 IN MX 10 mail.tornevall.net."
}
const baseUrl = 'https://tools.tornevall.net';
// Fetch all zones
async function listZones() {
const response = await fetch(`${baseUrl}/dns/zones`, {
method: 'GET',
credentials: 'include' // Include session cookie
});
const data = await response.json();
if (data.ok) {
console.log(`Found ${data.count} zones:`, data.zones);
} else {
console.error('Error:', data.reason);
}
}
// Fetch specific zone with records
async function getZoneDetails(zoneName) {
const response = await fetch(`${baseUrl}/dns/zones/${zoneName}`, {
method: 'GET',
credentials: 'include'
});
const data = await response.json();
if (data.ok) {
console.log(`Zone: ${data.zone}`);
console.log(`File: ${data.named.file}`);
console.log(`Records:`, data.zoneData);
} else {
console.error(`Error: ${data.reason}`);
}
}
// Usage
listZones();
getZoneDetails('tornevall.net');
async function displayZoneRecords(zoneName, recordType = null) {
const response = await fetch(`https://tools.tornevall.net/dns/zones/${zoneName}`, {
method: 'GET',
credentials: 'include'
});
const data = await response.json();
if (!data.ok) {
console.error(`Cannot load zone: ${data.reason}`);
return;
}
// Filter records if type specified
let records = data.zoneData || [];
if (recordType) {
records = records.filter(r => r.type === recordType.toUpperCase());
}
// Display in table
console.table(records);
}
// Get all A records for tornevall.net
displayZoneRecords('tornevall.net', 'A');
} }
// Fetch specific zone with records
async function getZoneDetails(zoneName) {
const response = await fetch(${apiBase}/dns/zones/${zoneName}, {
method: 'GET',
credentials: 'include'
});
const data = await response.json();
if (data.ok) {
console.log(Zone: ${data.zone});
console.log(File: ${data.named.file});
console.log(Records:, data.zoneData);
} else {
console.error(Error: ${data.reason});
}
}
// Usage listZones(); getZoneDetails('tornevall.net');
---
## Security Considerations
### Authentication Required
- All endpoints require valid session authentication
- Anonymous requests are rejected with `401 Unauthorized`
### Authorization
- **Admin Users** - Full access to all zones
- **Regular Users** - Access only to zones they have explicit permission for
- Zone permissions are managed via the `dns_zone_permissions` table
### Best Practices
- Use HTTPS only (always use `https://` in your requests)
- Session cookies are `HttpOnly` and `Secure` flagged
- Never share your login credentials or session cookies
- Regularly review zone access permissions for inactive users
---
## Limitations & Roadmap
### Current Limitations
- ✅ Session-based auth only (no API tokens yet)
- ✅ Admin-only zone listing (future: per-zone permissions filtering)
- ✅ Read-only access (no zone creation/modification yet)
- ✅ Basic zone file parsing (no `$INCLUDE` or `$GENERATE`)
### Planned Features
1. **Zone Editor** - Create, modify, delete DNS records
2. **API Tokens** - Programmatic access for integrations
3. **Per-Zone Permissions** - Filter listed zones by user permissions
4. **DNSSEC Support** - Parse and validate DNSSEC records
5. **Audit Logging** - Track all zone access and modifications
6. **Real-time Validation** - Check records against live DNS
---
## Related Documentation
- [MCU API Documentation](/docs/mcu-api)
- [RSS Watch System](/docs/rsswatch)
- [OpenAI Documentation](/docs/openai)
---
## Support
For issues or questions:
1. Ensure you're logged in with the correct account
2. Verify you have admin privileges or zone-specific permissions
3. Check that DNS zones are properly configured on the server
4. Contact an administrator for permission grants or server issues
**Last Updated:** 2026-02-13