Compare commits

..

28 Commits

Author SHA1 Message Date
itdoginfo
f29b97e495 v0.3.42 2025-05-01 14:17:18 +03:00
itdoginfo
41c21cebcd Fixed validation for ws 2025-04-30 23:43:36 +03:00
itdoginfo
238e99a547 Update 2025-04-30 19:02:31 +03:00
itdoginfo
4f44fcfe99 Update 2025-04-30 14:48:12 +03:00
itdoginfo
9fd2fb9b6e Update 2025-04-30 00:19:42 +03:00
itdoginfo
c0591b25b9 Fix 2025-04-30 00:16:09 +03:00
itdoginfo
97fd392334 Fixed read. Added upgrade flag 2025-04-30 00:11:55 +03:00
itdoginfo
848c784cc0 Fix 2025-04-29 23:49:28 +03:00
itdoginfo
ab971dcd36 Update 2025-04-29 23:48:49 +03:00
itdoginfo
b8d96f28cd Added CF. Fixed https-dns-proxy warning. Masked for static wan 2025-04-29 18:54:50 +03:00
itdoginfo
f2268fd494 v0.3.41. Improved Diagnotics: WAN, WARP, versions, etc 2025-04-29 12:53:29 +03:00
itdoginfo
19897afcdd v0.3.40. Improved Diagnotics 2025-04-28 00:33:07 +03:00
itdoginfo
0e2ea60f01 v0.3.39. Added global check button 2025-04-27 19:29:34 +03:00
itdoginfo
2dc5944961 Fix https-dns-proxy --force-depends 2025-04-27 18:07:58 +03:00
itdoginfo
f65de36804 Detect https-dns-proxy 2025-04-27 15:50:37 +03:00
itdoginfo
19541f8bb3 v0.3.38. fix reload config luci 2025-04-26 22:35:11 +03:00
itdoginfo
aa42c707fe v0.3.37 2025-04-26 17:49:28 +03:00
itdoginfo
bf96f93987 Fix kill stderr. Return if 127.0.0.42 exists 2025-04-26 17:49:04 +03:00
itdoginfo
ff9aad8947 Option enable iface mon 2025-04-26 17:47:52 +03:00
itdoginfo
d9718617bd Option enable iface mon 2025-04-26 17:47:42 +03:00
itdoginfo
e865c9f324 Validate raw network. Path for DoH. Bool for iface monitoring 2025-04-26 17:47:08 +03:00
itdoginfo
7df8bb5826 rmempty proxy url string 2025-04-25 19:29:31 +03:00
itdoginfo
f960358eb6 0.3.36 2025-04-25 10:57:59 +03:00
itdoginfo
ba44966c02 Interface trigger. Disable sing-box autostart. dont touch dhcp. reload without dnsmasq restart 2025-04-24 19:25:08 +03:00
itdoginfo
615241aa37 Merge pull request #88 from Davoyan/patch-1
Update localisation
2025-04-22 11:36:38 +03:00
Davoyan
9a3220d226 Update localisation 2025-04-22 11:24:54 +03:00
itdoginfo
ec8d28857e #82 and #83 2025-04-15 00:42:16 +03:00
itdoginfo
26b49f5bbb Check fix 2025-04-15 00:15:28 +03:00
9 changed files with 358 additions and 111 deletions

View File

