Compare commits

..

12 Commits

Author SHA1 Message Date
itdoginfo
25b0dcaad5 v0.4.6 2025-06-30 16:27:44 +03:00
itdoginfo
cc59e756dd br_netfilter. Cache size unset. Mixed & source_ip_cidr 2025-06-30 16:26:31 +03:00
itdoginfo
210714c499 unnecessary check 2025-06-30 16:24:33 +03:00
itdoginfo
8b6c336584 Change to 1.1.1.1 2025-06-27 23:54:52 +03:00
itdoginfo
5c543c1608 Change to procd_add_interface_trigger. Added PROCD_RELOAD_DELAY 2025-06-27 23:54:31 +03:00
itdoginfo
ac274d8796 v0.4.5 2025-06-25 23:38:55 +03:00
itdoginfo
ce1f86ceb7 Added split dns. Func for build sing-box config 2025-06-25 23:34:39 +03:00
itdoginfo
1fd67eefb3 Fix eng phrase 2025-06-25 23:32:33 +03:00
itdoginfo
e7b726d27c Merge pull request #127 from procudin/fix/extra-configs-visibility
fix: hide extra configs for non-basic tabs
2025-06-23 13:58:25 +03:00
Artem Prokudin
adb16e7f74 fix: hide extra configs for non-basic tabs 2025-06-15 10:57:16 +03:00
itdoginfo
51da8c22fd Update 2025-06-03 15:47:13 +03:00
itdoginfo
41351dafd2 Removed the installation awg/wg/ovpn/oc. Refactoring 2025-06-03 15:45:27 +03:00
13 changed files with 272 additions and 447 deletions

View File

