Last active
March 7, 2025 20:29
-
-
Save leodido/1dfbbc19139c2c3d1a8fd31bff39671d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -eu | |
# Define variables | |
INSTALL_DIR="/usr/local/bin" | |
NAME="update_cloudflare_ips" | |
SCRIPT_NAME="$NAME.sh" | |
SCRIPT_PATH="$INSTALL_DIR/$SCRIPT_NAME" | |
SERVICE_FILE="/etc/systemd/system/$NAME.service" | |
TIMER_FILE="/etc/systemd/system/$NAME.timer" | |
DATA_DIR="/var/lib/$NAME" | |
LOG_FILE="/var/log/$NAME.log" | |
# Create the data directory | |
echo "Creating data directory at $DATA_DIR..." | |
sudo mkdir -p "$DATA_DIR" | |
sudo chown root:root "$DATA_DIR" | |
sudo chmod 700 "$DATA_DIR" | |
# Create the log directory if it doesn't exist | |
echo "Creating log directory for $LOG_FILE..." | |
sudo mkdir -p "$(dirname "$LOG_FILE")" | |
sudo touch "$LOG_FILE" | |
sudo chown root:root "$LOG_FILE" | |
sudo chmod 600 "$LOG_FILE" | |
# Create update_cloudflare_ips.sh script with logging | |
cat << EOF | sudo tee "$SCRIPT_PATH" > /dev/null | |
#!/usr/bin/env bash | |
set -eu | |
LOG_FILE="$LOG_FILE" | |
DATA_DIR="$DATA_DIR" | |
# Ensure log directory exists | |
mkdir -p "\$(dirname "\$LOG_FILE")" | |
# Function to ensure file ends with a newline | |
ensure_trailing_newline() { | |
local file=\$1 | |
# Check if the file ends with a newline | |
if [[ -n \$(tail -c 1 "\$file") ]]; then | |
# If the last character is not a newline, append one | |
echo "" >> "\$file" | |
fi | |
} | |
# Function to apply UFW rules | |
add_ufw_rules() { | |
local ip_list_file=\$1 | |
local proto=\$2 | |
while IFS= read -r ip; do | |
echo "Adding UFW rule: allow \$ip on port 443 proto \$proto" | tee -a "\$LOG_FILE" | |
ufw allow from "\$ip" to any port 443 proto "\$proto" || echo "Failed to add rule for \$ip" >> "\$LOG_FILE" | |
done < "\$ip_list_file" | |
} | |
# Function to remove UFW rules | |
remove_ufw_rules() { | |
local ip_list_file=\$1 | |
local proto=\$2 | |
while IFS= read -r ip; do | |
echo "Removing UFW rule: allow \$ip on port 443 proto \$proto" | tee -a "\$LOG_FILE" | |
ufw delete allow from "\$ip" to any port 443 proto "\$proto" || echo "Failed to remove rule for \$ip" >> "\$LOG_FILE" | |
done < "\$ip_list_file" | |
} | |
# Function to update UFW rules from the given URL | |
update_ufw_from_url() { | |
local url=\$1 | |
local current_ips_file=\$2 | |
local previous_ips_file=\$3 | |
local proto=\$4 | |
echo "Updating from URL: \$url" | tee -a "\$LOG_FILE" | |
curl -s "\$url" -o "\$current_ips_file" | |
# Ensure file ends with a newline | |
ensure_trailing_newline "\$current_ips_file" | |
# Add new IPs first | |
add_ufw_rules "\$current_ips_file" "\$proto" | |
# Remove old IPs that are not in the new list | |
if [[ -f \$previous_ips_file ]]; then | |
ensure_trailing_newline "\$previous_ips_file" | |
local ips_to_remove | |
ips_to_remove="\$(mktemp)" | |
comm -23 <(sort "\$previous_ips_file") <(sort "\$current_ips_file") > "\$ips_to_remove" | |
remove_ufw_rules "\$ips_to_remove" "\$proto" | |
rm "\$ips_to_remove" | |
fi | |
# Backup current IPs as previous IPs for the next run | |
mv "\$current_ips_file" "\$previous_ips_file" | |
} | |
# Update both IPv4 and IPv6 | |
update_ufw_from_url "https://www.cloudflare.com/ips-v4" "\$DATA_DIR/current_ips_v4.txt" "\$DATA_DIR/previous_ips_v4.txt" "tcp" | |
update_ufw_from_url "https://www.cloudflare.com/ips-v6" "\$DATA_DIR/current_ips_v6.txt" "\$DATA_DIR/previous_ips_v6.txt" "tcp" | |
EOF | |
# Make the script executable | |
echo "Setting execute permissions for $SCRIPT_PATH..." | |
sudo chmod +x "$SCRIPT_PATH" | |
# Create systemd service file | |
echo "Writing systemd service file: $SERVICE_FILE..." | |
cat << EOF | sudo tee "$SERVICE_FILE" > /dev/null | |
[Unit] | |
Description=Update Cloudflare IPs in UFW | |
[Service] | |
ExecStart=$SCRIPT_PATH | |
[Install] | |
WantedBy=multi-user.target | |
EOF | |
# Create systemd timer file | |
echo "Writing systemd timer file: $TIMER_FILE..." | |
cat << EOF | sudo tee "$TIMER_FILE" > /dev/null | |
[Unit] | |
Description=Run $NAME.service daily | |
[Timer] | |
OnCalendar=daily | |
Persistent=true | |
[Install] | |
WantedBy=timers.target | |
EOF | |
# Reload systemd daemon to recognize our new service and timer | |
echo "Reloading systemd daemon..." | |
sudo systemctl daemon-reload | |
# Enable the systemd timer | |
echo "Enabling systemd timer..." | |
sudo systemctl enable $NAME.timer | |
echo "Installation complete. You can now start the timer using: sudo systemctl start $NAME.timer" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment