mirror of
https://codeberg.org/shm0rt/ddns-pdns-updater.git
synced 2025-07-29 05:29:07 +02:00
added testfile
This commit is contained in:
parent
def723b223
commit
fda7113382
2 changed files with 587 additions and 88 deletions
358
pdns-ddns
358
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
|
||||
|
|
317
pdns-ddns-test
Normal file
317
pdns-ddns-test
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue