From fda71133829d69d9ec592e9d81b049b7a60d91d3 Mon Sep 17 00:00:00 2001 From: shm0rt Date: Tue, 8 Jul 2025 21:01:56 +0200 Subject: [PATCH] added testfile --- pdns-ddns | 358 +++++++++++++++++++++++++++++++++++++------------ pdns-ddns-test | 317 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 587 insertions(+), 88 deletions(-) create mode 100644 pdns-ddns-test diff --git a/pdns-ddns b/pdns-ddns index 188bad3..fcd6d1d 100755 --- a/pdns-ddns +++ b/pdns-ddns @@ -8,124 +8,306 @@ source /etc/powerdns/ddns.conf # IP History file IP_HISTORY_FILE="/var/log/ddns-ip-history.log" -# Get external IP -EXTERNAL_IP=$(curl -s ifconfig.me) +# ============================================================================ +# LOGGING FUNCTIONS +# ============================================================================ -if [[ ! $EXTERNAL_IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then - echo "ERROR: Invalid IP address: $EXTERNAL_IP" - exit 1 -fi +log_info() { + echo "$(date): $1" +} -echo "$(date): External IP: $EXTERNAL_IP" +log_error() { + echo "$(date): ERROR: $1" +} -# Read last known IP -LAST_IP="" -if [[ -f "$IP_HISTORY_FILE" ]]; then - LAST_IP=$(grep "IP changed from" "$IP_HISTORY_FILE" | tail -1 | sed 's/.*to \([0-9.]*\)$/\1/') -fi +log_success() { + echo "$(date): SUCCESS: $1" +} -# Log IP change if different -if [[ -n "$LAST_IP" && "$LAST_IP" != "$EXTERNAL_IP" ]]; then - echo "$(date): IP changed from $LAST_IP to $EXTERNAL_IP" | tee -a "$IP_HISTORY_FILE" - echo "$(date): Previous IPs in last 10 changes:" - grep "IP changed from" "$IP_HISTORY_FILE" | tail -10 | sed 's/.*from \([0-9.]*\) to \([0-9.]*\)$/Old: \1 -> New: \2/' || echo "No previous changes found" -elif [[ -z "$LAST_IP" ]]; then - echo "$(date): IP unchanged: $EXTERNAL_IP (first run or no history)" -else - echo "$(date): IP unchanged: $EXTERNAL_IP" -fi +log_change() { + local message="$1" + echo "$(date): $message" + echo "$(date): $message" >> "$IP_HISTORY_FILE" +} -# Check and update Infomaniak (external) -echo "$(date): Checking Infomaniak A record for $INFOMANIAK_DOMAIN..." -CURRENT_RECORD=$(curl -s -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ - "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records" | \ - jq -r '.data[] | select(.type=="A" and .source==".") | .target' | head -1) +log_history() { + echo "$(date): $1" >> "$IP_HISTORY_FILE" +} -if [[ "$CURRENT_RECORD" == "$EXTERNAL_IP" ]]; then - echo "$(date): Infomaniak A record already correct: $EXTERNAL_IP" -else - if [[ -n "$CURRENT_RECORD" ]]; then - echo "$(date): Infomaniak A record needs update: $CURRENT_RECORD -> $EXTERNAL_IP" - echo "$(date): Infomaniak change: $CURRENT_RECORD -> $EXTERNAL_IP" >> "$IP_HISTORY_FILE" - else - echo "$(date): Infomaniak A record does not exist, creating with IP: $EXTERNAL_IP" - echo "$(date): Infomaniak created: -> $EXTERNAL_IP" >> "$IP_HISTORY_FILE" +# ============================================================================ +# IP CHANGE DETECTION +# ============================================================================ + +check_ip_change() { + # Get external IP + EXTERNAL_IP=$(curl -s ifconfig.me) + + if [[ ! $EXTERNAL_IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + log_error "Invalid IP address: $EXTERNAL_IP" + exit 1 fi - - RECORD_ID=$(curl -s -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ + + # Read last known IP + local last_ip="" + if [[ -f "$IP_HISTORY_FILE" ]]; then + last_ip=$(grep "IP changed from" "$IP_HISTORY_FILE" | tail -1 | sed 's/.*to \([0-9.]*\)$/\1/') + fi + + # Check if IP changed + if [[ -n "$last_ip" && "$last_ip" != "$EXTERNAL_IP" ]]; then + log_info "External IP: $EXTERNAL_IP" + log_change "IP changed from $last_ip to $EXTERNAL_IP" + log_info "Previous IPs in last 10 changes:" + grep "IP changed from" "$IP_HISTORY_FILE" | tail -10 | sed 's/.*from \([0-9.]*\) to \([0-9.]*\)$/Old: \1 -> New: \2/' || log_info "No previous changes found" + return 1 # IP changed = update needed + elif [[ -z "$last_ip" ]]; then + log_info "External IP: $EXTERNAL_IP" + log_info "First run or no history - checking DNS records" + return 1 # First run = update needed + else + # IP unchanged - only return 1 if we need to check DNS consistency + return 0 # No change needed + fi +} + +# ============================================================================ +# EXTERNAL DNS (INFOMANIAK) FUNCTIONS +# ============================================================================ + +check_external_dns() { + local current_record=$(curl -s -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ + "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records" | \ + jq -r '.data[] | select(.type=="A" and .source==".") | .target' | head -1) + + if [[ "$current_record" == "$EXTERNAL_IP" ]]; then + return 0 # No update needed - silent success + else + log_info "Checking Infomaniak A record for $INFOMANIAK_DOMAIN..." + if [[ -n "$current_record" ]]; then + log_change "Infomaniak A record needs update: $current_record -> $EXTERNAL_IP" + else + log_change "Infomaniak A record does not exist, creating with IP: $EXTERNAL_IP" + fi + return 1 # Update needed + fi +} + +update_external_dns() { + log_info "Updating Infomaniak DNS..." + + local record_id=$(curl -s -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records" | \ jq -r '.data[] | select(.type=="A" and .source==".") | .id' | head -1) - if [[ -z "$RECORD_ID" ]]; then - echo "$(date): Creating new Infomaniak A record..." + if [[ -z "$record_id" ]]; then + log_info "Creating new Infomaniak A record..." if curl -s -X POST "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records" \ -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"type\": \"A\", \"source\": \".\", \"target\": \"$EXTERNAL_IP\", \"ttl\": $TTL}" > /dev/null; then - echo "$(date): SUCCESS: Infomaniak A record created" + log_success "Infomaniak A record created" + log_history "Infomaniak created: -> $EXTERNAL_IP" else - echo "$(date): ERROR: Failed to create Infomaniak A record" + log_error "Failed to create Infomaniak A record" + return 1 fi else - echo "$(date): Updating Infomaniak A record..." - if curl -s -X PUT "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records/$RECORD_ID" \ + log_info "Updating existing Infomaniak A record..." + if curl -s -X PUT "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records/$record_id" \ -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"target\": \"$EXTERNAL_IP\", \"ttl\": $TTL}" > /dev/null; then - echo "$(date): SUCCESS: Infomaniak A record updated" + log_success "Infomaniak A record updated" + log_history "Infomaniak change: -> $EXTERNAL_IP" else - echo "$(date): ERROR: Failed to update Infomaniak A record" + log_error "Failed to update Infomaniak A record" + return 1 fi fi -fi + return 0 +} + +# ============================================================================ +# INTERNAL DNS (POWERDNS) FUNCTIONS +# ============================================================================ + +ensure_zone_exists() { + local domain="$1" -# Check and update PowerDNS (internal) -echo "$(date): Checking PowerDNS A records..." -for domain in $POWERDNS_DOMAINS; do - echo "$(date): Checking zone $domain..." - - # Check if zone exists if ! pdnsutil list-zone "$domain" >/dev/null 2>&1; then - echo "$(date): Zone $domain does not exist, creating..." - echo "$(date): PowerDNS $domain created: -> $EXTERNAL_IP" >> "$IP_HISTORY_FILE" + log_info "Zone $domain does not exist, creating..." + log_history "PowerDNS $domain zone created" pdnsutil create-zone "$domain" - NEEDS_UPDATE=true + return 1 # Zone was created, needs update + fi + return 0 # Zone exists +} + +check_powerdns_record() { + local domain="$1" + local record_type="$2" # "@" for root, "*" for wildcard + local display_name="$3" + + local current_ip + if [[ "$record_type" == "@" ]]; then + current_ip=$(pdnsutil list-zone "$domain" 2>/dev/null | grep -E "^${domain}\s+[0-9]+\s+IN\s+A\s+" | awk '{print $5}' | head -1) else - # Check current A record - match actual PowerDNS output format - CURRENT_IP=$(pdnsutil list-zone "$domain" 2>/dev/null | grep -E "^${domain}\s+[0-9]+\s+IN\s+A\s+" | awk '{print $5}' | head -1) - - if [[ "$CURRENT_IP" == "$EXTERNAL_IP" ]]; then - echo "$(date): PowerDNS A record for $domain already correct: $EXTERNAL_IP" - NEEDS_UPDATE=false + current_ip=$(pdnsutil list-zone "$domain" 2>/dev/null | grep -E "^\*\.${domain}\s+[0-9]+\s+IN\s+A\s+" | awk '{print $5}' | head -1) + fi + + if [[ "$current_ip" == "$EXTERNAL_IP" ]]; then + return 0 # No update needed - silent success + else + if [[ -n "$current_ip" ]]; then + log_change "PowerDNS A record for $display_name needs update: $current_ip -> $EXTERNAL_IP" else - if [[ -n "$CURRENT_IP" ]]; then - echo "$(date): PowerDNS A record for $domain needs update: $CURRENT_IP -> $EXTERNAL_IP" - echo "$(date): PowerDNS $domain change: $CURRENT_IP -> $EXTERNAL_IP" >> "$IP_HISTORY_FILE" - else - echo "$(date): PowerDNS A record for $domain does not exist, creating with IP: $EXTERNAL_IP" - echo "$(date): PowerDNS $domain created: -> $EXTERNAL_IP" >> "$IP_HISTORY_FILE" + log_change "PowerDNS A record for $display_name does not exist, creating with IP: $EXTERNAL_IP" + fi + return 1 # Update needed + fi +} + +update_powerdns_record() { + local domain="$1" + local record_type="$2" # "@" for root, "*" for wildcard + local display_name="$3" + + log_info "Updating PowerDNS A record for $display_name..." + + if pdnsutil replace-rrset "$domain" "$record_type" A "$TTL" "$EXTERNAL_IP" 2>/dev/null; then + log_success "PowerDNS A record updated for $display_name" + log_history "PowerDNS $display_name updated: -> $EXTERNAL_IP" + pdnsutil rectify-zone "$domain" 2>/dev/null + pdnsutil increase-serial "$domain" 2>/dev/null + return 0 + else + log_error "Failed to update PowerDNS A record for $display_name" + return 1 + fi +} + +check_internal_dns() { + local needs_update=false + local needs_logging=false + + for domain in $POWERDNS_DOMAINS; do + # Ensure zone exists (this might need logging) + if ! pdnsutil list-zone "$domain" >/dev/null 2>&1; then + if [[ "$needs_logging" == "false" ]]; then + log_info "Checking PowerDNS A records..." + needs_logging=true fi - NEEDS_UPDATE=true + log_info "Zone $domain does not exist, creating..." + log_history "PowerDNS $domain zone created" + pdnsutil create-zone "$domain" + needs_update=true + fi + + # Check root A record + if ! check_powerdns_record "$domain" "@" "$domain"; then + if [[ "$needs_logging" == "false" ]]; then + log_info "Checking PowerDNS A records..." + needs_logging=true + fi + needs_update=true + fi + + # Check wildcard A record + if ! check_powerdns_record "$domain" "*" "*.${domain}"; then + if [[ "$needs_logging" == "false" ]]; then + log_info "Checking PowerDNS A records..." + needs_logging=true + fi + needs_update=true + fi + done + + if [[ "$needs_update" == "true" ]]; then + return 1 # Update needed + else + return 0 # No update needed - was completely silent + fi +} + +update_internal_dns() { + log_info "Updating PowerDNS records..." + + for domain in $POWERDNS_DOMAINS; do + log_info "Processing zone $domain..." + + # Ensure zone exists + ensure_zone_exists "$domain" + + # Update root A record if needed + if ! check_powerdns_record "$domain" "@" "$domain"; then + update_powerdns_record "$domain" "@" "$domain" + fi + + # Update wildcard A record if needed + if ! check_powerdns_record "$domain" "*" "*.${domain}"; then + update_powerdns_record "$domain" "*" "*.${domain}" + fi + done +} + +# ============================================================================ +# MAIN EXECUTION +# ============================================================================ + +main() { + # Check if IP changed + if ! check_ip_change; then + # IP unchanged - check if DNS is consistent + local external_needs_update=false + local internal_needs_update=false + + if ! check_external_dns; then + external_needs_update=true + fi + + if ! check_internal_dns; then + internal_needs_update=true + fi + + # If everything is consistent, exit silently + if [[ "$external_needs_update" == "false" && "$internal_needs_update" == "false" ]]; then + exit 0 + fi + + # If we reach here, something needs fixing + log_info "External IP: $EXTERNAL_IP" + log_info "No IP change detected, but DNS inconsistencies found" + + if [[ "$external_needs_update" == "true" ]]; then + update_external_dns + fi + + if [[ "$internal_needs_update" == "true" ]]; then + update_internal_dns + fi + else + # IP changed - do full update + log_info "Starting DDNS check/update process" + + # Check and update external DNS (Infomaniak) + if ! check_external_dns; then + update_external_dns + fi + + # Check and update internal DNS (PowerDNS) + if ! check_internal_dns; then + update_internal_dns fi fi - - # Update if needed - if [[ "$NEEDS_UPDATE" == "true" ]]; then - echo "$(date): Updating PowerDNS A record for $domain..." - if pdnsutil replace-rrset "$domain" @ A "$TTL" "$EXTERNAL_IP" 2>/dev/null; then - echo "$(date): SUCCESS: PowerDNS A record updated for $domain" - pdnsutil rectify-zone "$domain" 2>/dev/null - pdnsutil increase-serial "$domain" 2>/dev/null - else - echo "$(date): ERROR: Failed to update PowerDNS A record for $domain" - fi + + log_info "DDNS check/update completed" + + # Show recent IP history summary + if [[ -f "$IP_HISTORY_FILE" ]]; then + log_info "Recent changes (last 5):" + tail -5 "$IP_HISTORY_FILE" | grep -E "(change:|created:|updated:)" || log_info "No recent changes" fi -done +} -echo "$(date): DDNS check/update completed" - -# Show recent IP history summary -if [[ -f "$IP_HISTORY_FILE" ]]; then - echo "$(date): Recent changes (last 5):" - tail -5 "$IP_HISTORY_FILE" | grep -E "(change:|created:)" || echo "No recent changes" -fi +# Run main function +main diff --git a/pdns-ddns-test b/pdns-ddns-test new file mode 100644 index 0000000..3231b46 --- /dev/null +++ b/pdns-ddns-test @@ -0,0 +1,317 @@ +#!/usr/bin/env bash +# pdns-ddns - Updates both Infomaniak and PowerDNS with external IP +# Speichern als: /usr/local/bin/pdns-ddns + +# Load config +source /etc/powerdns/ddns.conf + +# IP History file +IP_HISTORY_FILE="/var/log/ddns-ip-history.log" + +# ============================================================================ +# LOGGING FUNCTIONS +# ============================================================================ + +log_info() { + echo "$(date): $1" +} + +log_error() { + echo "$(date): ERROR: $1" +} + +log_success() { + echo "$(date): SUCCESS: $1" +} + +log_change() { + local message="$1" + echo "$(date): $message" + echo "$(date): $message" >> "$IP_HISTORY_FILE" +} + +log_history() { + echo "$(date): $1" >> "$IP_HISTORY_FILE" +} + +# ============================================================================ +# IP CHANGE DETECTION +# ============================================================================ + +check_ip_change() { + # Get external IP + EXTERNAL_IP=$(curl -s ifconfig.me) + + if [[ ! $EXTERNAL_IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + log_error "Invalid IP address: $EXTERNAL_IP" + exit 1 + fi + + # Read last known IP + local last_ip="" + if [[ -f "$IP_HISTORY_FILE" ]]; then + last_ip=$(grep "IP changed from" "$IP_HISTORY_FILE" | tail -1 | sed 's/.*to \([0-9.]*\)$/\1/') + fi + + # Check if IP changed + if [[ -n "$last_ip" && "$last_ip" != "$EXTERNAL_IP" ]]; then + log_info "External IP: $EXTERNAL_IP" + log_change "IP changed from $last_ip to $EXTERNAL_IP" + log_info "Previous IPs in last 10 changes:" + grep "IP changed from" "$IP_HISTORY_FILE" | tail -10 | sed 's/.*from \([0-9.]*\) to \([0-9.]*\)$/Old: \1 -> New: \2/' || log_info "No previous changes found" + return 1 # IP changed = update needed + elif [[ -z "$last_ip" ]]; then + log_info "External IP: $EXTERNAL_IP" + log_info "First run or no history - checking DNS records" + return 1 # First run = update needed + else + # IP unchanged - only return 1 if we need to check DNS consistency + return 0 # No change needed + fi +} + +# ============================================================================ +# EXTERNAL DNS (INFOMANIAK) FUNCTIONS +# ============================================================================ + +check_external_dns() { + local current_record=$(curl -s -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ + "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records" | \ + jq -r '.data[] | select(.type=="A" and .source==".") | .target' | head -1) + + if [[ "$current_record" == "$EXTERNAL_IP" ]]; then + return 0 # No update needed - silent success + else + log_info "Checking Infomaniak A record for $INFOMANIAK_DOMAIN..." + if [[ -n "$current_record" ]]; then + log_change "Infomaniak A record needs update: $current_record -> $EXTERNAL_IP" + else + log_change "Infomaniak A record does not exist, creating with IP: $EXTERNAL_IP" + fi + return 1 # Update needed + fi +} + +update_external_dns() { + log_info "Updating Infomaniak DNS..." + + local record_id=$(curl -s -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ + "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records" | \ + jq -r '.data[] | select(.type=="A" and .source==".") | .id' | head -1) + + if [[ -z "$record_id" ]]; then + log_info "Creating new Infomaniak A record..." + if curl -s -X POST "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records" \ + -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"type\": \"A\", \"source\": \".\", \"target\": \"$EXTERNAL_IP\", \"ttl\": $TTL}" > /dev/null; then + log_success "Infomaniak A record created" + log_history "Infomaniak created: -> $EXTERNAL_IP" + else + log_error "Failed to create Infomaniak A record" + return 1 + fi + else + log_info "Updating existing Infomaniak A record..." + if curl -s -X PUT "https://api.infomaniak.com/2/zones/$INFOMANIAK_DOMAIN/records/$record_id" \ + -H "Authorization: Bearer $INFOMANIAK_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"target\": \"$EXTERNAL_IP\", \"ttl\": $TTL}" > /dev/null; then + log_success "Infomaniak A record updated" + log_history "Infomaniak change: -> $EXTERNAL_IP" + else + log_error "Failed to update Infomaniak A record" + return 1 + fi + fi + return 0 +} + +# ============================================================================ +# INTERNAL DNS (POWERDNS) FUNCTIONS +# ============================================================================ + +ensure_zone_exists() { + local domain="$1" + + if ! pdnsutil list-zone "$domain" >/dev/null 2>&1; then + log_info "Zone $domain does not exist, creating..." + log_history "PowerDNS $domain zone created" + pdnsutil create-zone "$domain" + return 1 # Zone was created, needs update + fi + return 0 # Zone exists +} + +check_powerdns_record() { + local domain="$1" + local record_type="$2" # "@" for root, "*" for wildcard + local display_name="$3" + + local current_ip + if [[ "$record_type" == "@" ]]; then + current_ip=$(pdnsutil list-zone "$domain" 2>/dev/null | grep -E "^${domain}\s+[0-9]+\s+IN\s+A\s+" | awk '{print $5}' | head -1) + else + current_ip=$(pdnsutil list-zone "$domain" 2>/dev/null | grep -E "^\*\.${domain}\s+[0-9]+\s+IN\s+A\s+" | awk '{print $5}' | head -1) + fi + + if [[ "$current_ip" == "$EXTERNAL_IP" ]]; then + return 0 # No update needed - silent success + else + if [[ -n "$current_ip" ]]; then + log_change "PowerDNS A record for $display_name needs update: $current_ip -> $EXTERNAL_IP" + else + log_change "PowerDNS A record for $display_name does not exist, creating with IP: $EXTERNAL_IP" + fi + return 1 # Update needed + fi +} + +update_powerdns_record() { + local domain="$1" + local record_type="$2" # "@" for root, "*" for wildcard + local display_name="$3" + + log_info "Updating PowerDNS A record for $display_name..." + + if pdnsutil replace-rrset "$domain" "$record_type" A "$TTL" "$EXTERNAL_IP" 2>/dev/null; then + log_success "PowerDNS A record updated for $display_name" + log_history "PowerDNS $display_name updated: -> $EXTERNAL_IP" + pdnsutil rectify-zone "$domain" 2>/dev/null + pdnsutil increase-serial "$domain" 2>/dev/null + return 0 + else + log_error "Failed to update PowerDNS A record for $display_name" + return 1 + fi +} + +check_internal_dns() { + local needs_update=false + local needs_logging=false + + for domain in $POWERDNS_DOMAINS; do + # Ensure zone exists (this might need logging) + if ! pdnsutil list-zone "$domain" >/dev/null 2>&1; then + if [[ "$needs_logging" == "false" ]]; then + log_info "Checking PowerDNS A records..." + needs_logging=true + fi + log_info "Zone $domain does not exist, creating..." + log_history "PowerDNS $domain zone created" + pdnsutil create-zone "$domain" + needs_update=true + fi + + # Check root A record + if ! check_powerdns_record "$domain" "@" "$domain"; then + if [[ "$needs_logging" == "false" ]]; then + log_info "Checking PowerDNS A records..." + needs_logging=true + fi + needs_update=true + fi + + # Check wildcard A record + if ! check_powerdns_record "$domain" "*" "*.${domain}"; then + if [[ "$needs_logging" == "false" ]]; then + log_info "Checking PowerDNS A records..." + needs_logging=true + fi + needs_update=true + fi + done + + if [[ "$needs_update" == "true" ]]; then + return 1 # Update needed + else + return 0 # No update needed - was completely silent + fi +} + +update_internal_dns() { + log_info "Updating PowerDNS records..." + + for domain in $POWERDNS_DOMAINS; do + log_info "Processing zone $domain..." + + # Ensure zone exists + if ! pdnsutil list-zone "$domain" >/dev/null 2>&1; then + log_info "Zone $domain does not exist, creating..." + log_history "PowerDNS $domain zone created" + pdnsutil create-zone "$domain" + fi + + # Update root A record if needed + if ! check_powerdns_record "$domain" "@" "$domain"; then + update_powerdns_record "$domain" "@" "$domain" + fi + + # Update wildcard A record if needed + if ! check_powerdns_record "$domain" "*" "*.${domain}"; then + update_powerdns_record "$domain" "*" "*.${domain}" + fi + done +} + +# ============================================================================ +# MAIN EXECUTION +# ============================================================================ + +main() { + # Check if IP changed + if ! check_ip_change; then + # IP unchanged - check if DNS is consistent + local external_needs_update=false + local internal_needs_update=false + + if ! check_external_dns; then + external_needs_update=true + fi + + if ! check_internal_dns; then + internal_needs_update=true + fi + + # If everything is consistent, exit silently + if [[ "$external_needs_update" == "false" && "$internal_needs_update" == "false" ]]; then + exit 0 + fi + + # If we reach here, something needs fixing + log_info "External IP: $EXTERNAL_IP" + log_info "No IP change detected, but DNS inconsistencies found" + + if [[ "$external_needs_update" == "true" ]]; then + update_external_dns + fi + + if [[ "$internal_needs_update" == "true" ]]; then + update_internal_dns + fi + else + # IP changed - do full update + log_info "Starting DDNS check/update process" + + # Check and update external DNS (Infomaniak) + if ! check_external_dns; then + update_external_dns + fi + + # Check and update internal DNS (PowerDNS) + if ! check_internal_dns; then + update_internal_dns + fi + fi + + log_info "DDNS check/update completed" + + # Show recent IP history summary + if [[ -f "$IP_HISTORY_FILE" ]]; then + log_info "Recent changes (last 100):" + tail -100 "$IP_HISTORY_FILE" | grep -E "(change:|created:|updated:)" || log_info "No recent changes" + fi +} + +# Run main function +main