Created
February 24, 2026 12:08
-
-
Save likema/2ab9678111784e31430059f76b77bd79 to your computer and use it in GitHub Desktop.
Update v2ray config IPs to preferred Cloudflare CDN addresses
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 | |
| # vim: set ts=4 sw=4 sts=4 et: | |
| set -euo pipefail | |
| V2RAY_CFG=/usr/local/etc/v2ray/config.json | |
| CFST_DIR=. | |
| DRY_RUN=false | |
| panic() { | |
| echo "Error: $*" >&2 | |
| exit 1 | |
| } | |
| usage() { | |
| cat <<EOF | |
| Usage: $0 [OPTIONS] [v2ray_cfg] | |
| Options: | |
| --cfst-dir <DIR> Directory containing cfst binary (default: .) | |
| -h, --help Show this help message | |
| v2ray_cfg Print commands only, do not modify config or restart v2ray | |
| EOF | |
| exit 1 | |
| } | |
| parse_args() { | |
| local parsed | |
| # shellcheck disable=SC2155 | |
| parsed=$(getopt -o h -l cfst-dir:,help -n "$0" -- "$@") | |
| eval set -- "$parsed" | |
| while true; do | |
| case "$1" in | |
| --cfst-dir) | |
| CFST_DIR=$2 | |
| shift 2 | |
| ;; | |
| -h|--help) | |
| usage | |
| ;; | |
| --) | |
| shift | |
| break | |
| ;; | |
| *) | |
| panic "Internal error" | |
| ;; | |
| esac | |
| done | |
| [[ -n "${1:-}" ]] || return 0 | |
| V2RAY_CFG=$1 | |
| DRY_RUN=true | |
| } | |
| get_origin_ips() { | |
| jq -r '.outbounds[].settings.vnext[0]?.address // empty' "$V2RAY_CFG" | |
| } | |
| get_current_ips() { | |
| local count=$1 | |
| (cd "$CFST_DIR" && ./cfst -p "$count" -o "") 2>/dev/null | sed -n '/^IP/,$ { | |
| /^IP/d | |
| s/\s\+.*//p | |
| }' | |
| } | |
| intersect() { | |
| local -n arr1=$1 | |
| local -n arr2=$2 | |
| local -n result=$3 | |
| for ip1 in "${arr1[@]}"; do | |
| for ip2 in "${arr2[@]}"; do | |
| [[ "$ip1" == "$ip2" ]] || continue | |
| # shellcheck disable=SC2034 | |
| result["$ip1"]=1 | |
| break | |
| done | |
| done | |
| } | |
| build_modify_map() { | |
| local -n origin_arr=$1 | |
| local -n current_arr=$2 | |
| local -n map=$3 | |
| local -A same | |
| intersect origin_arr current_arr same | |
| local i=0 | |
| for src in "${origin_arr[@]}"; do | |
| [[ -z "${same[$src]:-}" ]] || continue | |
| while [[ $i -lt ${#current_arr[@]} ]]; do | |
| local target="${current_arr[$i]}" | |
| ((++i)) | |
| [[ -z "${same[$target]:-}" ]] || continue | |
| # shellcheck disable=SC2034 | |
| map["$src"]=$target | |
| break | |
| done | |
| done | |
| } | |
| generate_sed_cmd() { | |
| local -n modify_arr=$1 | |
| for src in "${!modify_arr[@]}"; do | |
| echo "-e s/\"$src\"/\"${modify_arr[$src]}\"/" | |
| done | |
| } | |
| update_v2ray_cfg() { | |
| local cmd=$1 | |
| local opt="" | |
| $DRY_RUN || opt=-i | |
| # shellcheck disable=SC2086 | |
| sed $opt $cmd "$V2RAY_CFG" | |
| } | |
| restart_v2ray() { | |
| $DRY_RUN || systemctl restart v2ray | |
| } | |
| main() { | |
| parse_args "$@" | |
| command -v jq &>/dev/null || \ | |
| panic "Not found jq! Please apt install jq" | |
| [[ -x "$CFST_DIR/cfst" ]] || \ | |
| panic "cfst is not executable! Please download from https://github.com/XIU2/CloudflareSpeedTest" | |
| local -a origin | |
| mapfile -t origin < <(get_origin_ips) | |
| [[ ${#origin[@]} -gt 0 ]] || panic "Failed to get origin IPs from config" | |
| local -a current | |
| mapfile -t current < <(get_current_ips "${#origin[@]}") | |
| [[ ${#current[@]} -eq ${#origin[@]} ]] || \ | |
| panic "IP count mismatch: origin=${#origin[@]}, current=${#current[@]}" | |
| local -A modify | |
| build_modify_map origin current modify | |
| [[ ${#modify[@]} -gt 0 ]] || return 0 | |
| echo -n 'Modify v2ray config: ' | |
| for src in "${!modify[@]}"; do | |
| echo -n "$src -> ${modify[$src]} " | |
| done | |
| echo | |
| update_v2ray_cfg "$(generate_sed_cmd modify)" | |
| restart_v2ray | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment