|
#!/bin/sh |
|
|
|
# ============================================================================== |
|
# VPN Director - Cloudflare CIDR Updater |
|
# |
|
# This script automatically fetches the latest Cloudflare IPv4 CIDRs, |
|
# compares them against the currently configured rules in VPN Director, |
|
# and updates the rule list if any changes are detected. |
|
# |
|
# It correctly parses and generates the concatenated rule format. |
|
# Designed for POSIX-compliant shells (e.g., ash on BusyBox). |
|
# ============================================================================== |
|
|
|
# --- Configuration --- |
|
readonly RULE_PREFIX="Cloudflare v4_" |
|
readonly VPN_CLIENT_ID="WGC2" |
|
readonly RULES_FILE="/jffs/openvpn/vpndirector_rulelist" |
|
readonly LOCAL_SUBNET="" # (Optional) Specify a subnet (e.g., 192.168.1.0/24) or a single IP address to restrict the Cloudflare rules to a specific local network segment or client. |
|
# Leave empty ("") to apply the rules to ALL clients on the router. |
|
# Example: LOCAL_SUBNET="192.168.1.0/24" will only route traffic from this subnet through the VPN for Cloudflare IPs. |
|
# Use for testing |
|
#readonly RULES_FILE="./vpndirector_rulelist" |
|
|
|
# --- Script Logic --- |
|
set -e |
|
set -u |
|
set -o pipefail |
|
|
|
readonly TEMP_DIR="/tmp/cf_updater_$$" |
|
mkdir "$TEMP_DIR" |
|
trap 'rm -rf -- "$TEMP_DIR"' EXIT |
|
|
|
readonly NEW_CIDRS_FILE="$TEMP_DIR/cloudflare_cidrs_new.txt" |
|
readonly OLD_CIDRS_FILE="$TEMP_DIR/cloudflare_cidrs_old.txt" |
|
readonly NEW_CF_RULES_FILE="$TEMP_DIR/cloudflare_rules_new.txt" |
|
readonly OLD_CF_RULES_FILE="$TEMP_DIR/cloudflare_rules_old.txt" |
|
|
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "INFO: Starting Cloudflare CIDR update process." |
|
|
|
# Step 1: Fetch the latest Cloudflare IPv4 CIDRs. |
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "INFO: Fetching latest Cloudflare IPv4 CIDRs..." |
|
if ! curl -s "https://api.cloudflare.com/client/v4/ips" | jq -r '.result.ipv4_cidrs[]' > "$NEW_CIDRS_FILE"; then |
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.error "ERROR: Failed to fetch or parse Cloudflare IPs. Exiting." |
|
exit 1 |
|
fi |
|
|
|
if [ ! -s "$NEW_CIDRS_FILE" ]; then |
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.error "ERROR: Fetched CIDR list is empty. Exiting." |
|
exit 1 |
|
fi |
|
|
|
# Step 2: Extract currently configured Cloudflare rules block. |
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "INFO: Extracting existing Cloudflare rules from $RULES_FILE..." |
|
if [ -f "$RULES_FILE" ] && [ -s "$RULES_FILE" ]; then |
|
# Extract the full Cloudflare rules block (not just CIDRs) |
|
awk -F'>' -v prefix="^${RULE_PREFIX}" 'BEGIN{RS="<"; ORS=""} NF>0 && $2 ~ prefix {print "<"$0}' "$RULES_FILE" > "$OLD_CF_RULES_FILE" |
|
else |
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "INFO: Rules file does not exist or is empty. Will create it." |
|
: > "$OLD_CF_RULES_FILE" |
|
fi |
|
|
|
# Step 3: Generate the new block of Cloudflare rules. |
|
NEW_CLOUDFLARE_RULES_BLOCK="" |
|
counter=0 |
|
while IFS= read -r cidr; do |
|
label="${RULE_PREFIX}${counter}" |
|
NEW_CLOUDFLARE_RULES_BLOCK="${NEW_CLOUDFLARE_RULES_BLOCK}<1>${label}>${LOCAL_SUBNET}>${cidr}>${VPN_CLIENT_ID}" |
|
counter=$((counter + 1)) |
|
done < "$NEW_CIDRS_FILE" |
|
echo -n "$NEW_CLOUDFLARE_RULES_BLOCK" > "$NEW_CF_RULES_FILE" |
|
|
|
# Step 4: Compare the new and existing Cloudflare rules blocks. |
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "INFO: Comparing new and existing Cloudflare rules block..." |
|
if cmp -s "$OLD_CF_RULES_FILE" "$NEW_CF_RULES_FILE"; then |
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "INFO: No changes detected in Cloudflare rules. No update necessary. Exiting." |
|
exit 0 |
|
fi |
|
|
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "INFO: Changes detected. Proceeding with rule update." |
|
|
|
# Step 5: Extract all non-Cloudflare rules. |
|
CUSTOM_RULES_BLOCK="" |
|
if [ -f "$RULES_FILE" ] && [ -s "$RULES_FILE" ]; then |
|
CUSTOM_RULES_BLOCK=$(awk -F'>' -v prefix="^${RULE_PREFIX}" 'BEGIN{RS="<"; ORS=""} NF>0 && $2 !~ prefix {print "<"$0}' "$RULES_FILE") |
|
fi |
|
|
|
# Step 6: Combine custom rules with the new Cloudflare rules by simple concatenation. |
|
FINAL_RULE_LIST="${CUSTOM_RULES_BLOCK}${NEW_CLOUDFLARE_RULES_BLOCK}" |
|
|
|
# Step 7: Atomically update the rule list and apply changes. |
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "INFO: Writing new rules to $RULES_FILE and applying changes." |
|
echo -n "$FINAL_RULE_LIST" > "$RULES_FILE.tmp" |
|
mv "$RULES_FILE.tmp" "$RULES_FILE" |
|
service restart_vpndirector |
|
|
|
logger -sc -t "Cloudflare CIDR VPN Director Updater" -p user.notice "SUCCESS: VPN Director rules updated successfully." |
|
exit 0 |
В VPN Director попробуйте принудительно выбрать WG туннель для конкретного устройства