@@ -39,9 +39,9 @@ sh <(wget -O - https://raw.githubusercontent.com/itdoginfo/podkop/refs/heads/mai
Скачать пакеты `podkop_*.ipk` и `luci-app-podkop_*.ipk` из релиза. `opkg install` сначала первый, потом второй. Скачать пакеты `podkop_*.ipk` и `luci-app-podkop_*.ipk` из релиза. `opkg install` сначала первый, потом второй.
# Обновление # Обновление
Та же самая команда, что для установки. Скрипт обнаружит уже установленный podkop и предложит обновиться. Та же самая команда, что для установки. Но с флагом **upgrade** сразу передёт к обновлению.
``` ```
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
``` ```
# Удаление # Удаление
@@ -73,16 +73,10 @@ Luci: Services/podkop
**Custom subnets enable** - Добавить подсети или IP-адреса. Для подсетей задать маску. **Custom subnets enable** - Добавить подсети или IP-адреса. Для подсетей задать маску.
# Известные баги
- [x] Не отрабатывает service podkop stop, если podkop запущен и не может, к пример, зарезолвить домен с сломанным DNS
- [x] Update list из remote url domain не удаляет старые домены. А добавляет новые. Для подсетей тоже самое скорее всего. Пересоздавать ruleset?
# ToDo # ToDo
Этот раздел не означает задачи, которые нужно брать и делать. Это общий список хотелок. Если вы хотите помочь, пожалуйста, спросите сначала в телеграмме. Этот раздел не означает задачи, которые нужно брать и делать. Это общий список хотелок. Если вы хотите помочь, пожалуйста, спросите сначала в телеграмме.
- [ ] Сделать галку запрещающую подкопу редачить dhcp. Допилить в исключение вместе с пустыми полями proxy и vpn (нужно wiki) Основные задачи в issues.
- [ ] Рестарт сервиса без рестарта dnsmasq
- [ ] `ash: can't kill pid 9848: No such process` при обновлении
Низкий приоритет Низкий приоритет
- [ ] Галочка, которая режет доступ к doh серверам - [ ] Галочка, которая режет доступ к doh серверам
@@ -94,6 +88,33 @@ Luci: Services/podkop
- [ ] Unit тесты (BATS) - [ ] Unit тесты (BATS)
- [ ] Интеграционые тесты бекенда (OpenWrt rootfs + BATS) - [ ] Интеграционые тесты бекенда (OpenWrt rootfs + BATS)
# Don't touch my dhcp
Нужно в первую очередь, чтоб использовать опцию `server`.
В случае если опция активна, podkop не трогает /etc/config/dhcp. И вам требуется самостоятельно указать следующие значения:
```
option noresolv '1'
option cachesize '0'
list server '127.0.0.42'
```
Без этого podkop работать не будет.
Если нужно до определённых доменов ходить через определённый DNS-сервер, то конфиг выглядит так
```
option noresolv '1'
option cachesize '0'
list server '/itdog.info/1.1.1.1'
list server '127.0.0.42'
```
В этом случае домен и все субдомены ресурса itdog.info будут резолвится через DNS-сервер 1.1.1.1
# Bad WAN
При использовании опции **Interface monitoring** необходимо рестартовать podkop, чтоб init.d подхватил это
```
service podkop restart
```
# Разработка # Разработка
Есть два варианта: Есть два варианта:
- Просто поставить пакет на роутер или виртуалку и прям редактировать через SFTP (opkg install openssh-sftp-server) - Просто поставить пакет на роутер или виртуалку и прям редактировать через SFTP (opkg install openssh-sftp-server)

View File

@@ -5,10 +5,17 @@ REPO="https://api.github.com/repos/itdoginfo/podkop/releases/latest"
IS_SHOULD_RESTART_NETWORK= 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
if [ "$arg" = "--upgrade" ]; then
UPGRADE=1
fi
done
main() { main() {
check_system check_system
sing_box sing_box
@@ -16,28 +23,34 @@ main() {
opkg update opkg update
if [ -f "/etc/init.d/podkop" ]; then if [ -f "/etc/init.d/podkop" ]; then
printf "\033[32;1mPodkop is already installed. Just upgrade it? (y/n)\033[0m\n" if [ "$UPGRADE" -eq 1 ]; then
printf "\033[32;1my - Only upgrade podkop\033[0m\n" echo "Upgraded podkop with flag..."
printf "\033[32;1mn - Upgrade and install tunnels (WG, AWG, OpenVPN, OC)\033[0m\n" 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 while true; do
read -r -p '' UPDATE printf "\033[32;1mEnter (y/n): \033[0m"
case $UPDATE in read -r -p '' UPDATE
y) case $UPDATE in
echo "Upgraded podkop..." y)
break echo "Upgraded podkop..."
;; break
;;
n) n)
add_tunnel add_tunnel
break break
;; ;;
*) *)
echo "Please enter y or n" echo "Please enter y or n"
;; ;;
esac esac
done done
fi
else else
echo "Installed podkop..." echo "Installed podkop..."
add_tunnel add_tunnel
@@ -160,13 +173,13 @@ add_tunnel() {
;; ;;
3) 3)
opkg install opkg install openvpn-openssl luci-app-openvpn 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" printf "\e[1;32mUse these instructions to configure https://itdog.info/nastrojka-klienta-openvpn-na-openwrt/\e[0m\n"
break break
;; ;;
4) 4)
opkg install opkg install openconnect luci-proto-openconnect 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" printf "\e[1;32mUse these instructions to configure https://itdog.info/nastrojka-klienta-openconnect-na-openwrt/\e[0m\n"
break break
;; ;;
@@ -248,8 +261,8 @@ install_awg_packages() {
fi fi
fi fi
if opkg list-installed | grep -q luci-app-amneziawg; then if opkg list-installed | grep -qE 'luci-app-amneziawg|luci-proto-amneziawg'; then
echo "luci-app-amneziawg already installed" echo "luci-app-amneziawg or luci-proto-amneziawg already installed"
else else
LUCI_APP_AMNEZIAWG_FILENAME="luci-app-amneziawg${PKGPOSTFIX}" LUCI_APP_AMNEZIAWG_FILENAME="luci-app-amneziawg${PKGPOSTFIX}"
DOWNLOAD_URL="${BASE_URL}v${VERSION}/${LUCI_APP_AMNEZIAWG_FILENAME}" DOWNLOAD_URL="${BASE_URL}v${VERSION}/${LUCI_APP_AMNEZIAWG_FILENAME}"
@@ -425,6 +438,25 @@ check_system() {
exit 1 exit 1
fi fi
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"
while true; do
read -r -p '' DNSPROXY
case $DNSPROXY in
yes|y|Y|yes)
opkg remove --force-depends luci-app-https-dns-proxy https-dns-proxy
break
;;
*)
echo "Exit"
exit 1
;;
esac
done
fi
if opkg list-installed | grep -qE "iptables|kmod-iptab"; then if opkg list-installed | grep -qE "iptables|kmod-iptab"; then
printf "\033[31;1mFound incompatible iptables packages. If you're using FriendlyWrt: https://t.me/itdogchat/44512/181082\033[0m\n" printf "\033[31;1mFound incompatible iptables packages. If you're using FriendlyWrt: https://t.me/itdogchat/44512/181082\033[0m\n"
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.3.35 PKG_VERSION:=0.3.42
PKG_RELEASE:=1 PKG_RELEASE:=1
LUCI_TITLE:=LuCI podkop app LUCI_TITLE:=LuCI podkop app

View File

@@ -62,6 +62,23 @@ function getNetworkInterfaces(o, section_id, excludeInterfaces = []) {
}); });
} }
function getNetworkNetworks(o, section_id, excludeInterfaces = []) {
return network.getNetworks().then(networks => {
o.keylist = [];
o.vallist = [];
networks.forEach(net => {
const name = net.getName();
const ifname = net.getIfname();
if (name && !excludeInterfaces.includes(name)) {
o.value(name, ifname ? `${name} (${ifname})` : name);
}
});
}).catch(error => {
console.error('Failed to get networks:', error);
});
}
function createConfigSection(section, map, network) { function createConfigSection(section, map, network) {
const s = section; const s = section;
@@ -82,6 +99,7 @@ function createConfigSection(section, map, network) {
o = s.taboption('basic', form.TextValue, 'proxy_string', _('Proxy Configuration URL'), _('')); o = s.taboption('basic', form.TextValue, 'proxy_string', _('Proxy Configuration URL'), _(''));
o.depends('proxy_config_type', 'url'); o.depends('proxy_config_type', 'url');
o.rows = 5; o.rows = 5;
o.rmempty = false;
o.ucisection = s.section; o.ucisection = s.section;
o.sectionDescriptions = new Map(); o.sectionDescriptions = new Map();
o.placeholder = 'vless://uuid@server:port?type=tcp&security=tls#main\n// backup ss://method:pass@server:port\n// backup2 vless://uuid@server:port?type=grpc&security=reality#alt'; o.placeholder = 'vless://uuid@server:port?type=tcp&security=tls#main\n// backup ss://method:pass@server:port\n// backup2 vless://uuid@server:port?type=grpc&security=reality#alt';
@@ -206,9 +224,9 @@ function createConfigSection(section, map, network) {
let params = new URLSearchParams(queryString.split('#')[0]); let params = new URLSearchParams(queryString.split('#')[0]);
let type = params.get('type'); let type = params.get('type');
const validTypes = ['tcp', 'udp', 'grpc', 'http']; const validTypes = ['tcp', 'raw', 'udp', 'grpc', 'http', 'ws'];
if (!type || !validTypes.includes(type)) { if (!type || !validTypes.includes(type)) {
return _('Invalid VLESS URL: type must be one of tcp, udp, grpc, http'); return _('Invalid VLESS URL: type must be one of tcp, raw, udp, grpc, http, ws');
} }
let security = params.get('security'); let security = params.get('security');
@@ -261,7 +279,7 @@ function createConfigSection(section, map, network) {
o.depends('mode', 'vpn'); o.depends('mode', 'vpn');
o.ucisection = s.section; o.ucisection = s.section;
o.load = function (section_id) { o.load = function (section_id) {
return getNetworkInterfaces(this, section_id, ['br-lan', 'eth0', 'eth1', 'wan', 'phy0-ap0', 'phy1-ap0', 'pppoe-wan']).then(() => { return getNetworkInterfaces(this, section_id, ['br-lan', 'eth0', 'eth1', 'wan', 'phy0-ap0', 'phy1-ap0', 'pppoe-wan', 'lan']).then(() => {
return this.super('load', section_id); return this.super('load', section_id);
}); });
}; };
@@ -288,6 +306,7 @@ function createConfigSection(section, map, network) {
o.value('hdrezka', 'HDRezka'); o.value('hdrezka', 'HDRezka');
o.value('tiktok', 'Tik-Tok'); o.value('tiktok', 'Tik-Tok');
o.value('telegram', 'Telegram'); o.value('telegram', 'Telegram');
o.value('cloudflare', 'Cloudflare');
o.depends('domain_list_enabled', '1'); o.depends('domain_list_enabled', '1');
o.rmempty = false; o.rmempty = false;
o.ucisection = s.section; o.ucisection = s.section;
@@ -319,13 +338,13 @@ function createConfigSection(section, map, network) {
} }
if (newValues.includes('russia_inside')) { if (newValues.includes('russia_inside')) {
const allowedWithRussiaInside = ['russia_inside', 'meta', 'twitter', 'discord', 'telegram']; const allowedWithRussiaInside = ['russia_inside', 'meta', 'twitter', 'discord', 'telegram', 'cloudflare'];
const removedServices = newValues.filter(v => !allowedWithRussiaInside.includes(v)); const removedServices = newValues.filter(v => !allowedWithRussiaInside.includes(v));
if (removedServices.length > 0) { if (removedServices.length > 0) {
newValues = newValues.filter(v => allowedWithRussiaInside.includes(v)); newValues = newValues.filter(v => allowedWithRussiaInside.includes(v));
notifications.push(E('p', { class: 'alert-message warning' }, [ notifications.push(E('p', { class: 'alert-message warning' }, [
E('strong', {}, _('Russia inside restrictions')), E('br'), E('strong', {}, _('Russia inside restrictions')), E('br'),
_('Warning: Russia inside can only be used with Meta, Twitter, Discord, and Telegram. %s already in Russia inside and have been removed from selection.') _('Warning: Russia inside can only be used with Meta, Twitter, Discord, Cloudflare and Telegram. %s already in Russia inside and have been removed from selection.')
.format(removedServices.join(', ')) .format(removedServices.join(', '))
])); ]));
} }
@@ -788,7 +807,12 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s
bypassStatus.message bypassStatus.message
]) ])
]) ])
]) ]),
ButtonFactory.createModalButton({
label: _('Global check'),
command: 'global_check',
title: _('Click here for all the info')
})
]), ]),
// Version Information Panel // Version Information Panel
@@ -1026,9 +1050,9 @@ return view.extend({
return true; return true;
} }
const domainRegex = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$/; const domainRegex = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/;
if (!domainRegex.test(value)) { if (!domainRegex.test(value)) {
return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com'); return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH');
} }
return true; return true;
@@ -1087,6 +1111,25 @@ return view.extend({
}); });
}; };
o = mainSection.taboption('additional', form.Flag, 'mon_restart_ifaces', _('Interface monitoring'), _('Interface monitoring for bad WAN'));
o.default = '0';
o.rmempty = false;
o.ucisection = 'main';
o = mainSection.taboption('additional', form.MultiValue, 'restart_ifaces', _('Interface for monitoring'), _('Select the WAN interfaces to be monitored'));
o.ucisection = 'main';
o.depends('mon_restart_ifaces', '1');
o.load = function (section_id) {
return getNetworkNetworks(this, section_id, ['lan', 'loopback']).then(() => {
return this.super('load', section_id);
});
};
o = mainSection.taboption('additional', form.Flag, 'dont_touch_dhcp', _('Dont touch my DHCP!'), _('Podkop will not change the DHCP config'));
o.default = '0';
o.rmempty = false;
o.ucisection = 'main';
// Extra IPs and exclusions (main section) // Extra IPs and exclusions (main section)
o = mainSection.taboption('basic', form.Flag, 'exclude_from_ip_enabled', _('IP for exclusion'), _('Specify local IP addresses that will never use the configured route')); o = mainSection.taboption('basic', form.Flag, 'exclude_from_ip_enabled', _('IP for exclusion'), _('Specify local IP addresses that will never use the configured route'));
o.default = '0'; o.default = '0';

