Skip to content

Instantly share code, notes, and snippets.

@likema
Created February 24, 2026 12:08
Show Gist options
  • Select an option

  • Save likema/2ab9678111784e31430059f76b77bd79 to your computer and use it in GitHub Desktop.

Select an option

Save likema/2ab9678111784e31430059f76b77bd79 to your computer and use it in GitHub Desktop.
Update v2ray config IPs to preferred Cloudflare CDN addresses
#!/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