@@ -17,16 +17,11 @@ https://podkop.net/
# Установка Podkop # Установка Podkop
Полная информация в [документации](https://podkop.net/docs/install/) Полная информация в [документации](https://podkop.net/docs/install/)
Вкратце, достаточно одного скрипта для установки: Вкратце, достаточно одного скрипта для установки и обновления:
``` ```
sh <(wget -O - https://raw.githubusercontent.com/itdoginfo/podkop/refs/heads/main/install.sh) sh <(wget -O - https://raw.githubusercontent.com/itdoginfo/podkop/refs/heads/main/install.sh)
``` ```
Для обновления:
```
sh <(wget -qO- https://raw.githubusercontent.com/itdoginfo/podkop/refs/heads/main/install.sh) --upgrade
```
# ToDo # ToDo
Этот раздел не означает задачи, которые нужно брать и делать. Это общий список хотелок. Если вы хотите помочь, пожалуйста, спросите сначала в телеграмме. Этот раздел не означает задачи, которые нужно брать и делать. Это общий список хотелок. Если вы хотите помочь, пожалуйста, спросите сначала в телеграмме.

View File

@@ -1,66 +1,35 @@
#!/bin/sh #!/bin/sh
REPO="https://api.github.com/repos/itdoginfo/podkop/releases/latest" REPO="https://api.github.com/repos/itdoginfo/podkop/releases/latest"
IS_SHOULD_RESTART_NETWORK=
DOWNLOAD_DIR="/tmp/podkop" DOWNLOAD_DIR="/tmp/podkop"
COUNT=3 COUNT=3
UPGRADE=0
rm -rf "$DOWNLOAD_DIR" rm -rf "$DOWNLOAD_DIR"
mkdir -p "$DOWNLOAD_DIR" mkdir -p "$DOWNLOAD_DIR"
for arg in "$@"; do msg() {
if [ "$arg" = "--upgrade" ]; then printf "\033[32;1m%s\033[0m\n" "$1"
UPGRADE=1 }
fi
done
main() { main() {
check_system check_system
sing_box sing_box
opkg update /usr/sbin/ntpd -q -p 194.190.168.1 -p 216.239.35.0 -p 216.239.35.4 -p 162.159.200.1 -p 162.159.200.123
opkg update || { echo "opkg update failed"; exit 1; }
if [ -f "/etc/init.d/podkop" ]; then if [ -f "/etc/init.d/podkop" ]; then
if [ "$UPGRADE" -eq 1 ]; then msg "Podkop is already installed. Upgraded..."
echo "Upgraded podkop with flag..."
break
else
printf "\033[32;1mPodkop is already installed. Just upgrade it?\033[0m\n"
printf "\033[32;1my - Only upgrade podkop\033[0m\n"
printf "\033[32;1mn - Upgrade and install tunnels (WG, AWG, OpenVPN, OC)\033[0m\n"
while true; do
printf "\033[32;1mEnter (y/n): \033[0m"
read -r -p '' UPDATE
case $UPDATE in
y)
echo "Upgraded podkop..."
break
;;
n)
add_tunnel
break
;;
*)
echo "Please enter y or n"
;;
esac
done
fi
else else
echo "Installed podkop..." msg "Installed podkop..."
add_tunnel
fi fi
if command -v curl &> /dev/null; then if command -v curl &> /dev/null; then
check_response=$(curl -s "https://api.github.com/repos/itdoginfo/podkop/releases/latest") check_response=$(curl -s "https://api.github.com/repos/itdoginfo/podkop/releases/latest")
if echo "$check_response" | grep -q 'API rate limit '; then if echo "$check_response" | grep -q 'API rate limit '; then
echo "You've reached rate limit from GitHub. Repeat in five minutes." msg "You've reached rate limit from GitHub. Repeat in five minutes."
exit 1 exit 1
fi fi
fi fi
@@ -72,33 +41,33 @@ main() {
attempt=0 attempt=0
while [ $attempt -lt $COUNT ]; do while [ $attempt -lt $COUNT ]; do
echo "Download $filename (count $((attempt+1)))..." msg "Download $filename (count $((attempt+1)))..."
if wget -q -O "$filepath" "$url"; then if wget -q -O "$filepath" "$url"; then
if [ -s "$filepath" ]; then if [ -s "$filepath" ]; then
echo "$filename successfully downloaded" msg "$filename successfully downloaded"
download_success=1 download_success=1
break break
fi fi
fi fi
echo "Download error $filename. Retry..." msg "Download error $filename. Retry..."
rm -f "$filepath" rm -f "$filepath"
attempt=$((attempt+1)) attempt=$((attempt+1))
done done
if [ $attempt -eq $COUNT ]; then if [ $attempt -eq $COUNT ]; then
echo "Failed to download $filename after $COUNT attempts" msg "Failed to download $filename after $COUNT attempts"
fi fi
done < <(wget -qO- "$REPO" | grep -o 'https://[^"[:space:]]*\.ipk') done < <(wget -qO- "$REPO" | grep -o 'https://[^"[:space:]]*\.ipk')
if [ $download_success -eq 0 ]; then if [ $download_success -eq 0 ]; then
echo "No packages were downloaded successfully" msg "No packages were downloaded successfully"
exit 1 exit 1
fi fi
for pkg in podkop luci-app-podkop; do for pkg in podkop luci-app-podkop; do
file=$(ls "$DOWNLOAD_DIR" | grep "^$pkg" | head -n 1) file=$(ls "$DOWNLOAD_DIR" | grep "^$pkg" | head -n 1)
if [ -n "$file" ]; then if [ -n "$file" ]; then
echo "Installing $file" msg "Installing $file"
opkg install "$DOWNLOAD_DIR/$file" opkg install "$DOWNLOAD_DIR/$file"
sleep 3 sleep 3
fi fi
@@ -106,341 +75,57 @@ main() {
ru=$(ls "$DOWNLOAD_DIR" | grep "luci-i18n-podkop-ru" | head -n 1) ru=$(ls "$DOWNLOAD_DIR" | grep "luci-i18n-podkop-ru" | head -n 1)
if [ -n "$ru" ]; then if [ -n "$ru" ]; then
printf "\033[32;1mРусский язык интерфейса ставим? y/n (Need a Russian translation?)\033[0m " if opkg list-installed | grep -q luci-i18n-podkop-ru; then
while true; do msg "Upgraded ru translation..."
read -r -p '' RUS
case $RUS in
y)
opkg remove luci-i18n-podkop* opkg remove luci-i18n-podkop*
opkg install "$DOWNLOAD_DIR/$ru" opkg install "$DOWNLOAD_DIR/$ru"
break else
;; msg "Русский язык интерфейса ставим? y/n (Need a Russian translation?)"
n) while true; do
break read -r -p '' RUS
;; case $RUS in
*) y)
echo "Введите y или n" opkg remove luci-i18n-podkop*
;; opkg install "$DOWNLOAD_DIR/$ru"
esac break
done ;;
n)
break
;;
*)
echo "Введите y или n"
;;
esac
done
fi
fi fi
find "$DOWNLOAD_DIR" -type f -name '*podkop*' -exec rm {} \; find "$DOWNLOAD_DIR" -type f -name '*podkop*' -exec rm {} \;
if [ "$IS_SHOULD_RESTART_NETWORK" ]; then
printf "\033[32;1mRestart network\033[0m\n"
/etc/init.d/network restart
fi
}
add_tunnel() {
printf "\033[32;1mWill you be using Wireguard, AmneziaWG, OpenVPN, OpenConnect? If yes, select a number and they will be automatically installed\033[0m\n"
echo "1) Wireguard"
echo "2) AmneziaWG"
echo "3) OpenVPN"
echo "4) OpenConnect"
echo "5) I use VLESS/SS. Skip this step"
while true; do
read -r -p '' TUNNEL
case $TUNNEL in
1)
opkg install wireguard-tools luci-proto-wireguard luci-app-wireguard
printf "\033[32;1mDo you want to configure the wireguard interface? (y/n): \033[0m\n"
read IS_SHOULD_CONFIGURE_WG_INTERFACE
if [ "$IS_SHOULD_CONFIGURE_WG_INTERFACE" = "y" ] || [ "$IS_SHOULD_CONFIGURE_WG_INTERFACE" = "Y" ]; then
wg_awg_setup Wireguard
else
printf "\e[1;32mUse these instructions to manual configure https://itdog.info/nastrojka-klienta-wireguard-na-openwrt/\e[0m\n"
fi
break
;;
2)
install_awg_packages
printf "\033[32;1mThere are no instructions for manual configure yet. Do you want to configure the amneziawg interface? (y/n): \033[0m\n"
read IS_SHOULD_CONFIGURE_WG_INTERFACE
if [ "$IS_SHOULD_CONFIGURE_WG_INTERFACE" = "y" ] || [ "$IS_SHOULD_CONFIGURE_WG_INTERFACE" = "Y" ]; then
wg_awg_setup AmneziaWG
fi
break
;;
3)
opkg install openvpn-openssl luci-app-openvpn
printf "\e[1;32mUse these instructions to configure https://itdog.info/nastrojka-klienta-openvpn-na-openwrt/\e[0m\n"
break
;;
4)
opkg install openconnect luci-proto-openconnect
printf "\e[1;32mUse these instructions to configure https://itdog.info/nastrojka-klienta-openconnect-na-openwrt/\e[0m\n"
break
;;
5)
echo "Installation without additional dependencies."
break
;;
*)
echo "Choose from the following options"
;;
esac
done
}
handler_network_restart() {
IS_SHOULD_RESTART_NETWORK=true
}
install_awg_packages() {
# Получение pkgarch с наибольшим приоритетом
PKGARCH=$(opkg print-architecture | awk 'BEGIN {max=0} {if ($3 > max) {max = $3; arch = $2}} END {print arch}')
TARGET=$(ubus call system board | jsonfilter -e '@.release.target' | cut -d '/' -f 1)
SUBTARGET=$(ubus call system board | jsonfilter -e '@.release.target' | cut -d '/' -f 2)
VERSION=$(ubus call system board | jsonfilter -e '@.release.version')
PKGPOSTFIX="_v${VERSION}_${PKGARCH}_${TARGET}_${SUBTARGET}.ipk"
BASE_URL="https://github.com/Slava-Shchipunov/awg-openwrt/releases/download/"
AWG_DIR="/tmp/amneziawg"
mkdir -p "$AWG_DIR"
if opkg list-installed | grep -q kmod-amneziawg; then
echo "kmod-amneziawg already installed"
else
KMOD_AMNEZIAWG_FILENAME="kmod-amneziawg${PKGPOSTFIX}"
DOWNLOAD_URL="${BASE_URL}v${VERSION}/${KMOD_AMNEZIAWG_FILENAME}"
wget -O "$AWG_DIR/$KMOD_AMNEZIAWG_FILENAME" "$DOWNLOAD_URL"
if [ $? -eq 0 ]; then
echo "kmod-amneziawg file downloaded successfully"
else
echo "Error downloading kmod-amneziawg. Please, install kmod-amneziawg manually and run the script again"
exit 1
fi
opkg install "$AWG_DIR/$KMOD_AMNEZIAWG_FILENAME"
if [ $? -eq 0 ]; then
echo "kmod-amneziawg file downloaded successfully"
else
echo "Error installing kmod-amneziawg. Please, install kmod-amneziawg manually and run the script again"
exit 1
fi
fi
if opkg list-installed | grep -q amneziawg-tools; then
echo "amneziawg-tools already installed"
else
AMNEZIAWG_TOOLS_FILENAME="amneziawg-tools${PKGPOSTFIX}"
DOWNLOAD_URL="${BASE_URL}v${VERSION}/${AMNEZIAWG_TOOLS_FILENAME}"
wget -O "$AWG_DIR/$AMNEZIAWG_TOOLS_FILENAME" "$DOWNLOAD_URL"
if [ $? -eq 0 ]; then
echo "amneziawg-tools file downloaded successfully"
else
echo "Error downloading amneziawg-tools. Please, install amneziawg-tools manually and run the script again"
exit 1
fi
opkg install "$AWG_DIR/$AMNEZIAWG_TOOLS_FILENAME"
if [ $? -eq 0 ]; then
echo "amneziawg-tools file downloaded successfully"
else
echo "Error installing amneziawg-tools. Please, install amneziawg-tools manually and run the script again"
exit 1
fi
fi
if opkg list-installed | grep -qE 'luci-app-amneziawg|luci-proto-amneziawg'; then
echo "luci-app-amneziawg or luci-proto-amneziawg already installed"
else
LUCI_APP_AMNEZIAWG_FILENAME="luci-app-amneziawg${PKGPOSTFIX}"
DOWNLOAD_URL="${BASE_URL}v${VERSION}/${LUCI_APP_AMNEZIAWG_FILENAME}"
wget -O "$AWG_DIR/$LUCI_APP_AMNEZIAWG_FILENAME" "$DOWNLOAD_URL"
if [ $? -eq 0 ]; then
echo "luci-app-amneziawg file downloaded successfully"
else
echo "Error downloading luci-app-amneziawg. Please, install luci-app-amneziawg manually and run the script again"
exit 1
fi
opkg install "$AWG_DIR/$LUCI_APP_AMNEZIAWG_FILENAME"
if [ $? -eq 0 ]; then
echo "luci-app-amneziawg file downloaded successfully"
else
echo "Error installing luci-app-amneziawg. Please, install luci-app-amneziawg manually and run the script again"
exit 1
fi
fi
rm -rf "$AWG_DIR"
}
wg_awg_setup() {
PROTOCOL_NAME=$1
printf "\033[32;1mConfigure ${PROTOCOL_NAME}\033[0m\n"
if [ "$PROTOCOL_NAME" = 'Wireguard' ]; then
INTERFACE_NAME="wg0"
CONFIG_NAME="wireguard_wg0"
PROTO="wireguard"
ZONE_NAME="wg"
fi
if [ "$PROTOCOL_NAME" = 'AmneziaWG' ]; then
INTERFACE_NAME="awg0"
CONFIG_NAME="amneziawg_awg0"
PROTO="amneziawg"
ZONE_NAME="awg"
echo "Do you want to use AmneziaWG config or basic Wireguard config + automatic obfuscation?"
echo "1) AmneziaWG"
echo "2) Wireguard + automatic obfuscation"
read CONFIG_TYPE
fi
read -r -p "Enter the private key (from [Interface]):"$'\n' WG_PRIVATE_KEY_INT
while true; do
read -r -p "Enter internal IP address with subnet, example 192.168.100.5/24 (from [Interface]):"$'\n' WG_IP
if echo "$WG_IP" | egrep -oq '^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]+$'; then
break
else
echo "This IP is not valid. Please repeat"
fi
done
read -r -p "Enter the public key (from [Peer]):"$'\n' WG_PUBLIC_KEY_INT
read -r -p "If use PresharedKey, Enter this (from [Peer]). If your don't use leave blank:"$'\n' WG_PRESHARED_KEY_INT
read -r -p "Enter Endpoint host without port (Domain or IP) (from [Peer]):"$'\n' WG_ENDPOINT_INT
read -r -p "Enter Endpoint host port (from [Peer]) [51820]:"$'\n' WG_ENDPOINT_PORT_INT
WG_ENDPOINT_PORT_INT=${WG_ENDPOINT_PORT_INT:-51820}
if [ "$WG_ENDPOINT_PORT_INT" = '51820' ]; then
echo $WG_ENDPOINT_PORT_INT
fi
if [ "$PROTOCOL_NAME" = 'AmneziaWG' ]; then
if [ "$CONFIG_TYPE" = '1' ]; then
read -r -p "Enter Jc value (from [Interface]):"$'\n' AWG_JC
read -r -p "Enter Jmin value (from [Interface]):"$'\n' AWG_JMIN
read -r -p "Enter Jmax value (from [Interface]):"$'\n' AWG_JMAX
read -r -p "Enter S1 value (from [Interface]):"$'\n' AWG_S1
read -r -p "Enter S2 value (from [Interface]):"$'\n' AWG_S2
read -r -p "Enter H1 value (from [Interface]):"$'\n' AWG_H1
read -r -p "Enter H2 value (from [Interface]):"$'\n' AWG_H2
read -r -p "Enter H3 value (from [Interface]):"$'\n' AWG_H3
read -r -p "Enter H4 value (from [Interface]):"$'\n' AWG_H4
elif [ "$CONFIG_TYPE" = '2' ]; then
#Default values to wg automatic obfuscation
AWG_JC=4
AWG_JMIN=40
AWG_JMAX=70
AWG_S1=0
AWG_S2=0
AWG_H1=1
AWG_H2=2
AWG_H3=3
AWG_H4=4
fi
fi
uci set network.${INTERFACE_NAME}=interface
uci set network.${INTERFACE_NAME}.proto=$PROTO
uci set network.${INTERFACE_NAME}.private_key=$WG_PRIVATE_KEY_INT
uci set network.${INTERFACE_NAME}.listen_port='51821'
uci set network.${INTERFACE_NAME}.addresses=$WG_IP
if [ "$PROTOCOL_NAME" = 'AmneziaWG' ]; then
uci set network.${INTERFACE_NAME}.awg_jc=$AWG_JC
uci set network.${INTERFACE_NAME}.awg_jmin=$AWG_JMIN
uci set network.${INTERFACE_NAME}.awg_jmax=$AWG_JMAX
uci set network.${INTERFACE_NAME}.awg_s1=$AWG_S1
uci set network.${INTERFACE_NAME}.awg_s2=$AWG_S2
uci set network.${INTERFACE_NAME}.awg_h1=$AWG_H1
uci set network.${INTERFACE_NAME}.awg_h2=$AWG_H2
uci set network.${INTERFACE_NAME}.awg_h3=$AWG_H3
uci set network.${INTERFACE_NAME}.awg_h4=$AWG_H4
fi
if ! uci show network | grep -q ${CONFIG_NAME}; then
uci add network ${CONFIG_NAME}
fi
uci set network.@${CONFIG_NAME}[0]=$CONFIG_NAME
uci set network.@${CONFIG_NAME}[0].name="${INTERFACE_NAME}_client"
uci set network.@${CONFIG_NAME}[0].public_key=$WG_PUBLIC_KEY_INT
uci set network.@${CONFIG_NAME}[0].preshared_key=$WG_PRESHARED_KEY_INT
uci set network.@${CONFIG_NAME}[0].route_allowed_ips='0'
uci set network.@${CONFIG_NAME}[0].persistent_keepalive='25'
uci set network.@${CONFIG_NAME}[0].endpoint_host=$WG_ENDPOINT_INT
uci set network.@${CONFIG_NAME}[0].allowed_ips='0.0.0.0/0'
uci set network.@${CONFIG_NAME}[0].endpoint_port=$WG_ENDPOINT_PORT_INT
uci commit network
if ! uci show firewall | grep -q "@zone.*name='${ZONE_NAME}'"; then
printf "\033[32;1mZone Create\033[0m\n"
uci add firewall zone
uci set firewall.@zone[-1].name=$ZONE_NAME
uci set firewall.@zone[-1].network=$INTERFACE_NAME
uci set firewall.@zone[-1].forward='REJECT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].input='REJECT'
uci set firewall.@zone[-1].masq='1'
uci set firewall.@zone[-1].mtu_fix='1'
uci set firewall.@zone[-1].family='ipv4'
uci commit firewall
fi
if ! uci show firewall | grep -q "@forwarding.*name='${ZONE_NAME}'"; then
printf "\033[32;1mConfigured forwarding\033[0m\n"
uci add firewall forwarding
uci set firewall.@forwarding[-1]=forwarding
uci set firewall.@forwarding[-1].name="${ZONE_NAME}-lan"
uci set firewall.@forwarding[-1].dest=${ZONE_NAME}
uci set firewall.@forwarding[-1].src='lan'
uci set firewall.@forwarding[-1].family='ipv4'
uci commit firewall
fi
handler_network_restart
} }
check_system() { check_system() {
# Get router model # Get router model
MODEL=$(cat /tmp/sysinfo/model) MODEL=$(cat /tmp/sysinfo/model)
echo "Router model: $MODEL" msg "Router model: $MODEL"
# Check available space # Check available space
AVAILABLE_SPACE=$(df /overlay | awk 'NR==2 {print $4}') AVAILABLE_SPACE=$(df /overlay | awk 'NR==2 {print $4}')
REQUIRED_SPACE=15360 # 15MB in KB REQUIRED_SPACE=15360 # 15MB in KB
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_SPACE" ]; then if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_SPACE" ]; then
printf "\033[31;1mError: Insufficient space in flash\033[0m\n" msg "Error: Insufficient space in flash"
echo "Available: $((AVAILABLE_SPACE/1024))MB" msg "Available: $((AVAILABLE_SPACE/1024))MB"
echo "Required: $((REQUIRED_SPACE/1024))MB" msg "Required: $((REQUIRED_SPACE/1024))MB"
exit 1 exit 1
fi fi
if ! nslookup google.com >/dev/null 2>&1; then if ! nslookup google.com >/dev/null 2>&1; then
printf "\033[31;1mDNS not working\033[0m\n" msg "DNS not working"
exit 1 exit 1
fi fi
if opkg list-installed | grep -q https-dns-proxy; then if opkg list-installed | grep -q https-dns-proxy; then
printf "\033[31;1mСonflicting package detected: https-dns-proxy. Remove? yes/no\033[0m\n" msg "Сonflicting package detected: https-dns-proxy. Remove?"
while true; do while true; do
read -r -p '' DNSPROXY read -r -p '' DNSPROXY
@@ -451,7 +136,7 @@ check_system() {
break break
;; ;;
*) *)
echo "Exit" msg "Exit"
exit 1 exit 1
;; ;;
esac esac
@@ -459,7 +144,7 @@ check_system() {
fi fi
if opkg list-installed | grep -q "iptables-mod-extra"; then if opkg list-installed | grep -q "iptables-mod-extra"; then
printf "\033[31;1mFound incompatible iptables packages. If you're using FriendlyWrt: https://t.me/itdogchat/44512/181082\033[0m\n" msg "Found incompatible iptables packages. If you're using FriendlyWrt: https://t.me/itdogchat/44512/181082"
fi fi
} }
@@ -472,6 +157,8 @@ sing_box() {
required_version="1.11.1" required_version="1.11.1"
if [ "$(echo -e "$sing_box_version\n$required_version" | sort -V | head -n 1)" != "$required_version" ]; then if [ "$(echo -e "$sing_box_version\n$required_version" | sort -V | head -n 1)" != "$required_version" ]; then
msg "sing-box version $sing_box_version is older than required $required_version"
msg "Removing old version..."
opkg remove sing-box opkg remove sing-box
fi fi
} }