View File

@@ -88,8 +88,8 @@ msgstr "Введите имена доменов без протоколов (п
msgid "User Domains List" msgid "User Domains List"
msgstr "Список пользовательских доменов" msgstr "Список пользовательских доменов"
msgid "Enter domain names separated by comma, space or newline (example: sub.example.com, example.com or one domain per line)" msgid "Enter domain names separated by comma, space or newline. You can add comments after //"
msgstr "Введите имена доменов через запятую, пробел или новую строку (пример: sub.example.com, example.com или один домен на строку)" msgstr "Введите имена доменов, разделяя их запятой, пробелом или с новой строки. Вы можете добавлять комментарии после //"
msgid "Local Domain Lists" msgid "Local Domain Lists"
msgstr "Локальные списки доменов" msgstr "Локальные списки доменов"
@@ -556,6 +556,9 @@ msgstr "Путь должен содержать хотя бы одну дире
msgid "Invalid path format. Must be like /tmp/cache.db" msgid "Invalid path format. Must be like /tmp/cache.db"
msgstr "Неверный формат пути. Пример: /tmp/cache.db" msgstr "Неверный формат пути. Пример: /tmp/cache.db"
msgid "Select the network interface from which the traffic will originate"
msgstr "Выберите сетевой интерфейс, с которого будет исходить трафик"
msgid "Copy to Clipboard" msgid "Copy to Clipboard"
msgstr "Копировать в буфер обмена" msgstr "Копировать в буфер обмена"
@@ -812,4 +815,7 @@ msgid "available"
msgstr "доступен" msgstr "доступен"
msgid "unavailable" msgid "unavailable"
msgstr "недоступен" msgstr "недоступен"
msgid "Apply for SS2022"
msgstr "Применить для SS2022"

