first commit
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
# Cloudflare DNS Updater
|
||||
|
||||
A Bash script that automatically updates Cloudflare DNS A records with your current public IP address. This script demonstrates various advanced Bash programming features while providing a practical tool for dynamic DNS management.
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic IP Detection**: Retrieves current public IP using external services
|
||||
- **Multi-Domain Support**: Manages DNS records for multiple domains simultaneously
|
||||
- **Smart Updates**: Only updates records when IP changes to avoid unnecessary API calls
|
||||
- **Orphaned Record Cleanup**: Automatically removes unmanaged DNS records
|
||||
- **Protected Records**: Prevents deletion of critical DNS records
|
||||
- **Dry Run Mode**: Test changes without actually modifying DNS records
|
||||
- **Comprehensive Logging**: Detailed output showing all operations performed
|
||||
|
||||
## Bash Features Demonstrated
|
||||
|
||||
This script showcases the following Bash programming features:
|
||||
|
||||
### 1. **Shebang and Script Structure**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
```
|
||||
Proper script initialization with bash interpreter specification.
|
||||
|
||||
### 2. **Variable Declarations and Constants**
|
||||
```bash
|
||||
TOKEN=""
|
||||
AUTO_DELETE_ORPHANS=true
|
||||
DRY_RUN=false
|
||||
```
|
||||
Use of string constants and boolean flags for configuration.
|
||||
|
||||
### 3. **Associative Arrays**
|
||||
```bash
|
||||
declare -A d0 d1 # Declare associative arrays for domain configuration
|
||||
d0=(
|
||||
["domain"]=""
|
||||
["zone_id"]=""
|
||||
["subdomains"]="@,"
|
||||
["protected_records"]=""
|
||||
)
|
||||
```
|
||||
Key-value data structures for complex domain configurations.
|
||||
|
||||
### 4. **Indexed Arrays**
|
||||
```bash
|
||||
declare -a domains # Declare indexed array to hold domain references
|
||||
domains=( d0 d1 )
|
||||
```
|
||||
Ordered collections for managing multiple domains.
|
||||
|
||||
### 5. **Array References (Namerefs)**
|
||||
```bash
|
||||
declare -n domain="$item" # Create reference to associative array
|
||||
echo "${domain[domain]}" # Access array elements through reference
|
||||
```
|
||||
Dynamic array referencing for flexible data access.
|
||||
|
||||
### 6. **Functions**
|
||||
```bash
|
||||
get_current_ip() {
|
||||
curl -s https://ifconfig.me/ip
|
||||
}
|
||||
|
||||
create_dns_record() {
|
||||
local zone_id="$1"
|
||||
local data="$2"
|
||||
# Function implementation
|
||||
}
|
||||
```
|
||||
Modular code organization with local variables and parameters.
|
||||
|
||||
### 7. **Advanced Conditional Statements**
|
||||
```bash
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
echo "⚠️ DRY RUN MODE ENABLED"
|
||||
fi
|
||||
|
||||
if [[ -n "${existing_a_records[$full_name]}" ]]; then
|
||||
# Record exists logic
|
||||
fi
|
||||
```
|
||||
String comparison, variable existence checks, and complex conditions.
|
||||
|
||||
### 8. **Loop Constructs**
|
||||
```bash
|
||||
for item in "${domains[@]}"; do
|
||||
# Process each domain
|
||||
done
|
||||
|
||||
for subdomain in "${managed_subdomains[@]}"; do
|
||||
# Process each subdomain
|
||||
done
|
||||
```
|
||||
Iteration over arrays with proper quoting.
|
||||
|
||||
### 9. **String Manipulation and Parsing**
|
||||
```bash
|
||||
IFS=',' read -ra protected_records <<< "${domain[protected_records]}"
|
||||
IFS=',' read -ra managed_subdomains <<< "${domain[subdomains]}"
|
||||
```
|
||||
Field splitting and array population from comma-separated strings.
|
||||
|
||||
### 10. **Command and Process Substitution**
|
||||
```bash
|
||||
current_ip=$(get_current_ip) # Command substitution
|
||||
|
||||
done < <(echo "$response" | jq -c '.result[] | select(.type == "A")') # Process substitution
|
||||
```
|
||||
Capturing command output and feeding output to loops.
|
||||
|
||||
### 11. **JSON Processing with jq**
|
||||
```bash
|
||||
if echo "$response" | jq -e '.success == false' > /dev/null 2>&1; then
|
||||
echo "Error: Failed to get DNS records"
|
||||
fi
|
||||
|
||||
create_data=$(jq -n \
|
||||
--arg name "$full_name" \
|
||||
--arg ip "$current_ip" \
|
||||
'{
|
||||
"type": "A",
|
||||
"name": $name,
|
||||
"content": $ip,
|
||||
"ttl": 1,
|
||||
"proxied": true
|
||||
}')
|
||||
```
|
||||
Parsing JSON responses and constructing JSON payloads.
|
||||
|
||||
### 12. **Error Handling and Exit Codes**
|
||||
```bash
|
||||
if [ -z "$current_ip" ]; then
|
||||
echo "Error: Could not retrieve current IP"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
Input validation and controlled script termination.
|
||||
|
||||
### 13. **Arithmetic Operations**
|
||||
```bash
|
||||
((records_created++))
|
||||
((records_updated++))
|
||||
((records_skipped++))
|
||||
((records_deleted++))
|
||||
```
|
||||
Counter variables for operation statistics.
|
||||
|
||||
### 14. **API Integration with curl**
|
||||
```bash
|
||||
curl -s "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records" \
|
||||
-X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d "$data"
|
||||
```
|
||||
REST API calls with proper headers and data payloads.
|
||||
|
||||
### 15. **Dynamic Variable Management**
|
||||
```bash
|
||||
unset existing_a_records # Clean up associative arrays
|
||||
unset domain # Clean up nameref
|
||||
```
|
||||
Memory management and variable cleanup.
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Configure Domains**: Edit the domain arrays at the top of the script
|
||||
2. **Set API Token**: Update the `TOKEN` variable with your Cloudflare API token
|
||||
3. **Dry Run First**: Test with `DRY_RUN=true` to see what would change
|
||||
4. **Run Updates**: Set `DRY_RUN=false` to apply actual changes
|
||||
|
||||
```bash
|
||||
# Dry run (safe testing)
|
||||
./update_domain.sh
|
||||
|
||||
# Apply changes
|
||||
# Edit script: DRY_RUN=false
|
||||
./update_domain.sh
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Domain Configuration Structure
|
||||
Each domain is configured as an associative array with:
|
||||
- `domain`: The root domain name
|
||||
- `zone_id`: Cloudflare zone identifier
|
||||
- `subdomains`: Comma-separated list of subdomains to manage
|
||||
- `protected_records`: Records that should never be deleted
|
||||
|
||||
### Script Parameters
|
||||
- `TOKEN`: Cloudflare API bearer token
|
||||
- `AUTO_DELETE_ORPHANS`: Whether to remove unmanaged records
|
||||
- `DRY_RUN`: Test mode without making actual changes
|
||||
|
||||
## Requirements
|
||||
|
||||
- Bash 4.0+
|
||||
- curl
|
||||
- jq
|
||||
- Valid Cloudflare API token with DNS edit permissions
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Store API tokens securely (consider environment variables)
|
||||
- Use dry run mode when testing
|
||||
- Review protected records configuration carefully
|
||||
- Monitor script output for any API errors
|
||||
|
||||
## Output Example
|
||||
|
||||
```
|
||||
⚠️ DRY RUN MODE ENABLED - No actual changes will be made
|
||||
=========================================
|
||||
Current Public IP: 203.0.113.1
|
||||
=========================================
|
||||
Processing domain: my-dev.pro
|
||||
Zone ID: 5c9a19af6aeababb78b294844290a7d2
|
||||
Managed subdomains: @ git
|
||||
----------------------------------------
|
||||
Existing A records:
|
||||
- my-dev.pro → 203.0.113.1 (ID: abc123)
|
||||
- git.my-dev.pro → 203.0.113.1 (ID: def456)
|
||||
----------------------------------------
|
||||
Checking: my-dev.pro
|
||||
✓ SKIPPED: IP unchanged (203.0.113.1 = 203.0.113.1)
|
||||
Checking: git.my-dev.pro
|
||||
✓ SKIPPED: IP unchanged (203.0.113.1 = 203.0.113.1)
|
||||
=========================================
|
||||
SUMMARY for my-dev.pro:
|
||||
✓ Created: 0
|
||||
✓ Updated: 0
|
||||
✓ Skipped (IP unchanged): 2
|
||||
✓ Deleted: 0
|
||||
=========================================
|
||||
⚠️ DRY RUN COMPLETED - No actual changes were made
|
||||
Set DRY_RUN=false to apply changes
|
||||
```
|
||||
Reference in New Issue
Block a user