← Back to docs

dns-api

Language: EN | EN | SV

DNS Zone List API - User Guide

Overview

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)


Authentication Methods

Session-Based (Web Interface)

For web applications and dashboard use:

  1. Login at /login with your credentials
  2. Browser maintains session automatically
  3. Use with credentials: 'include' in JavaScript fetch

Token-Based (API Integrations)

For programmatic access:

  1. Request an API token in the DNS Editor UI (/dns/tokens)
  2. Each zone has a unique Secret token
  3. Include the Secret as Bearer token in API requests:
    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.


Quick Start

I'm a Web Developer Using the API

  1. Get a session - Login to https://tools.tornevall.net with your credentials
  2. Your browser maintains the session automatically - JavaScript with credentials: 'include' works
  3. Make requests - Use fetch or curl with your session

I'm a Zone Owner Requesting an API Token

  1. Navigate to /dns/editor in the web interface
  2. Click "Manage API Tokens"
  3. Select your zone and click "Create Token"
  4. Copy the Secret for use in API calls

I'm an Admin Setting Up Zone Access

See the Access Control section to grant zone permissions to users.


Key Features


Prerequisites

For API Users

You need:

For Token-Based Access

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:


Access Control & Roles

User Roles

Each user can have different roles for different zones:

Admin Users

Regular Users

Granting Zone Access to Users

As an admin, you can grant specific users access to specific zones:

  1. Navigate to /admin/dns/zone/{zoneName}
  2. Select a user and assign a role (Viewer, Editor, or Owner)
  3. The user can now access that zone via the API

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());

Token Management

Each zone can have one active API token consisting of:

Users with Owner or Editor roles can:

  1. Request an API token for their zone via /dns/tokens
  2. Use the token in API calls
  3. Regenerate tokens if compromised

Admins can:

  1. Create tokens for any zone via /admin/dns/zone/{zone}
  2. Regenerate or revoke tokens anytime
  3. View when tokens were last used

API Endpoints

List All Zones

Endpoint: GET /dns/zones

Description: Returns a list of all editable zones discovered from BIND configuration files.

Requirements:

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:

Notes:


Get Zone Details

Endpoint: 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:

Requirements:

Request:

# 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:

Access Control:

Notes:


Record Format

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)

Zone File Parsing

Supported Syntax

The API parses zone files with the following features:

Unsupported Features

The parser conservatively excludes:

Note: If you need advanced parsing, consider requesting an enhanced version.


Error Handling

Common Error Responses

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)

Examples

Example 1: List All Zones (Browser)

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).

Example 2: List All Zones (curl with cookies)

#!/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"
    }
  ]
}

Example 3: Retrieve and Filter Zone Records (curl)

#!/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."
}

Example 4: JavaScript / Fetch API (SPA/Frontend)

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');

Example 5: Filter and Display Zone Records

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