View File

@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-podkop PKG_NAME:=luci-app-podkop
PKG_VERSION:=0.4.4 PKG_VERSION:=0.4.6
PKG_RELEASE:=1 PKG_RELEASE:=1
LUCI_TITLE:=LuCI podkop app LUCI_TITLE:=LuCI podkop app

View File

@@ -34,7 +34,7 @@ function createAdditionalSection(mainSection, network) {
o.value('doh', _('DNS over HTTPS (DoH)')); o.value('doh', _('DNS over HTTPS (DoH)'));
o.value('dot', _('DNS over TLS (DoT)')); o.value('dot', _('DNS over TLS (DoT)'));
o.value('udp', _('UDP (Unprotected DNS)')); o.value('udp', _('UDP (Unprotected DNS)'));
o.default = 'doh'; o.default = 'udp';
o.rmempty = false; o.rmempty = false;
o.ucisection = 'main'; o.ucisection = 'main';
@@ -70,6 +70,53 @@ function createAdditionalSection(mainSection, network) {
return true; return true;
}; };
o = mainSection.taboption('additional', form.Flag, 'split_dns_enabled', _('Split DNS'), _('DNS for the list via proxy'));
o.default = '1';
o.rmempty = false;
o.ucisection = 'main';
o = mainSection.taboption('additional', form.ListValue, 'split_dns_type', _('Split DNS Protocol Type'), _('Select DNS protocol for split'));
o.value('doh', _('DNS over HTTPS (DoH)'));
o.value('dot', _('DNS over TLS (DoT)'));
o.value('udp', _('UDP (Unprotected DNS)'));
o.default = 'udp';
o.rmempty = false;
o.depends('split_dns_enabled', '1');
o.ucisection = 'main';
o = mainSection.taboption('additional', form.Value, 'split_dns_server', _('Split DNS Server'), _('Select or enter DNS server address'));
Object.entries(constants.DNS_SERVER_OPTIONS).forEach(([key, label]) => {
o.value(key, _(label));
});
o.default = '1.1.1.1';
o.rmempty = false;
o.depends('split_dns_enabled', '1');
o.ucisection = 'main';
o.validate = function (section_id, value) {
if (!value) {
return _('DNS server address cannot be empty');
}
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
if (ipRegex.test(value)) {
const parts = value.split('.');
for (const part of parts) {
const num = parseInt(part);
if (num < 0 || num > 255) {
return _('IP address parts must be between 0 and 255');
}
}
return true;
}
const domainRegex = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/;
if (!domainRegex.test(value)) {
return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH');
}
return true;
};
o = mainSection.taboption('additional', form.Value, 'dns_rewrite_ttl', _('DNS Rewrite TTL'), _('Time in seconds for DNS record caching (default: 60)')); o = mainSection.taboption('additional', form.Value, 'dns_rewrite_ttl', _('DNS Rewrite TTL'), _('Time in seconds for DNS record caching (default: 60)'));
o.default = '60'; o.default = '60';
o.rmempty = false; o.rmempty = false;

