diff --git a/.gitignore b/.gitignore index eb42bc9..5192a95 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ desktop.ini AGENTS.md README.md .agents +.serena diff --git a/DYNAMIC_DNS.md b/DYNAMIC_DNS.md new file mode 100644 index 0000000..a83492d --- /dev/null +++ b/DYNAMIC_DNS.md @@ -0,0 +1,129 @@ +# Dynamic DNS Client Guide + +This application can update selected DNS records through a public Dynamic DNS API endpoint. Dynamic DNS is available only for `A` and `AAAA` records. + +## Prerequisites + +- The application must be running with its MySQL application database configured. +- The DNS record must already exist or be created through the web UI. +- Dynamic DNS must be enabled on the target record. +- The client must have the generated dynamic DNS token for that record. + +## Enable Dynamic DNS for a Record + +1. Sign in to the web UI. +2. Open the zone that contains the record. +3. Create or edit an `A` or `AAAA` record. +4. Check `Habilitar atualizacoes de DNS dinamico`. +5. Save the record. +6. Copy the generated token immediately. + +The token is displayed only once. If it is lost, regenerate it from the zone record list. + +## Update Endpoint + +Clients update records by sending a JSON `POST` request to: + +```text +/api/dyndns +``` + +Request body: + +```json +{ + "name": "www.example.org", + "token": "generated-token", + "address": "198.51.100.40" +} +``` + +Fields: + +- `name`: DNS record name to update. A trailing dot is optional. +- `token`: Dynamic DNS token generated by the application. +- `address`: Optional IP address to publish. + +If `address` is omitted, the application detects the client address in this order: + +1. First IP in the `X-Forwarded-For` header. +2. `X-Real-IP` header. +3. The direct remote client IP. + +For `A` records, the address must be IPv4. For `AAAA` records, the address must be IPv6. + +## Examples + +Update an `A` record with an explicit IPv4 address: + +```sh +curl -X POST https://dns-admin.example.com/api/dyndns \ + -H 'Content-Type: application/json' \ + -d '{"name":"www.example.org","token":"generated-token","address":"198.51.100.40"}' +``` + +Update an `A` record using the detected client IP: + +```sh +curl -X POST https://dns-admin.example.com/api/dyndns \ + -H 'Content-Type: application/json' \ + -d '{"name":"www.example.org","token":"generated-token"}' +``` + +Update an `AAAA` record with an explicit IPv6 address: + +```sh +curl -X POST https://dns-admin.example.com/api/dyndns \ + -H 'Content-Type: application/json' \ + -d '{"name":"ipv6.example.org","token":"generated-token","address":"2001:db8::40"}' +``` + +## Responses + +Successful update: + +```http +HTTP/1.1 200 OK +Content-Type: application/json; charset=utf-8 + +{"status":"OK"} +``` + +Error responses use this shape: + +```json +{ + "error": "message" +} +``` + +Common status codes: + +- `200 OK`: Record was updated in PowerDNS. +- `400 Bad Request`: Invalid JSON, record name, token format, IP address, or address type. +- `401 Unauthorized`: Record name and token do not match an enabled Dynamic DNS record. +- `502 Bad Gateway`: The application could not update PowerDNS. +- `503 Service Unavailable`: The application database is not configured or unavailable. + +## Token Management + +Dynamic DNS tokens are stored as hashes and are not displayed again after generation. + +To replace a token: + +1. Open the zone in the web UI. +2. Find the record marked `DNS dinamico`. +3. Click `Regenerar token`. +4. Copy the new token immediately. + +After regeneration, the previous token no longer works. + +To disable Dynamic DNS for a record, edit the record and clear `Habilitar atualizacoes de DNS dinamico`. Deleting the record also disables its Dynamic DNS configuration. + +## Security Notes + +- Treat the token like a password. +- Use HTTPS in production so tokens are not sent in clear text. +- The `/api/dyndns` endpoint is public and does not require a web UI session. +- Authentication for updates is based on the record name and token. +- Rotate the token if it may have been exposed.