ВНИМАНИЕ! Авторы не несут ответственность за работоспособность, безопасность и стабильность ПО, представленного в инструкции. Все действия (прошивка / настройка роутера) выполняются пользователями с учетом данного факта
Сценарии использования:
Обеспечение приватности интернет-соединения всех или части устройств в LAN-сети
Обход региональных блокировок на всех или части устройств в LAN-сети
-
Реализация двойного VPN:
- VPN-провайдер № 1 (на роутере): видит IP клиента, но не видит IP посещаемых ресурсов
- VPN-провайдер № 2 (на клиентских устройствах): видит IP посещаемых ресурсов, но не IP клиента
Требования:
-
Роутер c OpenWRT
Варианты:
Приобретение роутера с предустановленной OpenWRT (например, на маркетплейсах)
Самостоятельная установка OpenWRT на совместимый роутер. Таблица поддерживаемых устройств c инструкциями по установке: https://toh.openwrt.org
Личный VPN или подписка на коммерческий VPN, использующий протокол VLESS
1. Сброс до заводских настроек
Сброс роутера до настроек по-умолчанию удалит несовместимое с Passwall ПО при его наличии (другие VPN-клиенты, программы для анализа трафика, DoH- и DoT-конфигурации и т.д.) и временные файлы:
-
Подключиться по кабелю к LAN-порту роутера с компьютера (после сброса точка доступа WiFi может быть в выключенном состоянии), ввести локальный IP роутера (обычно, 192.168.0.1, 192.168.1.1) в браузере, после чего прописать пароль от роутера (при наличии)

-
Нажать на кнопку Perform reset в System - Backup/Flash Firmware и подтвердить сброс. В течение пары минут роутер перезагрузится и сбросится до изначального состояния

2. Настройка доступа в Интернет
Если после сброса доступ в интернет не появится, настроить WAN-интерфейс по инструкции от интернет-провайдера:
Ввести предложенные провайдером или прописанные в договоре об оказании услуг связи IP, шлюз по-умолчанию и DNS-сервера в настройках WAN-интерфейса (Network - Interfaces - Interfaces - WAN). Перезагрузить роутер
-
Если провайдер реализует фильтрацию по MAC-адресу, изменить MAC-адрес WAN-интерфейса в Network - Interfaces - Devices - WAN - Configure на представленный в личном кабинете провайдера, договоре или чате с технической поддержкой. Перезагрузить роутер и проверить подключение к интернету на клиентских устройствах

3. Установка Passwall
Passwall - программное обеспечение, позволяющее настроить VPN-подключение (в том числе и по протоколу VLESS) на роутере. Шаги установки:
-
Подключиться к роутеру по ssh и ввести пароль от роутера (при наличии):
- На Windows использовать ssh-клиент PuTTY: https://putty.org/
- На macOS и Linux ввести в терминал:
ssh root@router_ip # заменить router_ip на локальный IP роутера
-
Выполнить команду, загружающую, разрешающую исполнение и запускающую скрипт по установке Passwall:
rm -fpasswallx.sh&& wgethttps://raw.githubusercontent.com/amirhosseinchoghaei/Passwall/main/passwallx.sh&& chmod 777passwallx.sh&& shpasswallx.sh
-
Выбрать Вариант 1 (если объем оперативной памяти роутера меньше 256МБ) или Вариант 2 (если объем оперативной памяти роутера больше 256МБ)

-
Дождаться окончания установки Passwall и перезагрузить роутер

-
(Опционально) Если после выполнения скрипта название роутера (hostname) изменилось, вернуть его обратно :
uci set system.@system[0].hostname = "Name" # заменить Name на желаемое названиеuci commit systemecho $(uci get system.@system[0].hostname) > /proc/sys/kernel/hostnamereboot
После этих действий файл hostname должен содержать новое название, которое также будет отображаться в веб-интерфейсе OpenWRT:
cat /proc/sys/kernel/hostname Проверить наличие нового меню Services - Passwall в веб-интерфейсе роутера
4. Настройка Passwall
-
Добавить подписку на VPN в Services - Passwall - Node Subscribe - Add, введя название подписки в поле Subscribe Remark и ссылку, предоставленную VPN-провайдером, в поле Subscribe URL

-
Произвести подписку вручную, нажав на Manual Subscription в Services - Passwall - Node Subscribe и дождаться окончания процесса. Список VPN-серверов с возможностью проверить их Пинг отобразится в Services - Passwall - Node List


Логи Passwall после добавления/обновления подписки (Services - Passwall - Watch Logs) -
Выбрать локацию / сервер в Services - Passwall - Basic Settings - Main - Node и поставить галочку рядом с Main switch для подключения к VPN. После успешного подключения рядом с пунктом Core появится зеленая надпись RUNNING.

