#!/bin/sh
# Служебные функции и переменные
LOG="/opt/var/log/HydraRoute.log"
echo "$(date "+%Y-%m-%d %H:%M:%S") Запуск установки" >> "$LOG"
REQUIRED_VERSION="4.2.3"
IP_ADDRESS=$(ip addr show br0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)
VERSION=$(ndmc -c show version | grep "title" | awk -F": " '{print $2}')
AVAILABLE_SPACE=$(df /opt | awk 'NR==2 {print $4}')
## переменные для конфига AGH
PASSWORD=\$2y\$10\$fpdPsJjQMGNUkhXgalKGluJ1WFGBO6DKBJupOtBxIzckpJufHYpk.
rule1='||*^$dnstype=HTTPS,dnsrewrite=NOERROR'
rule2='||yabs.yandex.ru^$important'
rule3='||mc.yandex.ru^$important'
## анимация
animation() {
local pid=$1
local message=$2
local spin='-\|/'
echo -n "$message... "
while kill -0 $pid 2>/dev/null; do
for i in $(seq 0 3); do
echo -ne "\b${spin:$i:1}"
usleep 100000 # 0.1 сек
done
done
wait $pid
if [ $? -eq 0 ]; then
echo -e "\b✔ Готово!"
else
echo -e "\b✖ Ошибка!"
fi
}
# Получение списка и выбор интерфейса
get_interfaces() {
## выводим список интерфейсов для выбора
echo "Доступные интерфейсы:"
i=1
interfaces=$(ip a | sed -n 's/.*: \(.*\): <.*UP.*/\1/p')
interface_list=""
for iface in $interfaces; do
## проверяем, существует ли интерфейс, игнорируя ошибки 'ip: can't find device'
if ip a show "$iface" &>/dev/null; then
ip_address=$(ip a show "$iface" | grep -oP 'inet \K[\d.]+')
if [ -n "$ip_address" ]; then
echo "$i. $iface: $ip_address"
interface_list="$interface_list $iface"
i=$((i+1))
fi
fi
done
## запрашиваем у пользователя имя интерфейса с проверкой ввода
while true; do
read -p "Введите ИМЯ интерфейса, через которое будет перенаправляться трафик: " net_interface
if echo "$interface_list" | grep -qw "$net_interface"; then
echo "Выбран интерфейс: $net_interface"
break
else
echo "Неверный выбор, необходимо ввести ИМЯ интерфейса из списка."
fi
done
}
# Установка пакетов
opkg_install() {
opkg update
opkg install adguardhome-go ipset iptables ip-full
}
# Формирование файлов
files_create() {
## ipset
cat << EOF > /opt/etc/init.d/S52ipset
#!/bin/sh
PATH=/opt/sbin:/opt/bin:/opt/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
if [ "\$1" = "start" ]; then
ipset create bypass hash:ip
ipset create bypass6 hash:ip family inet6
ip rule add fwmark 1001 table 1001
ip -6 rule add fwmark 1001 table 1001
fi
EOF
## скрипты маршрутизации
cat << EOF > /opt/etc/ndm/ifstatechanged.d/010-bypass-table.sh
#!/bin/sh
[ "\$system_name" == "$net_interface" ] || exit 0
[ ! -z "\$(ipset --quiet list bypass)" ] || exit 0
[ "\${connected}-\${link}-\${up}" == "yes-up-up" ] || exit 0
if [ -z "\$(ip route list table 1001)" ]; then
ip route add default dev \$system_name table 1001
fi
EOF
cat << EOF > /opt/etc/ndm/ifstatechanged.d/011-bypass6-table.sh
#!/bin/sh
[ "\$system_name" == "$net_interface" ] || exit 0
[ ! -z "\$(ipset --quiet list bypass6)" ] || exit 0
[ "\${connected}-\${link}-\${up}" == "yes-up-up" ] || exit 0
if [ -z "\$(ip -6 route list table 1001)" ]; then
ip -6 route add default dev \$system_name table 1001
fi
EOF
## cкрипты маркировки трафика
cat << EOF > /opt/etc/ndm/netfilter.d/010-bypass.sh
#!/bin/sh
[ "\$type" == "ip6tables" ] && exit
[ "\$table" != "mangle" ] && exit
[ -z "\$(ip link list | grep $net_interface)" ] && exit
[ -z "\$(ipset --quiet list bypass)" ] && exit
if [ -z "\$(iptables-save | grep bypass)" ]; then
iptables -w -t mangle -A PREROUTING ! -i $net_interface -m conntrack --ctstate NEW -m set --match-set bypass dst -j CONNMARK --set-mark 1001
iptables -w -t mangle -A PREROUTING ! -i $net_interface -m set --match-set bypass dst -j CONNMARK --restore-mark
fi
EOF
cat << EOF > /opt/etc/ndm/netfilter.d/011-bypass6.sh
#!/bin/sh
[ "\$type" != "ip6tables" ] && exit
[ "\$table" != "mangle" ] && exit
[ -z "\$(ip -6 link list | grep $net_interface)" ] && exit
[ -z "\$(ipset --quiet list bypass6)" ] && exit
if [ -z "\$(ip6tables-save | grep bypass6)" ]; then
ip6tables -w -t mangle -A PREROUTING ! -i $net_interface -m conntrack --ctstate NEW -m set --match-set bypass6 dst -j CONNMARK --set-mark 1001
ip6tables -w -t mangle -A PREROUTING ! -i $net_interface -m set --match-set bypass6 dst -j CONNMARK --restore-mark
fi
EOF
}
# Настройки AGH
agh_setup() {
/opt/etc/init.d/S99adguardhome stop
## конфиг AdGuard Home
cat << EOF > /opt/etc/AdGuardHome/AdGuardHome.yaml
http:
pprof:
port: 6060
enabled: false
address: $IP_ADDRESS:3000
session_ttl: 720h
users:
- name: admin
password: $PASSWORD
auth_attempts: 5
block_auth_min: 15
http_proxy: ""
language: ""
theme: auto
dns:
bind_hosts:
- 0.0.0.0
port: 53
anonymize_client_ip: false
ratelimit: 20
ratelimit_subnet_len_ipv4: 24
ratelimit_subnet_len_ipv6: 56
ratelimit_whitelist: []
refuse_any: true
upstream_dns:
- tls://dns.google
- tls://one.one.one.one
- tls://p0.freedns.controld.com
- tls://dot.sb
- tls://dns.nextdns.io
- tls://dns.quad9.net
upstream_dns_file: ""
bootstrap_dns:
- 9.9.9.9
- 1.1.1.1
- 8.8.8.8
- 149.112.112.10
- 94.140.14.14
fallback_dns: []
upstream_mode: load_balance
fastest_timeout: 1s
allowed_clients: []
disallowed_clients: []
blocked_hosts:
- version.bind
- id.server
- hostname.bind
trusted_proxies:
- 127.0.0.0/8
- ::1/128
cache_size: 4194304
cache_ttl_min: 0
cache_ttl_max: 0
cache_optimistic: false
bogus_nxdomain: []
aaaa_disabled: false
enable_dnssec: false
edns_client_subnet:
custom_ip: ""
enabled: false
use_custom: false
max_goroutines: 300
handle_ddr: true
ipset: []
ipset_file: /opt/etc/AdGuardHome/ipset.conf
bootstrap_prefer_ipv6: false
upstream_timeout: 10s
private_networks: []
use_private_ptr_resolvers: true
local_ptr_upstreams: []
use_dns64: false
dns64_prefixes: []
serve_http3: false
use_http3_upstreams: false
serve_plain_dns: true
hostsfile_enabled: true
tls:
enabled: false
server_name: ""
force_https: false
port_https: 443
port_dns_over_tls: 853
port_dns_over_quic: 853
port_dnscrypt: 0
dnscrypt_config_file: ""
allow_unencrypted_doh: false
certificate_chain: ""
private_key: ""
certificate_path: ""
private_key_path: ""
strict_sni_check: false
querylog:
dir_path: ""
ignored: []
interval: 24h
size_memory: 1000
enabled: false
file_enabled: true
statistics:
dir_path: ""
ignored: []
interval: 24h
enabled: false
filters:
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt
name: AdGuard DNS filter
id: 1
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt
name: AdAway Default Blocklist
id: 2
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_59.txt
name: AdGuard DNS Popup Hosts filter
id: 1737211801
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_30.txt
name: Phishing URL Blocklist (PhishTank and OpenPhish)
id: 1737211802
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_42.txt
name: ShadowWhisperer's Malware List
id: 1737211803
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_9.txt
name: The Big List of Hacked Malware Web Sites
id: 1737211804
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_63.txt
name: HaGeZi's Windows/Office Tracker Blocklist
id: 1737211805
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_7.txt
name: Perflyst and Dandelion Sprout's Smart-TV Blocklist
id: 1737211806
- enabled: true
url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_12.txt
name: Dandelion Sprout's Anti-Malware List
id: 1737211807
whitelist_filters: []
user_rules:
- '$rule1'
- '$rule2'
- '$rule3'
dhcp:
enabled: false
interface_name: ""
local_domain_name: lan
dhcpv4:
gateway_ip: ""
subnet_mask: ""
range_start: ""
range_end: ""
lease_duration: 86400
icmp_timeout_msec: 1000
options: []
dhcpv6:
range_start: ""
lease_duration: 86400
ra_slaac_only: false
ra_allow_slaac: false
filtering:
blocking_ipv4: ""
blocking_ipv6: ""
blocked_services:
schedule:
time_zone: Local
ids: []
protection_disabled_until: null
safe_search:
enabled: false
bing: true
duckduckgo: true
ecosia: true
google: true
pixabay: true
yandex: true
youtube: true
blocking_mode: default
parental_block_host: family-block.dns.adguard.com
safebrowsing_block_host: standard-block.dns.adguard.com
rewrites: []
safe_fs_patterns:
- /opt/etc/AdGuardHome/userfilters/*
safebrowsing_cache_size: 1048576
safesearch_cache_size: 1048576
parental_cache_size: 1048576
cache_time: 30
filters_update_interval: 24
blocked_response_ttl: 10
filtering_enabled: true
parental_enabled: false
safebrowsing_enabled: false
protection_enabled: true
clients:
runtime_sources:
whois: true
arp: true
rdns: true
dhcp: true
hosts: true
persistent: []
log:
enabled: true
file: ""
max_backups: 0
max_size: 100
max_age: 3
compress: false
local_time: false
verbose: false
os:
group: ""
user: ""
rlimit_nofile: 0
schema_version: 29
EOF
}
# Базовый список доменов
domain_add() {
cat << EOF > /opt/etc/AdGuardHome/ipset.conf
2ip.ru/bypass,bypass6
googlevideo.com,ggpht.com,googleapis.com,googleusercontent.com,gstatic.com,nhacmp3youtube.com,youtu.be,youtube.com,ytimg.com/bypass,bypass6
cdninstagram.com,instagram.com,bookstagram.com,carstagram.com,chickstagram.com,ig.me,igcdn.com,igsonar.com,igtv.com,imstagram.com,imtagram.com,instaadder.com,instachecker.com,instafallow.com,instafollower.com,instagainer.com,instagda.com,instagify.com,instagmania.com,instagor.com,instagram.fkiv7-1.fna.fbcdn.net,instagram-brand.com,instagram-engineering.com,instagramhashtags.net,instagram-help.com,instagramhilecim.com,instagramhilesi.org,instagramium.com,instagramizlenme.com,instagramkusu.com,instagramlogin.com,instagrampartners.com,instagramphoto.com,instagram-press.com,instagram-press.net,instagramq.com,instagramsepeti.com,instagramtips.com,instagramtr.com,instagy.com,instamgram.com,instanttelegram.com,instaplayer.net,instastyle.tv,instgram.com,oninstagram.com,onlineinstagram.com,online-instagram.com,web-instagram.net,wwwinstagram.com/bypass,bypass6
1337x.to,262203.game4you.top,eztv.re,fitgirl-repacks.site,new.megashara.net,nnmclub.to,nnm-club.to,nnm-club.me,rarbg.to,rustorka.com,rutor.info,rutor.org,rutracker.cc,rutracker.org,tapochek.net,thelastgame.ru,thepiratebay.org,thepirate-bay.org,torrentgalaxy.to,torrent-games.best,torrentz2eu.org,limetorrents.info,pirateproxy-bay.com,torlock.com,torrentdownloads.me/bypass,bypass6
chatgpt.com,openai.com,oaistatic.com,files.oaiusercontent.com,gpt3-openai.com,openai.fund,openai.org/bypass,bypass6
EOF
}
# Установка прав на скрипты
chmod_set() {
chmod +x /opt/etc/init.d/S52ipset
chmod +x /opt/etc/ndm/ifstatechanged.d/010-bypass-table.sh
chmod +x /opt/etc/ndm/ifstatechanged.d/011-bypass6-table.sh
chmod +x /opt/etc/ndm/netfilter.d/010-bypass.sh
chmod +x /opt/etc/ndm/netfilter.d/011-bypass6.sh
}
# Установка web-панели
install_panel() {
opkg install node tar
mkdir -p /opt/tmp
/opt/etc/init.d/S99hpanel stop
chmod -R 777 /opt/etc/HydraRoute/
chmod 777 /opt/etc/init.d/S99hpanel
rm -rf /opt/etc/HydraRoute/
rm -r /opt/etc/init.d/S99hpanel
curl -Ls --retry 6 --retry-delay 5 --max-time 5 -o /opt/tmp/hpanel.tar "https://github.com/Ground-Zerro/HydraRoute/raw/refs/heads/main/Relic/webpanel/hpanel.tar"
if [ $? -ne 0 ]; then
exit 1
fi
mkdir -p /opt/etc/HydraRoute
tar -xf /opt/tmp/hpanel.tar -C /opt/etc/HydraRoute/
rm /opt/tmp/hpanel.tar
mv /opt/etc/HydraRoute/S99hpanel /opt/etc/init.d/S99hpanel
chmod -R 444 /opt/etc/HydraRoute/
chmod 755 /opt/etc/init.d/S99hpanel
chmod 755 /opt/etc/HydraRoute/hpanel.js
}
# Отключение ipv6 на провайдере
disable_ipv6() {
curl -kfsS "localhost:79/rci/show/interface/" | jq -r '
to_entries[] |
select(.value.defaultgw == true or .value.via != null) |
if .value.via then "\(.value.id) \(.value.via)" else "\(.value.id)" end
' | while read -r iface via; do
ndmc -c "no interface $iface ipv6 address"
if [ -n "$via" ]; then
ndmc -c "no interface $via ipv6 address"
fi
done
ndmc -c 'system configuration save'
}
# Проверка версии прошивки
firmware_check() {
if [ "$(printf '%s\n' "$VERSION" "$REQUIRED_VERSION" | sort -V | tail -n1)" = "$VERSION" ]; then
dns_off >>"$LOG" 2>&1 &
else
dns_off_sh
fi
}
# Отклчюение системного DNS
dns_off() {
ndmc -c 'opkg dns-override'
ndmc -c 'system configuration save'
sleep 3
}
# Отключение системного DNS через "nohup"
dns_off_sh() {
opkg install coreutils-nohup >>"$LOG" 2>&1
echo "Отключение системного DNS..."
echo ""
if [ "$PANEL" = "1" ]; then
complete_info
else
complete_info_no_panel
fi
rm -- "$0"
read -r
/opt/bin/nohup sh -c "ndmc -c 'opkg dns-override' && ndmc -c 'system configuration save' && sleep 3 && reboot" >>"$LOG" 2>&1
}
# Сообщение установка ОK
complete_info() {
echo "Установка HydraRoute завершена"
echo " - панель управления доступна по адресу: http://$IP_ADDRESS:2000/"
echo ""
echo "Нажмите Enter для перезагрузки (обязательно)."
}
# Сообщение установка без панели
complete_info_no_panel() {
echo "HydraRoute установлен, но для web-панели не достаточно места"
echo " - редактирование ipset возможно только вручную (инструкция на GitHub)."
echo ""
echo "AdGuard Home доступен по адресу: http://$IP_ADDRESS:3000/"
echo "Login: admin"
echo "Password: keenetic"
echo ""
echo "Нажмите Enter для перезагрузки (обязательно)."
}
# === main ===
# Выход если места меньше 80Мб
if [ "$AVAILABLE_SPACE" -lt 81920 ]; then
echo "Не достаточно места для установки"
rm -- "$0"
exit 1
fi
# Запрос интерфейса у пользователя
get_interfaces
# Установка пакетов
opkg_install >>"$LOG" 2>&1 &
animation $! "Установка необходимых пакетов"
# Формирование скриптов
files_create >>"$LOG" 2>&1 &
animation $! "Формируем скрипты"
# Настройка AdGuard Home
agh_setup >>"$LOG" 2>&1 &
animation $! "Настройка AdGuard Home"
# Добавление доменов в ipset
domain_add >>"$LOG" 2>&1 &
animation $! "Добавление доменов в ipset"
# Установка прав на выполнение скриптов
chmod_set >>"$LOG" 2>&1 &
animation $! "Установка прав на выполнение скриптов"
# установка web-панели если места больше 80Мб
if [ "$AVAILABLE_SPACE" -gt 81920 ]; then
PANEL="1"
install_panel >>"$LOG" 2>&1 &
animation $! "Установка web-панели"
fi
# Отключение ipv6
disable_ipv6 >>"$LOG" 2>&1 &
animation $! "Отключение ipv6"
# Отключение системного DNS и сохранение
firmware_check
animation $! "Отключение системного DNS"
# Завершение
echo ""
if [ "$PANEL" = "1" ]; then
complete_info
else
complete_info_no_panel
fi
rm -- "$0"
# Ждем Enter и ребутимся
read -r
reboot