Skip to content

Tools

Operator tools: DNS servers, /etc/hosts, port utilities, DNS resolution.

All endpoints below are mounted under /api. Authentication: Authorization: Bearer <token> unless noted as public.

Endpoint count: 6

Endpoints

Method Path Handler Guards
GET /api/tools/dns-servers getToolsDNSServers RequireSuperuser()
POST /api/tools/dns-servers postToolsDNSServers RequireSuperuser()
GET /api/tools/hosts getToolsHosts RequireSuperuser()
POST /api/tools/hosts postToolsHosts RequireSuperuser()
GET /api/tools/ports getToolsPorts RequireSuperuser()
GET /api/tools/resolve getToolsResolve RequireSuperuser()

Source

Handlers for this section live in api/routes/handlers_*.go in the StarkOne source. Each handler binds its request body with gin.ShouldBindJSON(&req) and responds with the standard envelope:

{ "data": { ... } }

On error:

{ "error": { "code": "string", "message": "string" } }

Reference

GET /api/tools/dns-servers

Returns the list of nameserver entries parsed from /etc/resolv.conf.

Guards: RequireSuperuser()

Response - 200 OK

The data field is an array of server objects (one per nameserver line).

{ "data": [ { "ip": "203.0.113.10", "type": "nameserver" } ] }

Errors

Status Code Meaning
500 read_failed /etc/resolv.conf could not be opened.

Side effects - none (reads /etc/resolv.conf).

Example

curl -X GET https://panel.example.com:2087/api/tools/dns-servers \
  -H "Authorization: Bearer $TOKEN"

POST /api/tools/dns-servers

Resets /etc/resolv.conf to a fixed set of public DNS servers (Cloudflare and Google); it ignores any request body.

Guards: RequireSuperuser()

Response - 200 OK

{ "data": { "message": "DNS servers reset to public DNS" } }

Errors

Status Code Meaning
500 write_failed /etc/resolv.conf could not be written.

Side effects

  • Overwrites /etc/resolv.conf (mode 0644) with a fixed list of public nameservers (1.1.1.1, 8.8.8.8, 1.0.0.1, 8.8.4.4). The request body is not read or used.

Example

curl -X POST https://panel.example.com:2087/api/tools/dns-servers \
  -H "Authorization: Bearer $TOKEN"

GET /api/tools/hosts

Reads /etc/hosts and returns it as a structured list of parsed lines.

Guards: RequireSuperuser()

Response - 200 OK

data.lines is an array of objects. Comment lines have comment: true with empty ip/hostname; entry lines carry the parsed ip and hostname. Every object includes the original raw line. Blank lines are skipped.

{
  "data": {
    "lines": [
      { "ip": "", "hostname": "", "comment": true, "raw": "# static entries" },
      { "ip": "203.0.113.20", "hostname": "host.example.com", "comment": false, "raw": "203.0.113.20 host.example.com" }
    ]
  }
}

Errors

Status Code Meaning
500 read_failed /etc/hosts could not be read.

Side effects - none (reads /etc/hosts).

Example

curl -X GET https://panel.example.com:2087/api/tools/hosts \
  -H "Authorization: Bearer $TOKEN"

POST /api/tools/hosts

Overwrites the entire /etc/hosts file with the supplied raw content.

Guards: RequireSuperuser()

Request body

{ "content": "string (required)" }
Field Type Required Description
content string no (binding) Full replacement text for /etc/hosts. No binding:"required" tag is set, but an empty/absent value writes an effectively empty file. A trailing newline is appended automatically.

Response - 200 OK

{ "data": { "message": "hosts file saved" } }

Errors

Status Code Meaning
400 invalid_body Request body is not valid JSON.
500 write_failed /etc/hosts could not be written.

Side effects

  • Overwrites /etc/hosts (mode 0644) with content plus a trailing newline.

Example

curl -X POST https://panel.example.com:2087/api/tools/hosts \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content": "127.0.0.1 localhost\n203.0.113.20 host.example.com"}'

GET /api/tools/ports

Lists listening TCP/UDP ports (via ss), annotates each with whether it is opened in the CSF firewall, and returns the count of established connections.

Guards: RequireSuperuser()

Response - 200 OK

data.ports is a deduplicated, port-sorted array. Entries sharing a port+protocol are merged, with their bind addresses joined by ,. csf_open reflects whether the port appears in TCP_IN/UDP_IN in /etc/csf/csf.conf. data.established is the number of established TCP connections.

{
  "data": {
    "ports": [
      { "port": 2087, "protocol": "tcp", "address": "0.0.0.0", "process": "starkone", "pid": "1234", "csf_open": true }
    ],
    "established": 5
  }
}

Side effects

  • Executes ss -tlnp, ss -ulnp, and ss -tn state established (read-only). Reads /etc/csf/csf.conf if present (missing/unreadable file is ignored).

Example

curl -X GET https://panel.example.com:2087/api/tools/ports \
  -H "Authorization: Bearer $TOKEN"

GET /api/tools/resolve

Resolves a hostname to a single IPv4 (default) or IPv6 address using the system resolver and reports how long the lookup took.

Guards: RequireSuperuser()

Query parameters

Name Type Optional Description
host string no Hostname to resolve. Required; a missing/empty value returns 400.
type string yes Record type. AAAA resolves IPv6 (ip6); any other value (default A) resolves IPv4 (ip4).

Response - 200 OK

On success, returns the first resolved address. Note that resolution failures also return 200 with an error field inside data and an empty ip (not an HTTP error status).

{ "data": { "host": "host.example.com", "ip": "203.0.113.30", "time_ms": 12, "type": "A" } }

Failure shape (still 200 OK):

{ "data": { "host": "host.example.com", "ip": "", "time_ms": 12, "error": "resolution failed", "type": "A" } }

Errors

Status Code Meaning
400 missing_host The host query parameter was absent or empty.

Side effects - none (performs a DNS lookup only).

Example

curl -X GET "https://panel.example.com:2087/api/tools/resolve?host=host.example.com&type=A" \
  -H "Authorization: Bearer $TOKEN"