Главное окно Passwall, в котором можно включить/выключить VPN, выбрать сервер для подключения и проверить пинг Проверить публичный IP на клиентских устройствах (например, на https://whatismyipaddress.com или curl ip.me в терминале) - отобразится IP VPN-сервиса
5. Добавление устройств в исключения Passwall
Отключить рандомизацию MAC-адреса при каждом переподключении к сети на клиентском устройстве, трафик которого должен идти в обход VPN. Например, в настройках Wi-Fi на Android и Linux с GNOME можно выбрать Стабильный MAC-адрес – для каждой WiFi-сети он будет разный, но меняться со временем внутри одной Wi-Fi-сети не будет
-
Нажать Add в Services - Passwall - ACL
- В поле Source выбрать MAC-адрес желаемого устройства
- В полях TCP No Redir Ports и UDP No Redir Ports выбрать All
- Нажать Save & Apply

-
В меню Services - Passwall - ACL поставить галочки напротив созданного правила и Main switch. Нажать Save & Apply. Проверить публичный IP-адрес на добавленных в этот список устройствах

Комментарии (11)

sohmstyle
27.03.2026 21:44Какие классные скрипты...
Автор, опишите, пожалуйста, что делает скрипт cdnopw.sh, который вызывается в passwallx.sh ?
Вы же изучили скрипты, правда? Не вслепую выпоняли все команды?
Derevtso
27.03.2026 21:44Этот файл можно деобфусцировать, но он и другой тащит внутри, мне уже лень было.
На https://cocalc.com в бесплатной песочнице потыкал палочкой: замена eval на printf, а потом сколько-то раз превратить внутренний base64 в текст.
Вот навайбкоженный скрипт деобфускации, он работает, в той же песочнице.unpack.sh
#!/bin/bash # unpack.sh — Распаковка: переменные + eval → цепочка base64 # Использование: ./unpack.sh <файл> [имя_вывода] set -e INPUT="${1:?Ошибка: укажите входной файл}" OUTPUT="${2:-unwrapped_final}" WORK_DIR=$(mktemp -d) echo "[*] Распаковка: $INPUT" echo "[*] Рабочая папка: $WORK_DIR" echo "========================================" # ------------------------------------------------------------- # ЭТАП 1: Раскрытие переменных (замена eval на printf) # ------------------------------------------------------------- echo "" echo "[ЭТАП 1/2] Раскрываем переменные..." cp "$INPUT" "$WORK_DIR/input.sh" # Находим строку с eval и заменяем eval на printf # Это заставит bash собрать строку из переменных и вывести её if grep -qE '^\s*eval\s+' "$WORK_DIR/input.sh"; then sed -E 's/^\s*eval\s+/printf "%s\\n" /' "$WORK_DIR/input.sh" > "$WORK_DIR/modified.sh" # Запускаем модифицированный скрипт, чтобы получить собранную строку # 2>/dev/null скрывает ошибки, так как после printf скрипт упадёт bash "$WORK_DIR/modified.sh" > "$WORK_DIR/layer1.txt" 2>/dev/null || true if [ -s "$WORK_DIR/layer1.txt" ]; then echo "[+] Переменные раскрыты" else echo "[!] Не удалось раскрыть переменные" exit 1 fi else echo "[+] eval не найден, копируем файл как есть" cp "$WORK_DIR/input.sh" "$WORK_DIR/layer1.txt" fi # ------------------------------------------------------------- # ЭТАП 2: Раскрутка base64 # ------------------------------------------------------------- echo "" echo "[ЭТАП 2/2] Раскручиваем base64..." cp "$WORK_DIR/layer1.txt" "$WORK_DIR/current.tmp" LAYER=0 MAX_LAYERS=20 while [ $LAYER -lt $MAX_LAYERS ]; do LAYER=$((LAYER + 1)) # Проверяем наличие base64 if ! grep -q 'base64' "$WORK_DIR/current.tmp" 2>/dev/null; then echo "[+] Слой $LAYER: base64 не найден — готово" break fi # Извлекаем base64 (удаляем всё, кроме символов кодировки) CONTENT=$(cat "$WORK_DIR/current.tmp" | tr -d '\n\r\t' | grep -oE '[A-Za-z0-9+/=]{100,}' | head -1) if [ -z "$CONTENT" ]; then echo "[!] Не удалось найти base64 на слое $LAYER" break fi echo "[*] Слой $LAYER: декодируем ${#CONTENT} символов..." # Декодируем if ! echo "$CONTENT" | base64 -d > "$WORK_DIR/next.tmp" 2>/dev/null; then echo "[!] Ошибка декодирования на слое $LAYER" break fi mv "$WORK_DIR/next.tmp" "$WORK_DIR/current.tmp" echo "[+] Слой $LAYER распакован" done # ------------------------------------------------------------- # ФИНАЛ: Сохранение # ------------------------------------------------------------- echo "" echo "[*] Сохранение результата..." if file "$WORK_DIR/current.tmp" | grep -q "ELF"; then mv "$WORK_DIR/current.tmp" "${OUTPUT}.bin" echo "[✓] Результат: ${OUTPUT}.bin (бинарник)" strings "${OUTPUT}.bin" 2>/dev/null | head -20 | sed 's/^/ /' elif file "$WORK_DIR/current.tmp" | grep -qE "script|ASCII|text"; then mv "$WORK_DIR/current.tmp" "${OUTPUT}.sh" echo "[✓] Результат: ${OUTPUT}.sh (скрипт)" head -30 "${OUTPUT}.sh" 2>/dev/null | sed 's/^/ /' else mv "$WORK_DIR/current.tmp" "${OUTPUT}.raw" echo "[✓] Результат: ${OUTPUT}.raw" fi rm -rf "$WORK_DIR" echo "" echo "[*] Готово!"Вот, если интересно cdnopw.sh.
cdnopw.sh
#!/bin/bash export LANG=en_US.UTF-8 case "$(uname -m)" in x86_64 | x64 | amd64 ) cpu=amd64 ;; i386 | i686 ) cpu=386 ;; armv8 | armv8l | arm64 | aarch64 ) cpu=arm64 ;; armv7l ) cpu=arm ;; mips64le ) cpu=mips64le ;; mips64 ) cpu=mips64 ;; mips ) cpu=mipsle ;; mipsle ) cpu=mipsle ;; * ) echo "当前架构为$(uname -m),暂不支持" exit ;; esac if [ ! -f ygop_update ]; then # 初始化包列表 packages="" # 创建一个包名数组和一个命令名数组 package_names=("bash" "jq" "wget" "curl" "sed" "unzip" "coreutils" "coreutils-timeout" "coreutils-base64") command_names=("bash" "jq" "wget" "curl" "sed" "unzip" "tr" "timeout" "base64") # 遍历命令名数组 for i in ${!command_names[@]}; do # 如果对应的命令没有安装,那么就把对应的包名添加到包列表中 if ! command -v ${command_names[$i]} &> /dev/null; then packages="$packages ${package_names[$i]}" fi done # 判断系统进行安装 if [ -n "$packages" ]; then echo "经检测,需要安装依赖: $packages" if cat /etc/issue /proc/version /etc/os-release 2>/dev/null | grep -q -E -i "alpine"; then apk update apk add $packages elif cat /etc/issue /proc/version /etc/os-release 2>/dev/null | grep -q -E -i "openwrt"; then opkg update opkg install $packages opkg install coreutils-timeout opkg install coreutils-base64 elif cat /etc/issue /proc/version /etc/os-release 2>/dev/null | grep -q -E -i "ubuntu|debian"; then sudo apt-get update -y sudo apt-get install $packages -y elif cat /etc/issue /proc/version /etc/os-release 2>/dev/null | grep -q -E -i "centos|red hat|redhat"; then sudo yum install $packages -y else echo "未能检测出你的系统:$(uname),请自行安装$packages这些软件。" exit 1 fi fi touch ygop_update fi v6=$(curl -s6m5 ip.gs -k) ipv6test(){ if [[ -n $v6 ]]; then echo "2:优选IPV6" else echo "2:无IPV6网络,请不要选择" fi } cdnv4v6(){ echo echo "1:优选IPV4" ipv6test read -p "请选择(回车默认为IPV4): " menu if [ -z $menu ] || [ "$menu" == "1" ]; then rm -rf ipv6.txt curl -s -O https://gitlab.com/rwkgyg/CFwarp/-/raw/main/point/cpu3/ip.txt IP_ADDR=ipv4 elif [ "$menu" == "2" ]; then if [[ -n $v6 ]]; then rm -rf ip.txt curl -s -O https://gitlab.com/rwkgyg/CFwarp/-/raw/main/point/cpu3/ipv6.txt IP_ADDR=ipv6 else echo "无IPV6网络" && cdnv4v6 fi else echo "输入有误" && cdnv4v6 fi } cdnport(){ echo echo "开启tls的端口:443、8443、2053、2083、2087、2096" echo "关闭tls的端口:80、8080、8880、2052、2082、2086、2095" read -p "请选择以上13个端口之一:" point if ! [[ "$point" =~ ^(2052|2082|2086|2095|80|8880|8080|2053|2083|2087|2096|8443|443)$ ]]; then echo "输入的端口为$opint,输入有误" && cdnport fi } cdnspedurl(){ echo echo "是否测速?(选择 1 表示测速,回车默认关闭测速)" read -p "请选择: " menu if [ -z $menu ]; then CFST_URL_R="" sed -i '29s/^CFST_SPD=.*/CFST_SPD=-dd/' /root/cfipopw/cdnip.sh elif [ "$menu" == "1" ];then echo "是否使用其他测速地址?(可直接输入其他测速地址 【 注意,不要带http(s):// 】 ,回车使用默认测速地址)" read -p "请输入: " menu if [ -z $menu ]; then CFST_URL="е.eu.org/500.zip" else CFST_URL="$menu" fi [[ $point =~ 2053|2083|2087|2096|8443|443 ]] && htp="https://" || htp="http://" CFST_URL_R="-url $htp$CFST_URL" sed -i '29s/^CFST_SPD=.*/CFST_SPD=""/' /root/cfipopw/cdnip.sh else echo "输入有误" && cdnspedurl fi } cdnym(){ echo echo "请输入Cloudflare解析好的域名(二级域名格式)" echo "例:1.test.eu.org空格2.test.eu.org空格3.test.eu.org…………以此类推,多域名之间有空格" read -p "请输入域名: " cfym if [ -z $cfym ]; then echo "不可为空,请重新输入" && cdnym fi hostname="($cfym)" } cdnymonly(){ echo read -p "请输入Cloudflare解析好的一级域名: " opymyj if [ -z $opymyj ]; then echo "不可为空,请重新输入" && cdnymonly fi domain=$opymyj read -p "请输入二级域自定义的名称: " opymmc if [ -z $opymmc ]; then echo "不可为空,请重新输入" && cdnymonly fi subdomain=$opymmc } cdnsptime(){ echo read -p "请输入重启代理插件后的等待时间多少秒(回车默认30秒): " sptime if [ -z $sptime ]; then sed -i "35s/^sleepTime=.*/sleepTime=30/" /root/cfipopw/cdnip.sh else sed -i "35s/^sleepTime=.*/sleepTime=$sptime/" /root/cfipopw/cdnip.sh fi } cdnyik(){ echo read -p "请输入Cloudflare登录邮箱: " cfmail x_email=$cfmail echo read -p "请输入Cloudflare域名-概述-区域ID: " cfid zone_id=$cfid echo read -p "请输入Cloudflare域名-概述-获取您的API令牌-Global API Key: " cfkey api_key=$cfkey } cdntg(){ echo read -p "是否启用Telegram机器人通知(回车默认不启用,选择1启用): " menu if [ -z $menu ]; then tgken="" tguserid="" elif [ "$menu" == "1" ];then read -p "输入Telegram机器人Token: " token tgken=$token read -p "输入Telegram机器人用户ID: " userid tguserid=$userid else echo "输入有误" && cdntg fi } cdnpush(){ echo read -p "是否启用Pushplus微信通知(回车默认不启用,选择1启用): " menu if [ -z $menu ]; then token="" elif [ "$menu" == "1" ];then read -p "输入Pushplus的Token: " menu token=$menu else echo "输入有误" && cdnpush fi } cdnopcl(){ echo echo "输入使用的代理插件【 0代表不使用任何插件 1代表Passwall 2代表Passwall2 3代表SSR-Plus 4代表Clash 5代表Openclash 6代表Bypass 7代表V2raya 8代表Hello-World 9代表Homeproxy 10代表MihomoTProxy 11代表ShellCrash 】" read -p "请输入一个数值(0-11): " num if [[ $num =~ ^[0-9]$ || $num == 10 || $num == 11 ]]; then clien=$num else echo "输入有误" && cdnopcl fi } install(){ rm -rf /root/cfipopw/cdnip.sh mkdir -p cfipopw cd cfipopw curl -sSL https://gitlab.com/rwkgyg/cdnopw/-/raw/main/cdnip.sh -o cdnip.sh curl -sSL https://gitlab.com/rwkgyg/cdnopw/-/raw/main/cdnac.sh -o cdnac.sh if [ ! -f cfst ]; then curl -L -o cfst -# --retry 2 https://gitlab.com/rwkgyg/CFwarp/-/raw/main/point/cpu3/$cpu chmod +x cfst fi if [ ! -f cfst ] || [ ! -f cdnip.sh ] || [ ! -f cdnac.sh ]; then echo "下载必要文件失败,请确保你的网络通畅,建议开启代理" && exit fi echo echo "1:域名解析推送模式(需要域名,推荐)" echo "2:IP直接推送模式(无需域名)" read -p "请选择: " ymorip if [ "$ymorip" == "1" ]; then echo echo "选择优选IP分配到域名解析的方案" echo "1:多个优选IP解析到一个域名" echo "2:每个优选IP解析到每个域名" read -p "请选择: " ymoryms if [ "$ymoryms" == "1" ]; then cdnymonly else cdnym sed -i "33s/^ymoryms=.*/ymoryms=2/" /root/cfipopw/cdnip.sh fi echo else sed -i "30s/^ymorip=.*/ymorip=2/" /root/cfipopw/cdnip.sh echo fi echo "使用哪种优选IP方式" echo "1:Cloudflare CDN官方IP(强烈推荐!支持IPV4与IPV6)" echo "2:Cloudflare CDN反代IP(仅支持ipv4)" read -p "请选择(回车默认为官方IP): " menu if [ -z $menu ] || [ "$menu" == "1" ]; then cdnv4v6 else rm -rf ipv6.txt curl -Ls https://cf.yg-kkk.gq -o txt.zip unzip -o txt.zip -d txt > /dev/null 2>&1 IP_ADDR=ipv4 fi sleep 1 cdnport sleep 1 cdnspedurl sleep 1 echo read -p "请输入测试线程数量【不懂就回车,默认200 最多1000】: " menu if [ -z $menu ]; then CFST_N=200 else CFST_N=$menu fi sleep 1 echo read -p "请输入测试并显示的IP数量【不懂就回车,默认10】: " menu if [ -z $menu ]; then CFST_DN=10 else CFST_DN=$menu fi sleep 1 echo read -p "请输入平均延迟上限【不懂就回车】: " menu if [ -z $menu ]; then CFST_TL=9999 else CFST_TL=$menu fi sleep 1 echo read -p "请输入平均延迟下限【不懂就回车】: " menu if [ -z $menu ]; then CFST_TLL=0 else CFST_TLL=$menu fi sleep 1 echo read -p "请输入下载速度下限【不懂就回车】: " menu if [ -z $menu ]; then CFST_SL=0 else CFST_SL=$menu fi sleep 1 cdnopcl sleep 1 cdnsptime sleep 1 if [ "$ymorip" == "1" ]; then cdnyik sleep 1 fi cdntg sleep 1 cdnpush sleep 1 sed -i "s/oppoint/$point/" /root/cfipopw/cdnip.sh sed -i "s/opv4v6/$IP_ADDR/" /root/cfipopw/cdnip.sh if [ "$ymorip" == "1" ]; then if [ "$ymoryms" == "1" ]; then hostname="(NO_name)" sed -i "s/opymyj/$domain/" /root/cfipopw/cdnip.sh sed -i "s/opymmc/$subdomain/" /root/cfipopw/cdnip.sh sed -i "s/opym/$hostname/" /root/cfipopw/cdnip.sh else domain="NO_name" subdomain="NO_name" sed -i "s/opymyj/$domain/" /root/cfipopw/cdnip.sh sed -i "s/opymmc/$subdomain/" /root/cfipopw/cdnip.sh sed -i "s/opym/$hostname/" /root/cfipopw/cdnip.sh fi sed -i "s/opmail/$x_email/" /root/cfipopw/cdnip.sh sed -i "s/opcfid/$zone_id/" /root/cfipopw/cdnip.sh sed -i "s/opcfkey/$api_key/" /root/cfipopw/cdnip.sh fi sed -i "s/opnum/$CFST_N/" /root/cfipopw/cdnip.sh sed -i "s/opsnum/$CFST_DN/" /root/cfipopw/cdnip.sh sed -i "s/opup/$CFST_TL/" /root/cfipopw/cdnip.sh sed -i "s/opdo/$CFST_TLL/" /root/cfipopw/cdnip.sh sed -i "s/opsd/$CFST_SL/" /root/cfipopw/cdnip.sh sed -i "s/opcli/$clien/" /root/cfipopw/cdnip.sh sed -i "s#opspd#$CFST_URL_R#" /root/cfipopw/cdnip.sh sed -i "s/optgken/$tgken/" /root/cfipopw/cdnip.sh sed -i "s/optgid/$tguserid/" /root/cfipopw/cdnip.sh sed -i "s/oppushtk/$token/" /root/cfipopw/cdnip.sh bash cdnip.sh } spedlinktr(){ echo echo "是否测速?(选择 1 表示测速,回车默认关闭测速)" read -p "请选择: " menu if [ -z $menu ]; then sed -i '12s/CFST_URL_R="[^"]*"/CFST_URL_R=""/' /root/cfipopw/cdnip.sh sed -i '29s/^CFST_SPD=.*/CFST_SPD=-dd/' /root/cfipopw/cdnip.sh elif [ "$menu" == "1" ];then echo "是否使用其他测速地址?(可直接输入其他测速地址 【 不要带http(s):// 】 ,回车使用默认测速地址)" read -p "请输入: " menu if [ -z $menu ]; then CFST_URL="е.eu.org/500.zip" else CFST_URL="$menu" fi sed -i "12s#$oldport#$CFST_URL#" /root/cfipopw/cdnip.sh sed -i '29s/^CFST_SPD=.*/CFST_SPD=""/' /root/cfipopw/cdnip.sh else echo "输入有误" && exit fi } spedlinkfa(){ echo echo "是否使用其他测速地址?(可直接输入其他测速地址 【 不要带http(s):// 】 ,回车使用默认测速地址)" read -p "请输入: " menu if [ -z $menu ]; then CFST_URL="е.eu.org/500.zip" else CFST_URL="$menu" fi [[ $(sed -n '3s/.*=//p' /root/cfipopw/cdnip.sh) =~ 2053|2083|2087|2096|8443|443 ]] && htp="https://" || htp="http://" spedlink="-url $htp$CFST_URL" sed -i '12s#CFST_URL_R=""#CFST_URL_R="'"$spedlink"'"#' /root/cfipopw/cdnip.sh sed -i '29s/^CFST_SPD=.*/CFST_SPD=""/' /root/cfipopw/cdnip.sh } changeinstall(){ if [ ! -f /root/cfipopw/cdnip.sh ]; then echo "未安装脚本,无法变更参数配置" && exit fi echo [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]] && echo "1.当前为域名解析推送模式(需要域名,推荐),更换为IP直接推送模式(无需域名)" || echo "1.当前为IP直接推送模式(无需域名),更换为域名解析推送模式(需要域名,推荐),注意:请确认选项 8 与 9 已有参数后再确认执行" [ -f /root/cfipopw/txt.zip ] && echo "2.当前为CDN反代IP模式,更换为CDN官方IP模式" || echo "2.当前为CDN官方IP模式,更换为CDN反代IP模式" if [[ $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then echo "3.当前为多个优选IP解析到一个域名方案,更换为每个优选IP解析到每个域名方案" elif [[ ! $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then echo "3.当前为每个优选IP解析到每个域名方案,更换为多个优选IP解析到一个域名方案" else echo "3.当前为IP直接推送模式,不支持域名解析方案的选择" fi echo "4.切换优选IPV4或者IPV6" echo "5.更换端口" echo "6.开启、关闭测速,更换测速网站" echo "7.更换软路由OpenWrt代理插件" echo "8.更改重启代理插件后的等待时间" echo "9.更换CF解析的域名" echo "10.更换CF邮箱、区域ID、API Key" echo "11.关闭、开启Telegram机器人通知,更换Token、用户ID" echo "12.切换Telegram api接口的域名地址" echo "13.关闭、开启Pushplus微信通知,更换Token" echo "============================================" echo "以上选项更改完毕之后,请输入 Y/y ,表示确认执行" echo "============================================" echo "14.退出" echo read -p "请输入: " menu if [[ "$menu" == [Yy] ]]; then bash cdnip.sh elif [ "$menu" == "1" ]; then if [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then sed -i "30s/^ymorip=.*/ymorip=2/" /root/cfipopw/cdnip.sh echo "当前为IP直接推送模式(无需域名)" && sleep 2 else sed -i "30s/^ymorip=.*/ymorip=1/" /root/cfipopw/cdnip.sh echo "当前为域名解析推送模式(需要域名,推荐),注意,请确认选项 7 与 8 已有参数后再确认执行" && sleep 2 fi changeinstall elif [ "$menu" == "2" ]; then oldport=$(sed -n '4s/.*=//p' /root/cfipopw/cdnip.sh) if [ -f txt.zip ]; then rm -rf txt.zip cdnv4v6 else rm -rf ipv6.txt curl -Ls https://cf.yg-kkk.gq -o txt.zip unzip -o txt.zip -d txt > /dev/null 2>&1 IP_ADDR=ipv4 fi sed -i "4s/$oldport/$IP_ADDR/" /root/cfipopw/cdnip.sh changeinstall elif [ "$menu" == "3" ]; then echo if [[ ! $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then sed -i "33s/^ymoryms=.*/ymoryms=1/" /root/cfipopw/cdnip.sh echo "已切换为多个优选IP解析到一个域名方案,注意,请确认 域名 与 CF相关信息 已有参数后再确认执行" && sleep 2 elif [[ $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then sed -i "33s/^ymoryms=.*/ymoryms=2/" /root/cfipopw/cdnip.sh echo "已切换为每个优选IP解析到每个域名方案,注意,请确认 域名 与 CF相关信息 已有参数后再确认执行" && sleep 2 else echo "当前为无域名解析方案,请先在选项1,选择域名解析推送模式" && sleep 2 fi changeinstall elif [ "$menu" == "4" ]; then echo oldport=$(sed -n '4s/.*=//p' /root/cfipopw/cdnip.sh) echo "当前为优选$oldport" echo if [ -f txt.zip ]; then echo "当前为CDN反代IP模式,仅支持优选ipv4" && sleep 2 && changeinstall else cdnv4v6 fi sed -i "4s/$oldport/$IP_ADDR/" /root/cfipopw/cdnip.sh changeinstall elif [ "$menu" == "5" ]; then echo oldport=$(sed -n '3s/.*=//p' /root/cfipopw/cdnip.sh) echo "当前使用的端口:$oldport" cdnport sed -i "3s/$oldport/$point/" /root/cfipopw/cdnip.sh [[ $point =~ 2053|2083|2087|2096|8443|443 ]] && htp="https" || htp="http" sed -i "12s/http\|https/$htp/" /root/cfipopw/cdnip.sh changeinstall elif [ "$menu" == "6" ]; then echo oldport=$(sed -n '12s/.*:\/\/\([^ ]*\).*/\1/p' /root/cfipopw/cdnip.sh | tr -d '"') if [[ $oldport =~ 'bestip' ]] && [[ ! $(sed -n '29p' /root/cfipopw/cdnip.sh) == *"-dd"* ]]; then echo "测速已开启,当前为默认测速网站" spedlinktr elif [[ ! $oldport =~ 'bestip' ]] && [[ ! $(sed -n '29p' /root/cfipopw/cdnip.sh) == *"-dd"* ]]; then echo "测速已开启,当前使用的测速网站:$oldport" spedlinktr else echo "当前已关闭测速" spedlinkfa fi changeinstall elif [ "$menu" == "7" ]; then echo oldport=$(sed -n '10s/.*=//p' /root/cfipopw/cdnip.sh) case $oldport in "11") oldport1=ShellCrash;; "10") oldport1=MihomoTProxy;; "9") oldport1=Homeproxy;; "8") oldport1=Hello-World;; "7") oldport1=V2raya;; "6") oldport1=Bypass;; "5") oldport1=Openclash;; "4") oldport1=Clash;; "3") oldport1=SSR-Plus;; "2") oldport1=Passwall2;; "1") oldport1=Passwall;; "0") oldport1=不使用任何插件;; esac echo "当前使用的代理插件:$oldport1" cdnopcl sed -i "10s/$oldport/$clien/" /root/cfipopw/cdnip.sh changeinstall elif [ "$menu" == "8" ]; then echo oldport=$(sed -n '35s/.*=//p' /root/cfipopw/cdnip.sh) echo "当前重启代理插件后的等待时间:$oldport秒" cdnsptime changeinstall elif [ "$menu" == "9" ]; then if [[ $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then echo "当前为多个优选IP解析到一个域名方案" echo oldport=$(sed -n '31s/.*=//p' /root/cfipopw/cdnip.sh) oldport1=$(sed -n '32s/.*=//p' /root/cfipopw/cdnip.sh) echo "当前使用的一级域名:$oldport" echo "当前使用的二级域自定义名称:$oldport1" cdnymonly sed -i "31s/$oldport/$domain/" /root/cfipopw/cdnip.sh sed -i "32s/^subdomain=.*/subdomain=$subdomain/" /root/cfipopw/cdnip.sh elif [[ ! $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then echo "当前为每个优选IP解析到每个域名方案" echo oldport=$(sed -n '6s/.*=//p' /root/cfipopw/cdnip.sh | tr -d '()') echo "当前使用的域名:$oldport" cdnym sed -i "6s/($oldport)/$hostname/" /root/cfipopw/cdnip.sh else echo "当前为无域名解析方案,如要切换域名解析推送模式,请在更改配置菜单-选项1中进行切换" && sleep 2 fi changeinstall elif [ "$menu" == "10" ]; then echo oldport1=$(sed -n '5s/.*=//p' /root/cfipopw/cdnip.sh) oldport2=$(sed -n '7s/.*=//p' /root/cfipopw/cdnip.sh) oldport3=$(sed -n '8s/.*=//p' /root/cfipopw/cdnip.sh) echo "当前使用的邮箱:$oldport1" echo "当前使用的区域ID:$oldport2" echo "当前使用的API Key:$oldport3" cdnyik sed -i "5s/$oldport1/$x_email/" /root/cfipopw/cdnip.sh sed -i "7s/$oldport2/$zone_id/" /root/cfipopw/cdnip.sh sed -i "8s/$oldport3/$api_key/" /root/cfipopw/cdnip.sh changeinstall elif [ "$menu" == "11" ]; then echo oldport1=$(sed -n '26s/.*=//p' /root/cfipopw/cdnip.sh) oldport2=$(sed -n '27s/.*=//p' /root/cfipopw/cdnip.sh) if [[ -z $oldport1 || -z $oldport2 ]]; then echo "未设置telegram机器人通知" else echo "当前Telegram机器人Token:$oldport1" echo "当前Telegram机器人用户ID:$oldport2" fi cdntg sed -i "26s/^telegramBotToken=.*/telegramBotToken=$tgken/" /root/cfipopw/cdnip.sh sed -i "27s/^telegramBotUserId=.*/telegramBotUserId=$tguserid/" /root/cfipopw/cdnip.sh changeinstall elif [ "$menu" == "12" ]; then echo oldport1=$(sed -n '36s/.*=//p' /root/cfipopw/cdnip.sh) echo "当前使用的TG api接口的域名地址:$oldport1" echo read -p "请输入要更改的TG api接口的域名地址【 回车默认使用TG官方api,输入时不要带https:// 】: " menu if [ -z $menu ]; then tgapi=api.telegram.org else tgapi=$menu fi sed -i "36s#^tgapi=.*#tgapi=$tgapi#" /root/cfipopw/cdnip.sh changeinstall elif [ "$menu" == "13" ]; then echo oldport1=$(sed -n '34s/.*=//p' /root/cfipopw/cdnip.sh) if [[ -z $oldport1 ]]; then echo "未设置Pushplus微信通知" else echo "当前Pushplus的Token:$oldport1" fi cdnpush sed -i "34s/^token=.*/token=$token/" /root/cfipopw/cdnip.sh changeinstall else exit fi } #sed -n '3s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '4s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '5s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '6s/.*=//p' /root/cfipopw/cdnip.sh | tr -d '()' #sed -n '7s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '8s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '10s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '12s/.*:\/\/\([^ ]*\).*/\1/p' /root/cfipopw/cdnip.sh | tr -d '"' #sed -n '14s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '18s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '20s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '22s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '24s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '26s/.*=//p' /root/cfipopw/cdnip.sh #sed -n '27s/.*=//p' /root/cfipopw/cdnip.sh #sed -i '29s/^CFST_SPD=.*/CFST_SPD=""/' /root/cfipopw/cdnip.sh #sed -i '29s/^CFST_SPD=.*/CFST_SPD=-dd/' /root/cfipopw/cdnip.sh showcdn(){ if [ -f /root/cfipopw/cdnip.sh ]; then echo echo "自动优选IP脚本正在运行中,详细配置如下:" echo "=====================================================" [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]] && echo "1、当前为域名解析推送模式(需要域名,推荐)" || echo "1、当前为IP直接推送模式(无需域名)" echo if [[ $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then echo "2、当前为多个优选IP解析到一个域名方案" elif [[ ! $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then echo "2、当前为每个优选IP解析到每个域名方案" else echo "2、当前为无域名解析方案" fi echo [ -f /root/cfipopw/txt.zip ] && echo "3、当前为CDN反代IP模式" || echo "3、当前为CDN官方IP模式" echo echo "4、当前为优选$(sed -n '4s/.*=//p' /root/cfipopw/cdnip.sh)" echo echo "5、使用的端口:$(sed -n '3s/.*=//p' /root/cfipopw/cdnip.sh)" echo old12=$(sed -n '12s/.*:\/\/\([^ ]*\).*/\1/p' /root/cfipopw/cdnip.sh | tr -d '"') if [[ $old12 =~ 'bestip' ]] && [[ ! $(sed -n '29p' /root/cfipopw/cdnip.sh) == *"-dd"* ]]; then echo "6、测速已开启,当前为默认测速网站" elif [[ ! $old12 =~ 'bestip' ]] && [[ ! $(sed -n '29p' /root/cfipopw/cdnip.sh) == *"-dd"* ]]; then echo "6、测速已开启,当前使用的测速网站:$old12" else echo "6、当前已关闭测速" fi echo oldport=$(sed -n '10s/.*=//p' /root/cfipopw/cdnip.sh) case $oldport in "10") oldport=MihomoTProxy;; "9") oldport=Homeproxy;; "8") oldport=Hello-World;; "7") oldport=V2raya;; "6") oldport=Bypass;; "5") oldport=Openclash;; "4") oldport=Clash;; "3") oldport=SSR-Plus;; "2") oldport=Passwall2;; "1") oldport=Passwall;; "0") oldport=不使用任何插件;; esac echo "7、当前使用的代理插件:$oldport" echo oldport35=$(sed -n '35s/.*=//p' /root/cfipopw/cdnip.sh) echo "8、当前重启代理插件后的等待时间:$oldport35秒" echo if [[ $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then old31=$(sed -n '31s/.*=//p' /root/cfipopw/cdnip.sh) old32=$(sed -n '32s/.*=//p' /root/cfipopw/cdnip.sh) echo "9、当前使用的二级域自定义名称:$old32 一级域名:$old31 " elif [[ ! $(sed -n '33p' /root/cfipopw/cdnip.sh | grep "1") ]] && [[ $(sed -n '30p' /root/cfipopw/cdnip.sh | grep "1") ]]; then old6=$(sed -n '6s/.*=//p' /root/cfipopw/cdnip.sh | tr -d '()') echo "9、当前使用的域名:$old6" else echo "9、当前无域名显示" fi echo echo "10、使用的邮箱:$(sed -n '5s/.*=//p' /root/cfipopw/cdnip.sh)" echo echo "11、使用的区域ID:$(sed -n '7s/.*=//p' /root/cfipopw/cdnip.sh)" echo echo "12、使用的API Key:$(sed -n '8s/.*=//p' /root/cfipopw/cdnip.sh)" echo old26=$(sed -n '26s/.*=//p' /root/cfipopw/cdnip.sh) old27=$(sed -n '27s/.*=//p' /root/cfipopw/cdnip.sh) if [[ -z $old26 && -z $old27 ]]; then echo "13、未设置telegram机器人通知" else echo "13、Telegram机器人Token:$old26" echo echo "13、Telegram机器人用户ID:$old27" echo old36=$(sed -n '36s/.*=//p' /root/cfipopw/cdnip.sh) echo "13、当前使用的TG api:$old36" fi echo old34=$(sed -n '34s/.*=//p' /root/cfipopw/cdnip.sh) if [[ -z $old34 ]]; then echo "14、未设置Pushplus微信通知" else echo "14、Pushplus的Token:$old34" fi echo echo "测速线程数量:$(sed -n '14s/.*=//p' /root/cfipopw/cdnip.sh)" echo echo "测速显示数量:$(sed -n '18s/.*=//p' /root/cfipopw/cdnip.sh)" echo echo "平均延迟上限:$(sed -n '20s/.*=//p' /root/cfipopw/cdnip.sh)" echo echo "平均延迟下限:$(sed -n '22s/.*=//p' /root/cfipopw/cdnip.sh)" echo echo "下载速度下限:$(sed -n '24s/.*=//p' /root/cfipopw/cdnip.sh)" echo echo "切记:在软路由-计划任务选项中,加入优选IP自动执行时间的cron表达式" echo "比如每天早上三点执行:0 3 * * * cd /root/cfipopw/ && bash cdnip.sh" echo "=====================================================" echo fi } runcdnopw(){ if [ -f /root/cfipopw/cdnip.sh ]; then cd /root/cfipopw/ && bash cdnip.sh else echo "未安装此脚本,无法执行" fi } rmrf(){ rm -rf /root/cfipopw cdnopw.sh ygop_update echo "卸载完成" } ipv4ipv6(){ if [[ -n $v6 ]]; then echo "当前网络:支持IPV4与IPV6" else echo "当前网络:仅支持IPV4,无IPV6" fi } deallym(){ echo read -p "请输入Cloudflare解析好的一级域名: " domain echo read -p "请输入二级域指定的名称: " subdomain cdnyik url="https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records" params="name=${subdomain}.${domain}&type=" response=$(curl -sm10 -X GET "$url?$params" -H "X-Auth-Email: $x_email" -H "X-Auth-Key: $api_key") if [[ $(echo "$response" | jq -r '.success') == "true" ]]; then records=$(echo "$response" | jq -r '.result') if [[ $(echo "$records" | jq 'length') -gt 0 ]]; then for record in $(echo "$records" | jq -c '.[]'); do record_id=$(echo "$record" | jq -r '.id') delete_url="$url/$record_id" delete_response=$(curl -sm10 -X DELETE "$delete_url" -H "X-Auth-Email: $x_email" -H "X-Auth-Key: $api_key") if [[ $(echo "$delete_response" | jq -r '.success') == "true" ]]; then echo "成功删除 DNS 记录:$(echo "$record" | jq -r '.name')" else echo "删除 DNS 记录失败" fi done else echo "没有找到指定的 DNS 记录" fi else echo "获取 DNS 记录失败" fi } echo "--------------------------------------------------------------" echo "甬哥Github项目 :github.com/yonggekkk" echo "甬哥Blogger博客 :ygkkk.blogspot.com" echo "甬哥YouTube频道 :www.youtube.com/@ygkkk" echo "--------------------------------------------------------------" echo "OpenWrt软路由-优选IP解析到CF域名脚本 V2024.4.1" ipv4ipv6 echo "--------------------------------------------------------------" showcdn echo "1.安装/重置脚本" echo "2.更改各项参数配置" echo "3.运行一次已配置完成的脚本" echo "4.删除CF域名指定名称解析记录" echo "5.卸载" echo "0.退出" read -p "请选择: " menu if [ "$menu" == "1" ];then install elif [ "$menu" == "2" ];then cd cfipopw changeinstall elif [ "$menu" == "3" ];then runcdnopw elif [ "$menu" == "4" ];thА вот cdnac.sh, что скачивается внутри этого скрипта.
cdnac.sh
#!/bin/bash export LANG=en_US.UTF-8 if [[ -f /root/cfipopw/txt.zip && -f /root/cfipopw/informlog ]]; then echo echo "请稍等,对优选反代IP进行地区识别,最多显示前10个IP" rm -rf cdnIP.csv b.csv a.csv awk -F ',' 'NR>1 && NR<=11 {print $1}' result.csv > a.csv while IFS= read -r ip_address; do UA_Browser="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36" response=$(curl -sm5 --user-agent "${UA_Browser}" "https://api.ip.sb/geoip/$ip_address" -k | awk -F "country_code" '{print $2}' | awk -F'":"|","|"' '{print $2}') if [ $? -eq 0 ]; then echo "IP地址 $ip_address 的地区是: $response" | tee -a b.csv else echo "无法获取IP地址 $ip_address 的地区信息" | tee -a b.csv fi sleep 1 done < "a.csv" echo -e "\n优选反代IP--国家地区识别" >> cdnIP.csv cat b.csv >> cdnIP.csv #grep 'SG' b.csv | head -n 10 >> cdnIP.csv #grep 'HK' b.csv | head -n 10 >> cdnIP.csv #grep 'JP' b.csv | head -n 10 >> cdnIP.csv #grep 'KR' b.csv | head -n 10 >> cdnIP.csv #grep 'TW' b.csv | head -n 10 >> cdnIP.csv #grep 'US' b.csv | head -n 10 >> cdnIP.csv #grep 'GB' b.csv | head -n 10 >> cdnIP.csv #grep 'DE' b.csv | head -n 10 >> cdnIP.csv #grep 'NL' b.csv | head -n 10 >> cdnIP.csv #grep 'FR' b.csv | head -n 10 >> cdnIP.csv echo cat cdnIP.csv >> informlog fi if [[ -f /root/cfipopw/txt.zip && ! -f /root/cfipopw/informlog ]]; then echo "下载更新反代IP库txt.zip文件……" wget -q https://zip.baipiao.eu.org -O txt.zip if [ $? -eq 0 ]; then echo "下载成功" else curl -L -# --retry 2 https://cf.yg-kkk.gq -o txt.zip if [ $? -eq 0 ]; then echo "下载成功" else echo "下载失败,继续使用之前的反代IP库" fi fi rm -rf txt unzip -o txt.zip -d txt > /dev/null 2>&1 if [[ ! -e "txt" ]]; then echo "反代IP库txt.zip文件下载失败" && exit fi point=$(sed -n '3s/.*=//p' /root/cfipopw/cdnip.sh) if [ "$point" == "443" ]; then find txt -type f -name "*443*" ! -name "*8443*" -exec cat {} \; > ip.txt elif [ "$point" == "80" ]; then find txt -type f -name "*80*" ! -name "*8880*" ! -name "*8080*" -exec cat {} \; > ip.txt else find txt -type f -name "*${point}*" -exec cat {} \; > ip.txt fi grep -E '^8|^47|^43|^130|^132|^152|^193|^140|^138|^150|^143|^141|^155|^168|^124|^170|^119' ip.txt > pass.txt && mv pass.txt ip.txt fiА ещё в cdnopw используется необфусцированный https://gitlab.com/rwkgyg/cdnopw/-/raw/main/cdnip.sh
Может, ещё что-то можно разобрать/понять. Я просто дал простенький инструмент деобфускации если кому будет ну очень интересно.
BOLNICHKA399
27.03.2026 21:44А суть то заминусованности в чем? В скрипте добавлены бэкдоры? Можете пояснить что не так? Я на себе попробовал, passwall2 поставился, поднял vless клиент, все работает. Что не так?

Derevtso
27.03.2026 21:44Лично я не минусовал. И не плюсовал.
Меня, конечно, слегка смущает обфусцированность скриптов, вызывает ощущение, будто, "что-то, наверное, не так". Но кто знает, может, это что-то на тему "прятать от правительства", я хз, у китайцев с этим тоже проблемы.

Alexander_th
27.03.2026 21:44Суть в том, что душнила, который разбирается больше вас считает что все вокруг идиоты и пишут всякую ерунду, и чтобы он злится и ставит минусы, еще вероятно расстраивается, что нейросеть дает доступ к информации, которую раньше только он один мог освоить. Другого объяснения не вижу - чувак дал инструкцию, ну не хочешь ты по ней ничего настраивать, ну не настраивай, е мое, че говнить то? Или лучше на stack overflow к своим. А, ой, он же уже не популярен.

Xendler
27.03.2026 21:44И чем это лучше podkop?

Amaev777
27.03.2026 21:44Podkop не поддерживает xray reality, и мне он показался каким то не стабильным, рандомно лезет торренты проксировать причем выборочно, ip диапазоны что задавались для проксирования тоже проксирует как-то выборочно, любит вешать сеть на время, ping с vless сервероов становится двухкратным из-за каких-то особенностей сингбокса, ну и вечные беды с проксированием what's app (хотя может уже пофиксили)

lorgar_xvii
27.03.2026 21:44Подкоп использует singbox. Passwall же использует xray, singbox и hysteria2

denbog1
27.03.2026 21:44Например Подкоп не поддерживает мой конфиг VLESS XHTTP REALITY EXTRA.
Также в passwall2 очень гибко настраиваются правила маршрутизации, можно задавать любые источники geosite и geoip и их автообновление.

Lainhard
Это конечно хорошо, защитился так защитился, но есть мнение, что человек (человек ведь?), условно, специалист, должен отвечать за свои "инструкции". Как минимум нести моральную ответственность как автор.