View File

@@ -179,10 +179,6 @@ function createConfigSection(section, map, network) {
if (!params.get('pbk')) return _('Invalid VLESS URL: missing pbk parameter for reality security'); if (!params.get('pbk')) return _('Invalid VLESS URL: missing pbk parameter for reality security');
if (!params.get('fp')) return _('Invalid VLESS URL: missing fp parameter for reality security'); if (!params.get('fp')) return _('Invalid VLESS URL: missing fp parameter for reality security');
} }
if (security === 'tls' && type !== 'tcp' && !params.get('sni')) {
return _('Invalid VLESS URL: missing sni parameter for tls security');
}
} }
return true; return true;

View File

@@ -726,7 +726,7 @@ async function updateDiagnostics() {
updateTextElement('fakeip-browser-status', updateTextElement('fakeip-browser-status',
E('span', { style: `color: ${result.error ? constants.STATUS_COLORS.WARNING : result.color}` }, [ E('span', { style: `color: ${result.error ? constants.STATUS_COLORS.WARNING : result.color}` }, [
result.error ? '! ' : result.state === 'working' ? '✔ ' : result.state === 'not_working' ? '✘ ' : '! ', result.error ? '! ' : result.state === 'working' ? '✔ ' : result.state === 'not_working' ? '✘ ' : '! ',
result.error ? 'check error' : result.state === 'working' ? _('works in browser') : _('not works in browser') result.error ? 'check error' : result.state === 'working' ? _('works in browser') : _('does not work in browser')
]) ])
); );
}); });
@@ -735,7 +735,7 @@ async function updateDiagnostics() {
updateTextElement('fakeip-router-status', updateTextElement('fakeip-router-status',
E('span', { style: `color: ${result.error ? constants.STATUS_COLORS.WARNING : result.color}` }, [ E('span', { style: `color: ${result.error ? constants.STATUS_COLORS.WARNING : result.color}` }, [
result.error ? '! ' : result.state === 'working' ? '✔ ' : result.state === 'not_working' ? '✘ ' : '! ', result.error ? '! ' : result.state === 'working' ? '✔ ' : result.state === 'not_working' ? '✘ ' : '! ',
result.error ? 'check error' : result.state === 'working' ? _('works on router') : _('not works on router') result.error ? 'check error' : result.state === 'working' ? _('works on router') : _('does not work on router')
]) ])
); );
}); });

