secubox-openwrt/package/secubox/secubox-app-dns-provider/files/usr/lib/secubox/dns/gandi.sh
CyberMind-FR 0e0749ed08 feat: Add threat-analyst, dns-guard, mcp-server and DNS provider DynDNS
New packages:
- secubox-threat-analyst: AI-powered threat analysis with CrowdSec integration
- luci-app-threat-analyst: LuCI dashboard for threat intelligence
- secubox-dns-guard: DNS security monitoring and blocking
- secubox-mcp-server: Model Context Protocol server for AI assistant integration

Enhancements:
- dns-provider: Add DynDNS support (dyndns, get, update, domains commands)
- gandi.sh: Full DynDNS with WAN IP detection and record updates
- luci-app-dnsguard: Upgrade to v1.1.0 with improved dashboard

Infrastructure:
- BIND9 DNS setup for secubox.in with CAA records
- Wildcard SSL certificates via DNS-01 challenge
- HAProxy config fixes for secubox.in subdomains
- Mail server setup with Roundcube webmail

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 08:30:28 +01:00

122 lines
3.3 KiB
Bash

#!/bin/sh
# Gandi LiveDNS v5 Provider Adapter
# API: https://api.gandi.net/v5/
# Requires: api_key (Personal Access Token)
# Optional: sharing_id (organization ID for filtering/billing)
GANDI_API_BASE="https://api.gandi.net"
_gandi_request() {
local method="$1" path="$2" body="$3"
local api_key=$(uci -q get dns-provider.gandi.api_key)
local sharing_id=$(uci -q get dns-provider.gandi.sharing_id)
[ -z "$api_key" ] && { echo '{"error":"No API key configured"}'; return 1; }
# Build query string with sharing_id if set
local query=""
[ -n "$sharing_id" ] && query="?sharing_id=$sharing_id"
local url="${GANDI_API_BASE}${path}${query}"
if [ -n "$body" ]; then
curl -s -X "$method" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $api_key" \
-d "$body" "$url" 2>/dev/null
else
curl -s -X "$method" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $api_key" \
"$url" 2>/dev/null
fi
}
dns_list() {
local zone="$1"
_gandi_request GET "/v5/livedns/domains/${zone}/records"
}
dns_add() {
local zone="$1" type="$2" subdomain="$3" target="$4" ttl="${5:-3600}"
local body="{\"rrset_type\":\"${type}\",\"rrset_ttl\":${ttl},\"rrset_values\":[\"${target}\"]}"
_gandi_request POST "/v5/livedns/domains/${zone}/records/${subdomain}/${type}" "$body"
}
dns_rm() {
local zone="$1" type="$2" subdomain="$3"
_gandi_request DELETE "/v5/livedns/domains/${zone}/records/${subdomain}/${type}"
}
dns_verify() {
local fqdn="$1"
local result=$(nslookup "$fqdn" 2>/dev/null | grep -A1 "Name:" | tail -1)
if [ -n "$result" ]; then
echo "resolved"
else
echo "not_resolved"
fi
}
dns_test_credentials() {
local result=$(_gandi_request GET "/v5/livedns/domains")
if echo "$result" | grep -q "fqdn"; then
echo "ok"
else
echo "failed: $result"
fi
}
# Get current IP for a record
dns_get() {
local zone="$1" type="$2" subdomain="$3"
[ -z "$subdomain" ] && subdomain="@"
_gandi_request GET "/v5/livedns/domains/${zone}/records/${subdomain}/${type}"
}
# Update existing record (PUT for DynDNS)
dns_update() {
local zone="$1" type="$2" subdomain="$3" target="$4" ttl="${5:-300}"
[ -z "$subdomain" ] && subdomain="@"
local body="{\"rrset_ttl\":${ttl},\"rrset_values\":[\"${target}\"]}"
_gandi_request PUT "/v5/livedns/domains/${zone}/records/${subdomain}/${type}" "$body"
}
# DynDNS: Update A record with current WAN IP
dns_dyndns() {
local zone="$1" subdomain="${2:-@}" ttl="${3:-300}"
# Get current WAN IP
local wan_ip=$(curl -s https://api.ipify.org 2>/dev/null)
[ -z "$wan_ip" ] && wan_ip=$(curl -s https://ifconfig.me 2>/dev/null)
[ -z "$wan_ip" ] && { echo '{"error":"Cannot detect WAN IP"}'; return 1; }
# Get current DNS value
local current=$(dns_get "$zone" "A" "$subdomain" | jsonfilter -e '@.rrset_values[0]' 2>/dev/null)
if [ "$current" = "$wan_ip" ]; then
echo "{\"status\":\"unchanged\",\"ip\":\"$wan_ip\"}"
return 0
fi
# Update record
local result=$(dns_update "$zone" "A" "$subdomain" "$wan_ip" "$ttl")
if echo "$result" | grep -q "error"; then
echo "$result"
return 1
fi
echo "{\"status\":\"updated\",\"old_ip\":\"$current\",\"new_ip\":\"$wan_ip\"}"
}
# List all domains in account
dns_domains() {
_gandi_request GET "/v5/livedns/domains"
}
# Get zone info
dns_zone_info() {
local zone="$1"
_gandi_request GET "/v5/livedns/domains/${zone}"
}