View File

@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=podkop PKG_NAME:=podkop
PKG_VERSION:=0.3.35 PKG_VERSION:=0.3.42
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=ITDog <podkop@itdog.info> PKG_MAINTAINER:=ITDog <podkop@itdog.info>
@@ -13,6 +13,7 @@ define Package/podkop
SECTION:=net SECTION:=net
CATEGORY:=Network CATEGORY:=Network
DEPENDS:=+sing-box +curl +jq +kmod-nft-tproxy +coreutils-base64 DEPENDS:=+sing-box +curl +jq +kmod-nft-tproxy +coreutils-base64
CONFLICTS:=https-dns-proxy
TITLE:=Domain routing app TITLE:=Domain routing app
URL:=https://itdog.info URL:=https://itdog.info
PKGARCH:=all PKGARCH:=all

View File

@@ -36,4 +36,6 @@ config main 'main'
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'
option mon_restart_ifaces '0'
#list restart_ifaces 'wan'
option ss_uot '0' option ss_uot '0'

View File

@@ -6,37 +6,16 @@ USE_PROCD=1
script=$(readlink "$initscript") script=$(readlink "$initscript")
NAME="$(basename ${script:-$initscript})" NAME="$(basename ${script:-$initscript})"
config_load "$NAME" config_load "$NAME"
RESOLV_CONF="/etc/resolv.conf"
start_service() { start_service() {
echo "Start podkop" echo "Start podkop"
sing_box_version=$(sing-box version | head -n 1 | awk '{print $3}') config_get mon_restart_ifaces "main" "mon_restart_ifaces"
required_version="1.11.1" config_get restart_ifaces "main" "restart_ifaces"
if [ "$(echo -e "$sing_box_version\n$required_version" | sort -V | head -n 1)" != "$required_version" ]; then
echo "The version of sing-box ($sing_box_version) is lower than the minimum version. Update sing-box: opkg update && opkg remove sing-box && opkg install sing-box"
exit 1
fi
if opkg list-installed | grep -q iptables-mod-extra; then
echo "Conflicting package detected: iptables-mod-extra"
fi
if opkg list-installed | grep -q kmod-ipt-nat; then
echo "Conflicting package detected: kmod-ipt-nat"
fi
if grep -qE 'doh_backup_noresolv|doh_backup_server|doh_server' /etc/config/dhcp; then
printf "\033[31;1mDetected https-dns-proxy. Disable or uninstall it for correct functionality.\033[0m\n"
fi
if { ! grep -q "search lan" "$RESOLV_CONF" || ! grep -q "nameserver 127.0.0.1" "$RESOLV_CONF"; } && ! grep -q "search tail" "$RESOLV_CONF"; then
echo "/etc/resolv.conf does not contain 'search lan' or 'nameserver 127.0.0.1' entries"
fi
procd_open_instance procd_open_instance
procd_set_param command /bin/sh -c "/usr/bin/podkop start" procd_set_param command /usr/bin/podkop start
[ "$mon_restart_ifaces" = "1" ] && [ -n "$restart_ifaces" ] && procd_set_param netdev $restart_ifaces
procd_set_param stdout 1 procd_set_param stdout 1
procd_set_param stderr 1 procd_set_param stderr 1
procd_close_instance procd_close_instance
@@ -46,17 +25,23 @@ stop_service() {
/usr/bin/podkop stop /usr/bin/podkop stop
} }
restart_service() {
stop
start
}
reload_service() { reload_service() {
stop /usr/bin/podkop reload > /dev/null 2>&1
start
} }
service_triggers() { service_triggers() {
echo "service_triggers start" echo "service_triggers start"
procd_add_config_trigger "config.change" "$NAME" "$initscript" reload 'on_config_change'
config_get mon_restart_ifaces "main" "mon_restart_ifaces"
config_get restart_ifaces "main" "restart_ifaces"
procd_open_trigger
procd_add_config_trigger "config.change" "$NAME" "$initscript" restart 'on_config_change'
if [ "$mon_restart_ifaces" = "1" ]; then
for iface in $restart_ifaces; do
procd_add_reload_interface_trigger $iface
done
fi
procd_close_trigger
} }

View File

@@ -15,9 +15,10 @@ SUBNETS_TWITTER="${GITHUB_RAW_URL}/Subnets/IPv4/twitter.lst"
SUBNETS_META="${GITHUB_RAW_URL}/Subnets/IPv4/meta.lst" SUBNETS_META="${GITHUB_RAW_URL}/Subnets/IPv4/meta.lst"
SUBNETS_DISCORD="${GITHUB_RAW_URL}/Subnets/IPv4/discord.lst" SUBNETS_DISCORD="${GITHUB_RAW_URL}/Subnets/IPv4/discord.lst"
SUBNETS_TELERAM="${GITHUB_RAW_URL}/Subnets/IPv4/telegram.lst" SUBNETS_TELERAM="${GITHUB_RAW_URL}/Subnets/IPv4/telegram.lst"
SUBNETS_CLOUDFLARE="${GITHUB_RAW_URL}/Subnets/IPv4/cloudflare.lst"
SING_BOX_CONFIG="/etc/sing-box/config.json" SING_BOX_CONFIG="/etc/sing-box/config.json"
FAKEIP="198.18.0.0/15" FAKEIP="198.18.0.0/15"
VALID_SERVICES="russia_inside russia_outside ukraine_inside geoblock block porn news anime youtube discord meta twitter hdrezka tiktok telegram" VALID_SERVICES="russia_inside russia_outside ukraine_inside geoblock block porn news anime youtube discord meta twitter hdrezka tiktok telegram cloudflare"
DNS_RESOLVERS="1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 9.9.9.9 9.9.9.11 94.140.14.14 94.140.15.15 208.67.220.220 208.67.222.222 77.88.8.1 77.88.8.8" DNS_RESOLVERS="1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 9.9.9.9 9.9.9.11 94.140.14.14 94.140.15.15 208.67.220.220 208.67.222.222 77.88.8.1 77.88.8.8"
TEST_DOMAIN="fakeip.tech-domain.club" TEST_DOMAIN="fakeip.tech-domain.club"
INTERFACES_LIST="" INTERFACES_LIST=""
@@ -45,7 +46,7 @@ nolog() {
echo -e "${CYAN}[$timestamp]${RESET} ${GREEN}$message${RESET}" echo -e "${CYAN}[$timestamp]${RESET} ${GREEN}$message${RESET}"
} }
start() { start_main() {
log "Starting podkop" log "Starting podkop"
# checking # checking
@@ -61,16 +62,8 @@ start() {
log "[critical] Conflicting package detected: iptables-mod-extra" log "[critical] Conflicting package detected: iptables-mod-extra"
fi fi
if opkg list-installed | grep -q kmod-ipt-nat; then
log "[critical] Conflicting package detected: kmod-ipt-nat"
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. Disable or uninstall it for correct functionality." log "[critical] Detected https-dns-proxy in dhcp config. Edit /etc/config/dhcp"
fi
if { ! grep -q "search lan" "$RESOLV_CONF" || ! grep -q "nameserver 127.0.0.1" "$RESOLV_CONF"; } && ! grep -q "search tail" "$RESOLV_CONF"; then
log "[critical] /etc/resolv.conf does not contain 'search lan' or 'nameserver 127.0.0.1' entries"
fi fi
migration migration
@@ -140,7 +133,12 @@ start() {
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 #/etc/init.d/sing-box enable
log "Nice"
}
start() {
start_main
config_get proxy_string "main" "proxy_string" config_get proxy_string "main" "proxy_string"
config_get interface "main" "interface" config_get interface "main" "interface"
@@ -154,13 +152,13 @@ start() {
fi fi
} }
stop() { stop_main() {
log "Stopping the podkop" log "Stopping the podkop"
if [ -f /var/run/podkop_list_update.pid ]; then if [ -f /var/run/podkop_list_update.pid ]; then
pid=$(cat /var/run/podkop_list_update.pid) pid=$(cat /var/run/podkop_list_update.pid)
if kill -0 "$pid"; then if kill -0 "$pid"; then
kill "$pid" kill "$pid" 2>/dev/null
log "Stopped list_update" log "Stopped list_update"
fi fi
rm -f /var/run/podkop_list_update.pid rm -f /var/run/podkop_list_update.pid
@@ -168,11 +166,6 @@ stop() {
remove_cron_job remove_cron_job
config_get_bool dont_touch_dhcp "main" "dont_touch_dhcp" "0"
if [ "$dont_touch_dhcp" -eq 0 ]; then
dnsmasq_restore
fi
rm -rf /tmp/podkop/*.lst rm -rf /tmp/podkop/*.lst
log "Flush nft" log "Flush nft"
@@ -192,8 +185,22 @@ stop() {
log "Stop sing-box" log "Stop sing-box"
/etc/init.d/sing-box stop /etc/init.d/sing-box stop
/etc/init.d/sing-box disable #/etc/init.d/sing-box disable
}
stop() {
config_get_bool dont_touch_dhcp "main" "dont_touch_dhcp" "0"
if [ "$dont_touch_dhcp" -eq 0 ]; then
dnsmasq_restore
fi
stop_main
}
reload() {
log "Podkop reload"
stop_main
start_main
} }
# Migrations and validation funcs # Migrations and validation funcs
@@ -365,7 +372,8 @@ dnsmasq_add_resolver() {
uci -q delete dhcp.@dnsmasq[0].podkop_server uci -q delete dhcp.@dnsmasq[0].podkop_server
for server in $(uci get dhcp.@dnsmasq[0].server 2>/dev/null); do for server in $(uci get dhcp.@dnsmasq[0].server 2>/dev/null); do
if [[ "$server" == "127.0.0.42" ]]; then if [[ "$server" == "127.0.0.42" ]]; then
log "Dnsmasq save config error: server=127.0.0.42" log "Dnsmasq save config error: server=127.0.0.42 is already configured. Skip editing DHCP"
return
else else
uci add_list dhcp.@dnsmasq[0].podkop_server="$server" uci add_list dhcp.@dnsmasq[0].podkop_server="$server"
fi fi
@@ -596,10 +604,12 @@ sing_box_uci() {
log "Change sing-box UCI config" log "Change sing-box UCI config"
fi fi
if grep -q '#\s*list ifaces' "$config"; then [ -f /etc/rc.d/S99sing-box ] && log "Disable sing-box" && /etc/init.d/sing-box disable
sed -i '/ifaces/s/#//g' $config
log "Uncommented list ifaces" # if grep -q '#\s*list ifaces' "$config"; then
fi # sed -i '/ifaces/s/#//g' $config
# log "Uncommented list ifaces"
# fi
} }
add_socks5_for_section() { add_socks5_for_section() {
@@ -1389,6 +1399,9 @@ list_subnets_download() {
"telegram") "telegram")
URL=$SUBNETS_TELERAM URL=$SUBNETS_TELERAM
;; ;;
"cloudflare")
URL=$SUBNETS_CLOUDFLARE
;;
"discord") "discord")
URL=$SUBNETS_DISCORD URL=$SUBNETS_DISCORD
nft add set inet $table podkop_discord_subnets { type ipv4_addr\; flags interval\; auto-merge\; } nft add set inet $table podkop_discord_subnets { type ipv4_addr\; flags interval\; auto-merge\; }
@@ -1818,6 +1831,7 @@ check_sing_box_logs() {
} }
check_fakeip() { check_fakeip() {
# Not used
nolog "Checking fakeip functionality..." nolog "Checking fakeip functionality..."
if ! command -v nslookup >/dev/null 2>&1; then if ! command -v nslookup >/dev/null 2>&1; then
@@ -1940,7 +1954,7 @@ show_sing_box_config() {
} }
show_config() { show_config() {
nolog "Current podkop configuration:" nolog "📄 Current podkop configuration:"
if [ ! -f /etc/config/podkop ]; then if [ ! -f /etc/config/podkop ]; then
nolog "Configuration file not found" nolog "Configuration file not found"
@@ -1959,6 +1973,7 @@ show_config() {
-e 's/\(pbk=[^&]*\)/pbk=MASKED/g' \ -e 's/\(pbk=[^&]*\)/pbk=MASKED/g' \
-e 's/\(sid=[^&]*\)/sid=MASKED/g' \ -e 's/\(sid=[^&]*\)/sid=MASKED/g' \
-e 's/\(option dns_server '\''[^'\'']*\.dns\.nextdns\.io'\''\)/option dns_server '\''MASKED.dns.nextdns.io'\''/g' \ -e 's/\(option dns_server '\''[^'\'']*\.dns\.nextdns\.io'\''\)/option dns_server '\''MASKED.dns.nextdns.io'\''/g' \
-e "s|\(option dns_server 'dns\.nextdns\.io\)/[^']*|\1/MASKED|"
> "$tmp_config" > "$tmp_config"
cat "$tmp_config" cat "$tmp_config"
@@ -1966,17 +1981,17 @@ show_config() {
} }
show_version() { show_version() {
local version=$(opkg info podkop | grep -m 1 "Version:" | cut -d' ' -f2) local version=$(opkg list-installed podkop | awk '{print $3}')
echo "$version" echo "$version"
} }
show_luci_version() { show_luci_version() {
local version=$(opkg info luci-app-podkop | grep -m 1 "Version:" | cut -d' ' -f2) local version=$(opkg list-installed luci-app-podkop | awk '{print $3}')
echo "$version" echo "$version"
} }
show_sing_box_version() { show_sing_box_version() {
local version=$(opkg info sing-box | grep -m 1 "Version:" | cut -d' ' -f2) local version=$(sing-box version | head -n 1 | awk '{print $3}')
echo "$version" echo "$version"
} }
@@ -2076,6 +2091,9 @@ check_dns_available() {
if echo "$dns_server" | grep -q "\.dns\.nextdns\.io$"; then if echo "$dns_server" | grep -q "\.dns\.nextdns\.io$"; then
local nextdns_id=$(echo "$dns_server" | cut -d'.' -f1) local nextdns_id=$(echo "$dns_server" | cut -d'.' -f1)
display_dns_server="$(echo "$nextdns_id" | sed 's/./*/g').dns.nextdns.io" display_dns_server="$(echo "$nextdns_id" | sed 's/./*/g').dns.nextdns.io"
elif echo "$dns_server" | grep -q "^dns\.nextdns\.io/"; then
local masked_path=$(echo "$dns_server" | cut -d'/' -f2- | sed 's/./*/g')
display_dns_server="dns.nextdns.io/$masked_path"
fi fi
if [ "$dns_type" = "doh" ]; then if [ "$dns_type" = "doh" ]; then
@@ -2153,6 +2171,143 @@ sing_box_add_secure_dns_probe_domain() {
log "DNS probe domain ${domain} configured with override to port ${override_port}" log "DNS probe domain ${domain} configured with override to port ${override_port}"
} }
global_check() {
nolog "📡 Global check run!"
nolog "Podkop $(opkg list-installed podkop | awk '{print $3}')"
nolog "LuCi App $(opkg list-installed luci-app-podkop | awk '{print $3}')"
nolog "Sing-box $(sing-box version | head -n 1 | awk '{print $3}')"
nolog "$(grep OPENWRT_RELEASE /etc/os-release | cut -d'"' -f2)"
nolog "Device: $(cat /tmp/sysinfo/model)"
printf "\n"
show_config
printf "\n"
nolog "Checking fakeip functionality..."
nolog "➡️ DNS resolution: system DNS server"
nslookup -timeout=2 $TEST_DOMAIN
local working_resolver=$(find_working_resolver)
if [ -z "$working_resolver" ]; then
nolog "❌ No working resolver found, skipping resolver check"
else
nolog "➡️ DNS resolution: external resolver ($working_resolver)"
nslookup -timeout=2 $TEST_DOMAIN $working_resolver
fi
# Main FakeIP check
nolog "➡️ DNS resolution: sing-box DNS server (127.0.0.42)"
local result=$(nslookup -timeout=2 $TEST_DOMAIN 127.0.0.42 2>&1)
echo "$result"
if echo "$result" | grep -q "198.18"; then
nolog "✅ FakeIP is working correctly! Domain resolved to FakeIP range (198.18.x.x)"
else
nolog "❌ FakeIP test failed. Domain did not resolve to FakeIP range"
nolog "Checking if sing-box is running..."
if ! pgrep -f "sing-box" >/dev/null; then
nolog "sing-box is not running"
else
nolog "sing-box is running, but FakeIP might not be configured correctly"
nolog "Checking DNS configuration in sing-box..."
if [ -f "$SING_BOX_CONFIG" ]; then
local fakeip_enabled=$(jq -r '.dns.fakeip.enabled' "$SING_BOX_CONFIG")
local fakeip_range=$(jq -r '.dns.fakeip.inet4_range' "$SING_BOX_CONFIG")
nolog "FakeIP enabled: $fakeip_enabled"
nolog "FakeIP range: $fakeip_range"
local dns_rules=$(jq -r '.dns.rules[] | select(.server == "fakeip-server") | .domain' "$SING_BOX_CONFIG")
nolog "FakeIP domain: $dns_rules"
else
nolog "sing-box config file not found"
fi
fi
fi
printf "\n"
if grep -E "^nameserver\s+([0-9]{1,3}\.){3}[0-9]{1,3}" "$RESOLV_CONF" | grep -vqE "127\.0\.0\.1|0\.0\.0\.0"; then
nolog "❌ /etc/resolv.conf contains an external nameserver:"
cat /etc/resolv.conf
echo ""
else
nolog "✅ /etc/resolv.conf OK"
fi
cachesize="$(uci get dhcp.@dnsmasq[0].cachesize 2>/dev/null)"
noresolv="$(uci get dhcp.@dnsmasq[0].noresolv 2>/dev/null)"
server="$(uci get dhcp.@dnsmasq[0].server 2>/dev/null)"
if [ "$cachesize" != "0" ] || [ "$noresolv" != "1" ] || [ "$server" != "127.0.0.42" ]; then
nolog "❌ The configuration differs from the template. 📄 DHCP config:"
awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp
elif [ "$(uci get podkop.main.dont_touch_dhcp 2>/dev/null)" = "1" ]; then
nolog "⚠️ Enable dont_touch_dhcp. 📄 DHCP config:"
awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp
else
nolog "✅ /etc/config/dhcp"
fi
if ! pgrep -f "sing-box" >/dev/null; then
nolog "❌ sing-box is not running"
else
nolog "✅ sing-box is running"
fi
nolog "📄 NFT Table Podkop"
if ! nft list table inet PodkopTable >/dev/null 2>&1; then
nolog "PodkopTable not found"
else
nft list table inet PodkopTable
fi
nolog "📄 WAN config"
if uci show network.wan >/dev/null 2>&1; then
awk '
/^config / {
p = ($2 == "interface" && $3 == "'\''wan'\''")
proto = ""
}
p {
if ($1 == "option" && $2 == "proto") {
proto = $3
print
} else if (proto == "'\''static'\''" && $1 == "option" && ($2 == "ipaddr" || $2 == "netmask" || $2 == "gateway")) {
print " option", $2, "'\''******'\''"
} else if (proto == "'\''pppoe'\''" && $1 == "option" && ($2 == "username" || $2 == "password")) {
print " option", $2, "'\''******'\''"
} else {
print
}
}
' /etc/config/network
else
nolog "WAN not exists"
fi
CLOUDFLARE_OCTETS="103.21 103.22 103.31 104.16 104.17 104.18 104.19 104.20 104.21 104.22 104.23 \
104.24 104.25 104.26 104.27 104.28 108.162 131.0 141.101 162.158 162.159 172.64 172.65 172.66 \
172.67 172.68 172.69 172.70 172.71 173.245 188.114 190.93 197.234 198.41"
if uci show network | grep -q endpoint_host; then
uci show network | grep endpoint_host | cut -d'=' -f2 | tr -d "'\" " | while read -r host; do
if [ "$host" = "engage.cloudflareclient.com" ]; then
nolog "⚠️ WARP detected ($host)"
continue
fi
ip_prefix=$(echo "$host" | cut -d'.' -f1,2)
if echo "$CLOUDFLARE_OCTETS" | grep -wq "$ip_prefix"; then
nolog "⚠️ WARP detected ($host)"
fi
done
fi
}
case "$1" in case "$1" in
start) start)
start start
@@ -2160,9 +2315,8 @@ case "$1" in
stop) stop)
stop stop
;; ;;
restart) reload)
stop reload
start
;; ;;
main) main)
main main
@@ -2221,8 +2375,11 @@ case "$1" in
check_dns_available) check_dns_available)
check_dns_available check_dns_available
;; ;;
global_check)
global_check
;;
*) *)
echo "Usage: $0 {start|stop|restart|reload|enable|disable|main|list_update|check_proxy|check_nft|check_github|check_logs|check_sing_box_connections|check_sing_box_logs|check_fakeip|check_dnsmasq|show_config|show_version|show_sing_box_config|show_luci_version|show_sing_box_version|show_system_info|get_status|get_sing_box_status|check_dns_available}" echo "Usage: $0 {start|stop|reload|enable|disable|main|list_update|check_proxy|check_nft|check_github|check_logs|check_sing_box_connections|check_sing_box_logs|check_fakeip|check_dnsmasq|show_config|show_version|show_sing_box_config|show_luci_version|show_sing_box_version|show_system_info|get_status|get_sing_box_status|check_dns_available|global_check}"
exit 1 exit 1
;; ;;
esac esac