View File

@@ -30,6 +30,10 @@ return view.extend({
background: var(--background-color-primary); background: var(--background-color-primary);
border-color: var(--border-color-medium); border-color: var(--border-color-medium);
} }
#cbi-podkop:has(.cbi-tab-disabled[data-tab="basic"]) #cbi-podkop-extra {
display: none;
}
</style> </style>
`); `);

View File

@@ -745,10 +745,10 @@ msgstr "Проверка FakeIP через CLI"
msgid "FakeIP CLI Check Results" msgid "FakeIP CLI Check Results"
msgstr "Результаты проверки FakeIP через CLI" msgstr "Результаты проверки FakeIP через CLI"
msgid "not works in browser" msgid "does not work in browser"
msgstr "не работает в браузере" msgstr "не работает в браузере"
msgid "not works on router" msgid "does not work on router"
msgstr "не работает на роутере" msgstr "не работает на роутере"
msgid "Diagnostics" msgid "Diagnostics"

View File

@@ -1096,10 +1096,10 @@ msgstr ""
msgid "FakeIP CLI Check Results" msgid "FakeIP CLI Check Results"
msgstr "" msgstr ""
msgid "not works in browser" msgid "does not work in browser"
msgstr "" msgstr ""
msgid "not works on router" msgid "does not work on router"
msgstr "" msgstr ""
msgid "Diagnostics" msgid "Diagnostics"

View File

@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=podkop PKG_NAME:=podkop
PKG_VERSION:=0.4.4 PKG_VERSION:=0.4.6
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=ITDog <podkop@itdog.info> PKG_MAINTAINER:=ITDog <podkop@itdog.info>

View File

@@ -31,8 +31,11 @@ config main 'main'
option quic_disable '0' option quic_disable '0'
option dont_touch_dhcp '0' option dont_touch_dhcp '0'
option update_interval '1d' option update_interval '1d'
option dns_type 'doh' option dns_type 'udp'
option dns_server '8.8.8.8' option dns_server '8.8.8.8'
option split_dns_enabled '1'
option split_dns_type 'udp'
option split_dns_server '1.1.1.1'
option dns_rewrite_ttl '60' option dns_rewrite_ttl '60'
option cache_file '/tmp/cache.db' option cache_file '/tmp/cache.db'
list iface 'br-lan' list iface 'br-lan'

View File

