Files
wgtool/validate_config.sh
2026-03-22 00:54:58 -07:00

295 lines
8.3 KiB
Bash
Executable File

#!/bin/bash
# WireGuard Configuration Validator
# This script validates WireGuard configuration files for common issues
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_status() {
echo -e "${GREEN}[PASS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
print_error() {
echo -e "${RED}[FAIL]${NC} $1"
}
print_header() {
echo -e "${BLUE}================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}================================${NC}"
}
# Function to validate IP address format
validate_ip() {
local ip=$1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
return 0
else
return 1
fi
}
# Function to validate port number
validate_port() {
local port=$1
if [[ $port =~ ^[0-9]+$ ]] && [ $port -ge 1 ] && [ $port -le 65535 ]; then
return 0
else
return 1
fi
}
# Function to validate WireGuard key format
validate_wg_key() {
local key=$1
# WireGuard keys are base64 encoded and typically 44 characters long
if [[ $key =~ ^[A-Za-z0-9+/]{43}=$ ]]; then
return 0
else
return 1
fi
}
# Function to validate endpoint format
validate_endpoint() {
local endpoint=$1
if [[ $endpoint =~ ^[a-zA-Z0-9.-]+:[0-9]+$ ]]; then
return 0
else
return 1
fi
}
# Function to validate a single configuration file
validate_config_file() {
local config_file=$1
local errors=0
local warnings=0
print_header "Validating: $config_file"
if [ ! -f "$config_file" ]; then
print_error "Configuration file not found: $config_file"
return 1
fi
# Check file permissions
local perms=$(stat -c %a "$config_file")
if [ "$perms" != "600" ]; then
print_warning "File permissions should be 600, current: $perms"
((warnings++))
fi
# Parse the configuration file
local in_interface=0
local in_peer=0
local has_interface=0
local has_private_key=0
local has_address=0
local peer_count=0
while IFS= read -r line; do
# Skip comments and empty lines
if [[ $line =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then
continue
fi
# Check for Interface section
if [[ $line =~ ^\[Interface\] ]]; then
in_interface=1
in_peer=0
has_interface=1
continue
fi
# Check for Peer section
if [[ $line =~ ^\[Peer\] ]]; then
in_interface=0
in_peer=1
((peer_count++))
continue
fi
# Parse Interface section
if [ $in_interface -eq 1 ]; then
if [[ $line =~ ^PrivateKey[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local private_key="${BASH_REMATCH[1]}"
if validate_wg_key "$private_key"; then
print_status "Valid private key found"
has_private_key=1
else
print_error "Invalid private key format"
((errors++))
fi
elif [[ $line =~ ^Address[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local address="${BASH_REMATCH[1]}"
if validate_ip "$address"; then
print_status "Valid address: $address"
has_address=1
else
print_error "Invalid address format: $address"
((errors++))
fi
elif [[ $line =~ ^ListenPort[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local port="${BASH_REMATCH[1]}"
if validate_port "$port"; then
print_status "Valid listen port: $port"
else
print_error "Invalid listen port: $port"
((errors++))
fi
fi
fi
# Parse Peer section
if [ $in_peer -eq 1 ]; then
if [[ $line =~ ^PublicKey[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local public_key="${BASH_REMATCH[1]}"
if validate_wg_key "$public_key"; then
print_status "Valid peer public key"
else
print_error "Invalid peer public key format"
((errors++))
fi
elif [[ $line =~ ^AllowedIPs[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local allowed_ips="${BASH_REMATCH[1]}"
# Split multiple IPs if present
IFS=',' read -ra IP_ARRAY <<< "$allowed_ips"
for ip in "${IP_ARRAY[@]}"; do
ip=$(echo "$ip" | xargs) # Trim whitespace
if validate_ip "$ip"; then
print_status "Valid allowed IP: $ip"
else
print_error "Invalid allowed IP format: $ip"
((errors++))
fi
done
elif [[ $line =~ ^Endpoint[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local endpoint="${BASH_REMATCH[1]}"
if validate_endpoint "$endpoint"; then
print_status "Valid endpoint: $endpoint"
else
print_error "Invalid endpoint format: $endpoint"
((errors++))
fi
elif [[ $line =~ ^PersistentKeepalive[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local keepalive="${BASH_REMATCH[1]}"
if validate_port "$keepalive"; then
print_status "Valid persistent keepalive: $keepalive"
else
print_error "Invalid persistent keepalive: $keepalive"
((errors++))
fi
fi
fi
done < "$config_file"
# Check required fields
if [ $has_interface -eq 0 ]; then
print_error "Missing [Interface] section"
((errors++))
fi
if [ $has_private_key -eq 0 ]; then
print_error "Missing PrivateKey in [Interface] section"
((errors++))
fi
if [ $has_address -eq 0 ]; then
print_error "Missing Address in [Interface] section"
((errors++))
fi
if [ $peer_count -eq 0 ]; then
print_warning "No [Peer] sections found"
((warnings++))
fi
# Summary
echo ""
if [ $errors -eq 0 ] && [ $warnings -eq 0 ]; then
print_status "Configuration file is valid!"
return 0
elif [ $errors -eq 0 ]; then
print_warning "Configuration file has $warnings warning(s)"
return 0
else
print_error "Configuration file has $errors error(s) and $warnings warning(s)"
return 1
fi
}
# Function to validate all config files in a directory
validate_directory() {
local dir=$1
local total_errors=0
local total_files=0
print_header "Validating all config files in: $dir"
if [ ! -d "$dir" ]; then
print_error "Directory not found: $dir"
return 1
fi
for config_file in "$dir"/*.conf; do
if [ -f "$config_file" ]; then
((total_files++))
if ! validate_config_file "$config_file"; then
((total_errors++))
fi
echo ""
fi
done
if [ $total_files -eq 0 ]; then
print_warning "No .conf files found in $dir"
else
print_header "Validation Summary"
echo "Total files: $total_files"
echo "Files with errors: $total_errors"
echo "Files without errors: $((total_files - total_errors))"
fi
}
# Show usage
show_usage() {
echo "Usage: $0 [OPTIONS] <config_file_or_directory>"
echo ""
echo "Options:"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 wireguard_configs/test.conf # Validate single file"
echo " $0 wireguard_configs/ # Validate all files in directory"
echo " $0 TESTING/ # Validate TESTING directory"
}
# Main logic
if [ $# -eq 0 ] || [[ $1 =~ ^- ]]; then
show_usage
exit 0
fi
target=$1
if [ -f "$target" ]; then
validate_config_file "$target"
elif [ -d "$target" ]; then
validate_directory "$target"
else
print_error "Target not found: $target"
exit 1
fi