@@ -35,12 +35,14 @@ service_triggers() {
config_get mon_restart_ifaces "main" "mon_restart_ifaces" config_get mon_restart_ifaces "main" "mon_restart_ifaces"
config_get restart_ifaces "main" "restart_ifaces" config_get restart_ifaces "main" "restart_ifaces"
PROCD_RELOAD_DELAY=2000
procd_open_trigger procd_open_trigger
procd_add_config_trigger "config.change" "$NAME" "$initscript" restart 'on_config_change' procd_add_config_trigger "config.change" "$NAME" "$initscript" restart 'on_config_change'
if [ "$mon_restart_ifaces" = "1" ]; then if [ "$mon_restart_ifaces" = "1" ]; then
for iface in $restart_ifaces; do for iface in $restart_ifaces; do
procd_add_reload_interface_trigger $iface procd_add_interface_trigger "interface.*.up" "$iface" /etc/init.d/podkop reload
done done
fi fi
procd_close_trigger procd_close_trigger

View File

@@ -53,6 +53,10 @@ echolog() {
nolog "$message" nolog "$message"
} }
build_sing_box_config() {
cat > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG"
}
start_main() { start_main() {
log "Starting podkop" log "Starting podkop"
@@ -65,10 +69,6 @@ start_main() {
exit 1 exit 1
fi fi
if opkg list-installed | grep -q iptables-mod-extra; then
log "[critical] Conflicting package detected: iptables-mod-extra"
fi
if grep -qE 'doh_backup_noresolv|doh_backup_server|doh_server' /etc/config/dhcp; then if grep -qE 'doh_backup_noresolv|doh_backup_server|doh_server' /etc/config/dhcp; then
log "[critical] Detected https-dns-proxy in dhcp config. Edit /etc/config/dhcp" log "[critical] Detected https-dns-proxy in dhcp config. Edit /etc/config/dhcp"
fi fi
@@ -76,11 +76,13 @@ start_main() {
migration migration
config_foreach process_validate_service config_foreach process_validate_service
br_netfilter_disable
# Sync time for DoH/DoT # Sync time for DoH/DoT
/usr/sbin/ntpd -q -p 194.190.168.1 -p 216.239.35.0 -p 216.239.35.4 -p 162.159.200.1 -p 162.159.200.123 /usr/sbin/ntpd -q -p 194.190.168.1 -p 216.239.35.0 -p 216.239.35.4 -p 162.159.200.1 -p 162.159.200.123
sleep 2 sleep 1
mkdir -p /tmp/podkop mkdir -p /tmp/podkop
@@ -126,7 +128,7 @@ start_main() {
jq '.experimental.clash_api = { jq '.experimental.clash_api = {
"external_ui": "ui", "external_ui": "ui",
"external_controller": "0.0.0.0:9090" "external_controller": "0.0.0.0:9090"
}' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }' "$SING_BOX_CONFIG" | build_sing_box_config
fi fi
config_get_bool exclude_ntp "main" "exclude_ntp" "0" config_get_bool exclude_ntp "main" "exclude_ntp" "0"
@@ -149,7 +151,6 @@ start_main() {
sing_box_config_check sing_box_config_check
/etc/init.d/sing-box start /etc/init.d/sing-box start
#/etc/init.d/sing-box enable
log "Nice" log "Nice"
} }
@@ -299,6 +300,14 @@ process_validate_service() {
fi fi
} }
br_netfilter_disable() {
if lsmod | grep -q br_netfilter && [ "$(sysctl -n net.bridge.bridge-nf-call-iptables 2>/dev/null)" = "1" ]; then
log "br_netfilter enabled detected. Disabling"
sysctl -w net.bridge.bridge-nf-call-iptables=0
sysctl -w net.bridge.bridge-nf-call-ip6tables=0
fi
}
# Main funcs # Main funcs
route_table_rule_mark() { route_table_rule_mark() {
@@ -416,8 +425,9 @@ dnsmasq_restore() {
log "Removing configuration for dnsmasq" log "Removing configuration for dnsmasq"
local cachesize=$(uci get dhcp.@dnsmasq[0].podkop_cachesize 2>/dev/null) local cachesize=$(uci get dhcp.@dnsmasq[0].podkop_cachesize 2>/dev/null)
if [ -z "$cachesize" ]; then if [[ "$cachesize" == "unset" ]]; then
log "dnsmasq revert: cachesize is unset" log "dnsmasq revert: cachesize is unset"
uci -q delete dhcp.@dnsmasq[0].cachesize
else else
uci set dhcp.@dnsmasq[0].cachesize="$cachesize" uci set dhcp.@dnsmasq[0].cachesize="$cachesize"
fi fi
@@ -557,7 +567,7 @@ prepare_custom_ruleset() {
"type": "local", "type": "local",
"format": "source", "format": "source",
"path": $file "path": $file
}]' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }]' "$SING_BOX_CONFIG" | build_sing_box_config
sing_box_rules $tag $section sing_box_rules $tag $section
sing_box_dns_rule_fakeip_section $tag $tag sing_box_dns_rule_fakeip_section $tag $tag
@@ -674,7 +684,7 @@ add_socks5_for_section() {
"inbound": [$tag], "inbound": [$tag],
"outbound": $section, "outbound": $section,
"action": "route" "action": "route"
}]' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }]' "$SING_BOX_CONFIG" | build_sing_box_config
} }
process_socks5() { process_socks5() {
@@ -731,10 +741,14 @@ sing_box_dns() {
local dns_type local dns_type
local dns_server local dns_server
local resolver_tag="resolver" local resolver_tag="resolver"
local split_resolver_tag="split-resolver"
config_get dns_type "main" "dns_type" "doh" config_get dns_type "main" "dns_type" "doh"
config_get dns_server "main" "dns_server" "1.1.1.1" config_get dns_server "main" "dns_server" "1.1.1.1"
config_get split_dns_enabled "main" "split_dns_enabled" "0"
config_get split_dns_type "main" "split_dns_type" "udp"
config_get split_dns_server "main" "split_dns_server" "1.1.1.1"
local server_json local server_json
local is_ip=$(echo "$dns_server" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' && echo "1" || echo "0") local is_ip=$(echo "$dns_server" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' && echo "1" || echo "0")
@@ -790,20 +804,79 @@ sing_box_dns() {
}]') }]')
fi fi
if [ "$split_dns_enabled" = "1" ]; then
local split_is_ip=$(echo "$split_dns_server" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' && echo "1" || echo "0")
if [ "$split_is_ip" = "0" ]; then
log "Finding working resolver for split DNS"
local split_dns_resolver=$(find_working_resolver)
if [ -z "$split_dns_resolver" ]; then
log "No working resolver found for split DNS, using default"
split_dns_resolver="1.1.1.1"
else
log "Found working resolver for split DNS: $split_dns_resolver"
fi
fi
server_json=$(echo "$server_json" | jq \
--arg type "$split_dns_type" \
--arg server "$split_dns_server" \
--arg split_is_ip "$split_is_ip" \
--arg split_resolver_tag "$split_resolver_tag" \
' .servers += [
{
"tag": "split-dns-server",
"address": (
if $type == "doh" then
"https://" + $server + "/dns-query"
elif $type == "dot" then
"tls://" + $server
else
$server
end
),
"detour": "main"
} + (
if $split_is_ip == "0" then
{"address_resolver": $split_resolver_tag}
else
{}
end
)
]')
if [ "$split_is_ip" = "0" ]; then
server_json=$(echo "$server_json" | jq \
--arg split_resolver_tag "$split_resolver_tag" \
--arg split_dns_resolver "$split_dns_resolver" \
'.servers += [{
"tag": $split_resolver_tag,
"address": $split_dns_resolver
}]')
fi
fi
server_json=$(echo "$server_json" | jq '.servers += [{"tag": "fakeip-server", "address": "fakeip"}]') server_json=$(echo "$server_json" | jq '.servers += [{"tag": "fakeip-server", "address": "fakeip"}]')
jq \ jq \
--argjson dns_config "$server_json" \ --argjson dns_config "$server_json" \
--arg fakeip "$FAKEIP" \ --arg fakeip "$FAKEIP" \
--argjson split_dns_enabled "$split_dns_enabled" \
'.dns = { '.dns = {
"strategy": "ipv4_only", "strategy": "ipv4_only",
"independent_cache": true, "independent_cache": true,
"final": (
if $split_dns_enabled == 1 then
"split-dns-server"
else
"dns-server"
end
),
"fakeip": { "fakeip": {
"enabled": true, "enabled": true,
"inet4_range": $fakeip "inet4_range": $fakeip
}, },
"servers": $dns_config.servers "servers": $dns_config.servers
}' $SING_BOX_CONFIG > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }' "$SING_BOX_CONFIG" | build_sing_box_config
} }
sing_box_create_bypass_ruleset() { sing_box_create_bypass_ruleset() {
@@ -820,7 +893,7 @@ sing_box_create_bypass_ruleset() {
] ]
} }
] ]
}]' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }]' "$SING_BOX_CONFIG" | build_sing_box_config
# Add a rule to route bypass domains to direct-out outbound # Add a rule to route bypass domains to direct-out outbound
jq ' jq '
@@ -829,49 +902,64 @@ sing_box_create_bypass_ruleset() {
"rule_set": ["bypass"], "rule_set": ["bypass"],
"outbound": "main", "outbound": "main",
"action": "route" "action": "route"
}]' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }]' "$SING_BOX_CONFIG" | build_sing_box_config
# Make sure the bypass ruleset is in the fakeip DNS rule # Make sure the bypass ruleset is in the fakeip DNS rule
jq ' jq '
.dns.rules = (.dns.rules | map( .dns.rules = (.dns.rules | map(
if .server == "fakeip-server" then if (.server == "fakeip-server" or (.server == "dns-server" and .invert == true)) then
.rule_set += ["bypass"] if any(.rule_set[]?; . == "bypass") then
else .
. else
.rule_set += ["bypass"]
end
else
.
end end
))' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG ))' "$SING_BOX_CONFIG" | build_sing_box_config
} }
sing_box_dns_rule_fakeip() { sing_box_dns_rule_fakeip() {
local rewrite_ttl local rewrite_ttl
config_get rewrite_ttl "main" "dns_rewrite_ttl" "600" config_get rewrite_ttl "main" "dns_rewrite_ttl" "60"
config_get split_dns_enabled "main" "split_dns_enabled" "0"
log "Configure fakeip route in sing-box and set TTL to $rewrite_ttl seconds" log "Configure fakeip route in sing-box and set TTL to $rewrite_ttl seconds"
jq \ jq \
--arg ttl "$rewrite_ttl" \ --arg ttl "$rewrite_ttl" \
'.dns += { --argjson split_dns_enabled "$split_dns_enabled" \
"rules": [ '.dns.rules = [
{
"query_type": [
"HTTPS"
],
"action": "reject"
},
{ {
"domain_suffix": [ "query_type": [
"use-application-dns.net" "HTTPS"
], ],
"action": "reject" "action": "reject"
}, },
{ {
"server": "fakeip-server", "domain_suffix": [
"domain": "", "use-application-dns.net"
"rewrite_ttl": ($ttl | tonumber), ],
"rule_set": [] "action": "reject"
},
{
"server": "fakeip-server",
"domain": "",
"rewrite_ttl": ($ttl | tonumber),
"rule_set": []
} }
] ]
}' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG + (
if $split_dns_enabled == 1 then
[{
"server": "dns-server",
"domain": "",
"invert": true,
"rule_set": []
}]
else []
end
)' "$SING_BOX_CONFIG" | build_sing_box_config
} }
sing_box_dns_rule_fakeip_section() { sing_box_dns_rule_fakeip_section() {
@@ -882,16 +970,16 @@ sing_box_dns_rule_fakeip_section() {
jq \ jq \
--arg rule_set "$rule_set" \ --arg rule_set "$rule_set" \
'.dns.rules |= map( '.dns.rules |= map(
if .server == "fakeip-server" then if (.server == "fakeip-server" or (.server == "dns-server" and .invert == true)) then
if any(.rule_set[]?; . == $rule_set) then if any(.rule_set[]?; . == $rule_set) then
. .
else else
.rule_set += [$rule_set] .rule_set += [$rule_set]
end end
else else
. .
end end
)' "$SING_BOX_CONFIG" >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" )' "$SING_BOX_CONFIG" | build_sing_box_config
} }
sing_box_cache_file() { sing_box_cache_file() {
@@ -907,7 +995,7 @@ sing_box_cache_file() {
"store_fakeip": true, "store_fakeip": true,
"path": $cache_file "path": $cache_file
} }
}' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }' "$SING_BOX_CONFIG" | build_sing_box_config
} }
sing_box_outdound() { sing_box_outdound() {
@@ -990,7 +1078,7 @@ sing_box_outbound_interface() {
[{"tag": $section, "type": "direct", "bind_interface": $interface}] [{"tag": $section, "type": "direct", "bind_interface": $interface}]
else [] end else [] end
) )
)' "$SING_BOX_CONFIG" > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" )' "$SING_BOX_CONFIG" | build_sing_box_config
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
log "Config updated successfully" log "Config updated successfully"
@@ -1018,7 +1106,7 @@ sing_box_rule_dns() {
} }
], ],
"auto_detect_interface": true "auto_detect_interface": true
}' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }' "$SING_BOX_CONFIG" | build_sing_box_config
} }
sing_box_config_check() { sing_box_config_check() {
@@ -1050,7 +1138,7 @@ sing_box_config_outbound_json() {
[$outbound] [$outbound]
else [] end else [] end
) )
)' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG )' "$SING_BOX_CONFIG" | build_sing_box_config
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
log "Outbound config updated successfully" log "Outbound config updated successfully"
@@ -1113,7 +1201,7 @@ sing_box_config_shadowsocks() {
} + (if $ss_uot == 1 then { "udp_over_tcp": { "enabled": true, "version": 2 } } else {} end)] } + (if $ss_uot == 1 then { "udp_over_tcp": { "enabled": true, "version": 2 } } else {} end)]
else [] end else [] end
) )
)' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG )' "$SING_BOX_CONFIG" | build_sing_box_config
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
log "Config Shadowsocks updated successfully" log "Config Shadowsocks updated successfully"
@@ -1239,7 +1327,7 @@ sing_box_config_vless() {
else . end else . end
else . end else . end
) )
else . end' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG else . end' "$SING_BOX_CONFIG" | build_sing_box_config
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
@@ -1275,7 +1363,7 @@ sing_box_ruleset_domains() {
else else
. .
end end
' /etc/sing-box/config.json > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json /etc/sing-box/config.json ' "$SING_BOX_CONFIG" | build_sing_box_config
log "$domain added to the list for tag $tag" log "$domain added to the list for tag $tag"
else else
@@ -1294,7 +1382,7 @@ sing_box_ruleset_domains() {
} }
] ]
} }
]' /etc/sing-box/config.json > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json /etc/sing-box/config.json ]' "$SING_BOX_CONFIG" | build_sing_box_config
log "$domain added as a new rule set for tag $tag" log "$domain added as a new rule set for tag $tag"
fi fi
@@ -1326,7 +1414,7 @@ sing_box_ruleset_subnets() {
else else
. .
end end
' /etc/sing-box/config.json > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json /etc/sing-box/config.json ' "$SING_BOX_CONFIG" | build_sing_box_config
log "$subnet added to the list for tag $tag" log "$subnet added to the list for tag $tag"
else else
@@ -1345,7 +1433,7 @@ sing_box_ruleset_subnets() {
} }
] ]
} }
]' /etc/sing-box/config.json > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json /etc/sing-box/config.json ]' "$SING_BOX_CONFIG" | build_sing_box_config
log "$subnet added as a new rule set for tag $tag" log "$subnet added as a new rule set for tag $tag"
fi fi
@@ -1428,7 +1516,7 @@ sing_box_ruleset_remote() {
} + } +
(if $detour == "1" then {"download_detour": "main"} else {} end) (if $detour == "1" then {"download_detour": "main"} else {} end)
) )
]' "$SING_BOX_CONFIG" > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" ]' "$SING_BOX_CONFIG" | build_sing_box_config
log "Added new ruleset with tag $tag" log "Added new ruleset with tag $tag"
fi fi
@@ -1502,7 +1590,7 @@ sing_box_rules() {
jq \ jq \
--arg rule_set "$rule_set" \ --arg rule_set "$rule_set" \
'(.route.rules[] | select(.inbound == ["tproxy-in"] and .action == "reject") .rule_set) += [$rule_set]' \ '(.route.rules[] | select(.inbound == ["tproxy-in"] and .action == "reject") .rule_set) += [$rule_set]' \
"$SING_BOX_CONFIG" > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" "$SING_BOX_CONFIG" | build_sing_box_config
else else
# If there is no rule for reject, create a new one with rule_set # If there is no rule for reject, create a new one with rule_set
jq \ jq \
@@ -1511,7 +1599,7 @@ sing_box_rules() {
"inbound": ["tproxy-in"], "inbound": ["tproxy-in"],
"rule_set": [$rule_set], "rule_set": [$rule_set],
"action": "reject" "action": "reject"
}]' "$SING_BOX_CONFIG" > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" }]' "$SING_BOX_CONFIG" | build_sing_box_config
fi fi
return return
else else
@@ -1525,7 +1613,7 @@ sing_box_rules() {
--arg rule_set "$rule_set" \ --arg rule_set "$rule_set" \
--arg outbound "$outbound" \ --arg outbound "$outbound" \
'(.route.rules[] | select(.outbound == $outbound and .inbound == ["tproxy-in"]) .rule_set) += [$rule_set]' \ '(.route.rules[] | select(.outbound == $outbound and .inbound == ["tproxy-in"]) .rule_set) += [$rule_set]' \
"$SING_BOX_CONFIG" >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" "$SING_BOX_CONFIG" | build_sing_box_config
else else
# If there is no rule for tproxy-in, create a new one with rule_set # If there is no rule for tproxy-in, create a new one with rule_set
jq \ jq \
@@ -1536,7 +1624,7 @@ sing_box_rules() {
"rule_set": [$rule_set], "rule_set": [$rule_set],
"outbound": $outbound, "outbound": $outbound,
"action": "route" "action": "route"
}]' "$SING_BOX_CONFIG" >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" }]' "$SING_BOX_CONFIG" | build_sing_box_config
fi fi
fi fi
} }
@@ -1554,7 +1642,7 @@ sing_box_quic_reject() {
. + [$rule] . + [$rule]
end end
) )
)' "$SING_BOX_CONFIG" >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" )' "$SING_BOX_CONFIG" | build_sing_box_config
log "QUIC reject rule added successfully" log "QUIC reject rule added successfully"
fi fi
@@ -1729,15 +1817,13 @@ sing_box_rules_source_ip_cidr() {
local source_ip_cidr="$1" local source_ip_cidr="$1"
local outbound="$2" local outbound="$2"
local current_source_ip_cidr=$(jq -r '.route.rules[] | select(.outbound == "'"$outbound"'" and .action == "route" and (.rule_set | not))' $SING_BOX_CONFIG) local current_source_ip_cidr=$(jq -r '.route.rules[] | select(.outbound == "'"$outbound"'" and .action == "route" and .source_ip_cidr and (.inbound // [] | contains(["tproxy-in"])))' $SING_BOX_CONFIG)
if [[ -n "$current_source_ip_cidr" ]]; then if [[ -n "$current_source_ip_cidr" ]]; then
jq \ jq \
--arg source_ip_cidr "$source_ip_cidr" \ --arg source_ip_cidr "$source_ip_cidr" \
--arg outbound "$outbound" \ --arg outbound "$outbound" \
'(.route.rules[] | select(.outbound == $outbound and .action == "route" and (.rule_set | not)) | .source_ip_cidr) += [$source_ip_cidr]' \ '(.route.rules[] | select(.outbound == $outbound and .action == "route" and .source_ip_cidr and (.inbound // [] | contains(["tproxy-in"]))) | .source_ip_cidr) += [$source_ip_cidr]' "$SING_BOX_CONFIG" | build_sing_box_config
$SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG
else else
jq \ jq \
--arg source_ip_cidr "$source_ip_cidr" \ --arg source_ip_cidr "$source_ip_cidr" \
@@ -1749,7 +1835,7 @@ sing_box_rules_source_ip_cidr() {
"outbound": $outbound, "outbound": $outbound,
"action": "route" "action": "route"
} }
] + .route.rules' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG ] + .route.rules' "$SING_BOX_CONFIG" | build_sing_box_config
fi fi
} }
@@ -1775,7 +1861,7 @@ detour_mixed() {
"inbound": [$tag], "inbound": [$tag],
"outbound": $section, "outbound": $section,
"action": "route" "action": "route"
}]' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG }]' "$SING_BOX_CONFIG" | build_sing_box_config
} }
## nftables ## nftables
@@ -2348,7 +2434,7 @@ sing_box_add_secure_dns_probe_domain() {
--arg domain "$domain" \ --arg domain "$domain" \
--argjson override_port "$override_port" \ --argjson override_port "$override_port" \
'.dns.rules |= map( '.dns.rules |= map(
if .server == "fakeip-server" then if (.server == "fakeip-server" or (.server == "dns-server" and .invert == true)) then
. + { . + {
"domain": $domain "domain": $domain
} }
@@ -2362,7 +2448,7 @@ sing_box_add_secure_dns_probe_domain() {
"action": "route-options", "action": "route-options",
"override_port": $override_port "override_port": $override_port
} }
]' "$SING_BOX_CONFIG" >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" ]' "$SING_BOX_CONFIG" | build_sing_box_config
log "DNS probe domain ${domain} configured with override to port ${override_port}" log "DNS probe domain ${domain} configured with override to port ${override_port}"
} }
@@ -2461,6 +2547,11 @@ global_check() {
done done
fi fi
if [ -d "/etc/init.d/zapret" ]; then
print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "⚠️ Zapret detected"
fi
print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━" print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "➡️ DNS status" print_global "➡️ DNS status"
dns_info=$(check_dns_available) dns_info=$(check_dns_available)