Compare commits

...

26 Commits

Author SHA1 Message Date
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
itdoginfo
0a7efb3169 Fix 2025-04-03 17:53:21 +03:00
itdoginfo
468e51ee8e v0.3.35 2025-04-03 17:42:45 +03:00
itdoginfo
3b93a914de v0.3.34 2025-04-03 17:27:35 +03:00
itdoginfo
76c5baf1e2 Fix tailscale smartdns in resolve.conf 2025-04-03 17:27:13 +03:00
itdoginfo
c752c46abf Fix resolv_conf value 2025-04-03 17:24:57 +03:00
itdoginfo
1df1defa5e Check curl 2025-04-03 17:24:31 +03:00
itdoginfo
3cb4be6427 v0.3.33 2025-04-03 16:47:47 +03:00
itdoginfo
25bfdce5ce Added critical log. Rm friendlywrt check. Added iptables check 2025-04-03 16:47:26 +03:00
itdoginfo
6d0f097a07 Merge pull request #75 from itdoginfo/feature/error-notification (#47)
Feature/error notification
2025-04-03 14:52:00 +03:00
Ivan K
5f780955eb 💄 style(podkop): update error log filtering criteria 2025-04-03 13:42:55 +03:00
Ivan K
389def9056 ♻️ refactor(podkop): remove unused createErrorModal function 2025-04-03 13:40:41 +03:00
Ivan K
e816da5133 feat(podkop): add error logging and notification system 2025-04-03 13:36:22 +03:00
Ivan K
e57adbe042 🔒 refactor(config): Mask NextDNS server address in config output 2025-03-30 20:36:49 +03:00
itdoginfo
d78c51360d Merge pull request #73 from itdoginfo/feature/no-more-cache
🐛 fix(doh): Improve DoH server compatibility detection for quad9
2025-03-30 18:44:26 +03:00
Ivan K
c2357337fc 🐛 fix(dns): improve DoH server compatibility and error handling 2025-03-30 17:20:06 +03:00
Ivan K
bc6490b56e 🐛 fix(doh): Improve DoH server compatibility detection for quad9 2025-03-30 17:04:30 +03:00
itdoginfo
2f645d9151 v0.3.32 2025-03-30 16:03:49 +03:00
itdoginfo
94cc65001b Merge pull request #72 from itdoginfo/feature/no-more-cache
🐛 fix(podkop): Handle DNS check errors and timeouts properly
2025-03-30 16:02:44 +03:00
Ivan K
87caa70e97 feat(dns): Mask NextDNS ID in DNS availability check output 2025-03-30 14:53:01 +03:00
Ivan K
90d7c60fcb 🐛 fix(podkop): Handle DNS check errors and timeouts properly 2025-03-30 14:46:03 +03:00
9 changed files with 296 additions and 98 deletions

View File

@@ -80,9 +80,15 @@ Luci: Services/podkop
# ToDo # ToDo
Этот раздел не означает задачи, которые нужно брать и делать. Это общий список хотелок. Если вы хотите помочь, пожалуйста, спросите сначала в телеграмме. Этот раздел не означает задачи, которые нужно брать и делать. Это общий список хотелок. Если вы хотите помочь, пожалуйста, спросите сначала в телеграмме.
- [ ] Interface trigger
- [ ] Управление sing-box с помощью podkop. sing-box disable
- [ ] Сделать галку запрещающую подкопу редачить dhcp. Допилить в исключение вместе с пустыми полями proxy и vpn (нужно wiki) - [ ] Сделать галку запрещающую подкопу редачить dhcp. Допилить в исключение вместе с пустыми полями proxy и vpn (нужно wiki)
- [ ] Рестарт сервиса без рестарта dnsmasq - [ ] Рестарт сервиса без рестарта dnsmasq
- [ ] `ash: can't kill pid 9848: No such process` при обновлении - [ ] `ash: can't kill pid 9848: No such process` при обновлении
- [ ] Luci: Добавить валидацию "Proxy Configuration URL". Если пустое, то ошибка. Как с интерфейсом.
- [ ] После выключения и включения может быть: `Dnsmasq save config error: server=127.0.0.42`
- [ ] Не грузится диагностика полностью при одной нерабочей комманде. Подумать как это можно дебажить легко. https://t.me/itdogchat/142500/378956
- [ ] DoH возможность добавлять сервера c path. Взять пример из NextDNS
Низкий приоритет Низкий приоритет
- [ ] Галочка, которая режет доступ к doh серверам - [ ] Галочка, которая режет доступ к doh серверам
@@ -94,6 +100,17 @@ 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 работать не будет.
# Разработка # Разработка
Есть два варианта: Есть два варианта:
- Просто поставить пакет на роутер или виртуалку и прям редактировать через SFTP (opkg install openssh-sftp-server) - Просто поставить пакет на роутер или виртуалку и прям редактировать через SFTP (opkg install openssh-sftp-server)

View File

@@ -42,12 +42,14 @@ main() {
echo "Installed podkop..." echo "Installed podkop..."
add_tunnel add_tunnel
fi fi
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
echo "You've reached rate limit from GitHub. Repeat in five minutes."
if echo "$check_response" | grep -q 'API rate limit '; then exit 1
echo "You've reached rate limit from GitHub. Repeat in five minutes." fi
exit 1
fi fi
download_success=0 download_success=0
@@ -158,13 +160,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
;; ;;
@@ -246,8 +248,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}"

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.31 PKG_VERSION:=0.3.36
PKG_RELEASE:=1 PKG_RELEASE:=1
LUCI_TITLE:=LuCI podkop app LUCI_TITLE:=LuCI podkop app

View File

@@ -12,6 +12,8 @@ const STATUS_COLORS = {
WARNING: '#ff9800' WARNING: '#ff9800'
}; };
const ERROR_POLL_INTERVAL = 5000; // 5 seconds
async function safeExec(command, args = [], timeout = 7000) { async function safeExec(command, args = [], timeout = 7000) {
try { try {
const controller = new AbortController(); const controller = new AbortController();
@@ -60,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;
@@ -813,20 +832,34 @@ function checkDNSAvailability() {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
try { try {
const dnsStatusResult = await safeExec('/usr/bin/podkop', ['check_dns_available']); const dnsStatusResult = await safeExec('/usr/bin/podkop', ['check_dns_available']);
const dnsStatus = JSON.parse(dnsStatusResult.stdout || '{"dns_type":"unknown","dns_server":"unknown","is_available":0,"status":"unknown","local_dns_working":0,"local_dns_status":"unknown"}'); if (!dnsStatusResult || !dnsStatusResult.stdout) {
return resolve({
remote: createStatus('error', 'DNS check timeout', 'WARNING'),
local: createStatus('error', 'DNS check timeout', 'WARNING')
});
}
const remoteStatus = dnsStatus.is_available ? try {
createStatus('available', `${dnsStatus.dns_type.toUpperCase()} (${dnsStatus.dns_server}) available`, 'SUCCESS') : const dnsStatus = JSON.parse(dnsStatusResult.stdout);
createStatus('unavailable', `${dnsStatus.dns_type.toUpperCase()} (${dnsStatus.dns_server}) unavailable`, 'ERROR');
const localStatus = dnsStatus.local_dns_working ? const remoteStatus = dnsStatus.is_available ?
createStatus('available', 'Router DNS working', 'SUCCESS') : createStatus('available', `${dnsStatus.dns_type.toUpperCase()} (${dnsStatus.dns_server}) available`, 'SUCCESS') :
createStatus('unavailable', 'Router DNS not working', 'ERROR'); createStatus('unavailable', `${dnsStatus.dns_type.toUpperCase()} (${dnsStatus.dns_server}) unavailable`, 'ERROR');
return resolve({ const localStatus = dnsStatus.local_dns_working ?
remote: remoteStatus, createStatus('available', 'Router DNS working', 'SUCCESS') :
local: localStatus createStatus('unavailable', 'Router DNS not working', 'ERROR');
});
return resolve({
remote: remoteStatus,
local: localStatus
});
} catch (parseError) {
return resolve({
remote: createStatus('error', 'DNS check parse error', 'WARNING'),
local: createStatus('error', 'DNS check parse error', 'WARNING')
});
}
} catch (error) { } catch (error) {
return resolve({ return resolve({
remote: createStatus('error', 'DNS check error', 'WARNING'), remote: createStatus('error', 'DNS check error', 'WARNING'),
@@ -836,6 +869,84 @@ function checkDNSAvailability() {
}); });
} }
async function getPodkopErrors() {
try {
const result = await safeExec('/usr/bin/podkop', ['check_logs']);
if (!result || !result.stdout) return [];
const logs = result.stdout.split('\n');
const errors = logs.filter(log =>
// log.includes('saved for future filters') ||
log.includes('[critical]')
);
console.log('Found errors:', errors);
return errors;
} catch (error) {
console.error('Error getting podkop logs:', error);
return [];
}
}
let errorPollTimer = null;
let lastErrorsSet = new Set();
let isInitialCheck = true;
function showErrorNotification(error, isMultiple = false) {
const notificationContent = E('div', { 'class': 'alert-message error' }, [
E('pre', { 'class': 'error-log' }, error)
]);
ui.addNotification(null, notificationContent);
}
function startErrorPolling() {
if (errorPollTimer) {
clearInterval(errorPollTimer);
}
async function checkErrors() {
const result = await safeExec('/usr/bin/podkop', ['check_logs']);
if (!result || !result.stdout) return;
const logs = result.stdout;
const errorLines = logs.split('\n').filter(line =>
// line.includes('saved for future filters') ||
line.includes('[critical]')
);
if (errorLines.length > 0) {
const currentErrors = new Set(errorLines);
if (isInitialCheck) {
if (errorLines.length > 0) {
showErrorNotification(errorLines.join('\n'), true);
}
isInitialCheck = false;
} else {
const newErrors = [...currentErrors].filter(error => !lastErrorsSet.has(error));
newErrors.forEach(error => {
showErrorNotification(error, false);
});
}
lastErrorsSet = currentErrors;
}
}
checkErrors();
errorPollTimer = setInterval(checkErrors, ERROR_POLL_INTERVAL);
}
function stopErrorPolling() {
if (errorPollTimer) {
clearInterval(errorPollTimer);
errorPollTimer = null;
}
}
return view.extend({ return view.extend({
async render() { async render() {
document.head.insertAdjacentHTML('beforeend', ` document.head.insertAdjacentHTML('beforeend', `
@@ -993,6 +1104,20 @@ return view.extend({
}); });
}; };
o = mainSection.taboption('additional', form.MultiValue, 'restart_ifaces', _('Interface for monitoring'), _('Select the WAN interfaces to be monitored'));
o.ucisection = 'main';
o.default = 'wan';
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';
@@ -1334,8 +1459,10 @@ return view.extend({
const diagnosticsContainer = document.getElementById('diagnostics-status'); const diagnosticsContainer = document.getElementById('diagnostics-status');
if (document.hidden) { if (document.hidden) {
stopDiagnosticsUpdates(); stopDiagnosticsUpdates();
stopErrorPolling();
} else if (diagnosticsContainer && diagnosticsContainer.hasAttribute('data-loading')) { } else if (diagnosticsContainer && diagnosticsContainer.hasAttribute('data-loading')) {
startDiagnosticsUpdates(); startDiagnosticsUpdates();
startErrorPolling();
} }
}); });
@@ -1346,6 +1473,7 @@ return view.extend({
if (!this.hasAttribute('data-loading')) { if (!this.hasAttribute('data-loading')) {
this.setAttribute('data-loading', 'true'); this.setAttribute('data-loading', 'true');
startDiagnosticsUpdates(); startDiagnosticsUpdates();
startErrorPolling();
} }
}); });
} }
@@ -1361,9 +1489,11 @@ return view.extend({
if (container && !container.hasAttribute('data-loading')) { if (container && !container.hasAttribute('data-loading')) {
container.setAttribute('data-loading', 'true'); container.setAttribute('data-loading', 'true');
startDiagnosticsUpdates(); startDiagnosticsUpdates();
startErrorPolling();
} }
} else { } else {
stopDiagnosticsUpdates(); stopDiagnosticsUpdates();
stopErrorPolling();
} }
} }
}); });
@@ -1374,6 +1504,7 @@ return view.extend({
if (container && !container.hasAttribute('data-loading')) { if (container && !container.hasAttribute('data-loading')) {
container.setAttribute('data-loading', 'true'); container.setAttribute('data-loading', 'true');
startDiagnosticsUpdates(); startDiagnosticsUpdates();
startErrorPolling();
} }
} }
} }

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.31 PKG_VERSION:=0.3.36
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=ITDog <podkop@itdog.info> PKG_MAINTAINER:=ITDog <podkop@itdog.info>

View File

@@ -36,4 +36,5 @@ 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'
list restart_ifaces 'wan'
option ss_uot '0' option ss_uot '0'

View File

@@ -6,38 +6,15 @@ 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 restart_ifaces "main" "restart_ifaces"
required_version="1.11.1"
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 grep -q FriendlyWrt /etc/banner; then
printf "\033[31;1mYou use FriendlyWrt. If you have problems, check out: https://t.me/itdogchat/44512/181082\033[0m\n"
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 ! ip addr | grep -q "br-lan"; then
echo "Interface br-lan not found"
exit 1
fi
if ! grep -q "search lan" "$resolv_conf" || ! grep -q "nameserver 127.0.0.1" "$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
[ -z "$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
@@ -47,17 +24,19 @@ 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 restart_ifaces "main" "restart_ifaces"
procd_open_trigger
procd_add_config_trigger "config.change" "$NAME" "$initscript" reload 'on_config_change'
for iface in $restart_ifaces; do
procd_add_reload_interface_trigger $iface
done
procd_close_trigger
} }

View File

@@ -22,6 +22,7 @@ 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.
TEST_DOMAIN="fakeip.tech-domain.club" TEST_DOMAIN="fakeip.tech-domain.club"
INTERFACES_LIST="" INTERFACES_LIST=""
SRC_INTERFACE="" SRC_INTERFACE=""
RESOLV_CONF="/etc/resolv.conf"
log() { log() {
local message="$1" local message="$1"
@@ -44,7 +45,30 @@ nolog() {
echo -e "${CYAN}[$timestamp]${RESET} ${GREEN}$message${RESET}" echo -e "${CYAN}[$timestamp]${RESET} ${GREEN}$message${RESET}"
} }
start() { start_main() {
log "Starting podkop"
# checking
sing_box_version=$(sing-box version | head -n 1 | awk '{print $3}')
required_version="1.11.1"
if [ "$(echo -e "$sing_box_version\n$required_version" | sort -V | head -n 1)" != "$required_version" ]; then
log "[critical] 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
log "[critical] Conflicting package detected: iptables-mod-extra"
fi
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."
fi
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
log "[critical] /etc/resolv.conf contains an external nameserver"
fi
migration migration
config_foreach process_validate_service config_foreach process_validate_service
@@ -112,7 +136,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"
@@ -126,7 +155,7 @@ 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
@@ -140,11 +169,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"
@@ -164,8 +188,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
@@ -568,10 +606,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() {
@@ -842,7 +882,7 @@ sing_box_outdound() {
config_get interface "$section" "interface" config_get interface "$section" "interface"
if [ -z "$interface" ]; then if [ -z "$interface" ]; then
log "VPN interface is not set. Exit" log "[critical] VPN interface is not set. Exit"
exit 1 exit 1
fi fi
@@ -868,7 +908,7 @@ sing_box_outdound() {
active_proxy_string=$(echo "$proxy_string" | grep -v "^[[:space:]]*\/\/" | head -n 1) active_proxy_string=$(echo "$proxy_string" | grep -v "^[[:space:]]*\/\/" | head -n 1)
if [ -z "$active_proxy_string" ]; then if [ -z "$active_proxy_string" ]; then
log "Proxy string is not set. Exit" log "[critical] Proxy string is not set. Exit"
exit 1 exit 1
fi fi
@@ -941,7 +981,7 @@ sing_box_rule_dns() {
sing_box_config_check() { sing_box_config_check() {
if ! sing-box -c $SING_BOX_CONFIG check >/dev/null 2>&1; then if ! sing-box -c $SING_BOX_CONFIG check >/dev/null 2>&1; then
log "Sing-box configuration is invalid" log "[critical] Sing-box configuration is invalid"
exit 1 exit 1
fi fi
} }
@@ -1857,12 +1897,24 @@ check_fakeip() {
check_logs() { check_logs() {
nolog "Showing podkop logs from system journal..." nolog "Showing podkop logs from system journal..."
if command -v logread >/dev/null 2>&1; then if ! command -v logread >/dev/null 2>&1; then
logread -e podkop | tail -n 50
else
nolog "Error: logread command not found" nolog "Error: logread command not found"
return 1 return 1
fi fi
# Get all logs first
local all_logs=$(logread)
# Find the last occurrence of "Starting podkop"
local start_line=$(echo "$all_logs" | grep -n "podkop.*Starting podkop" | tail -n 1 | cut -d: -f1)
if [ -z "$start_line" ]; then
nolog "No 'Starting podkop' message found in logs"
return 1
fi
# Output all logs from the last start
echo "$all_logs" | tail -n +"$start_line"
} }
show_sing_box_config() { show_sing_box_config() {
@@ -1918,6 +1970,7 @@ show_config() {
-e 's/\(ss:\/\/[^@]*@\)/ss:\/\/MASKED@/g' \ -e 's/\(ss:\/\/[^@]*@\)/ss:\/\/MASKED@/g' \
-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' \
> "$tmp_config" > "$tmp_config"
cat "$tmp_config" cat "$tmp_config"
@@ -2029,34 +2082,44 @@ check_dns_available() {
local status="unavailable" local status="unavailable"
local local_dns_working=0 local local_dns_working=0
local local_dns_status="unavailable" local local_dns_status="unavailable"
# Mask NextDNS ID if present
local display_dns_server="$dns_server"
if echo "$dns_server" | grep -q "\.dns\.nextdns\.io$"; then
local nextdns_id=$(echo "$dns_server" | cut -d'.' -f1)
display_dns_server="$(echo "$nextdns_id" | sed 's/./*/g').dns.nextdns.io"
fi
if [ "$dns_type" = "doh" ]; then if [ "$dns_type" = "doh" ]; then
# Different DoH providers use different endpoints and formats
local result="" local result=""
# Try common DoH endpoints and check for valid responses if echo "$dns_server" | grep -q "quad9.net" || \
# First try /dns-query endpoint (Cloudflare, AdGuard DNS, etc.) echo "$dns_server" | grep -qE "^9\.9\.9\.(9|10|11)$|^149\.112\.112\.(112|10|11)$|^2620:fe::(fe|9|10|11)$|^2620:fe::fe:(10|11)$"; then
result=$(curl --connect-timeout 5 -s -H "accept: application/dns-json" "https://$dns_server/dns-query?name=itdog.info&type=A") result=$(curl --connect-timeout 5 -s -H "accept: application/dns-json" "https://$dns_server:5053/dns-query?name=itdog.info&type=A")
if [ $? -eq 0 ] && echo "$result" | grep -q "data"; then
is_available=1
status="available"
else else
# If that fails, try /resolve endpoint (Google DNS) result=$(curl --connect-timeout 5 -s -H "accept: application/dns-json" "https://$dns_server/dns-query?name=itdog.info&type=A")
result=$(curl --connect-timeout 5 -s -H "accept: application/dns-json" "https://$dns_server/resolve?name=itdog.info&type=A")
if [ $? -eq 0 ] && echo "$result" | grep -q "data"; then if [ $? -eq 0 ] && echo "$result" | grep -q "data"; then
is_available=1 is_available=1
status="available" status="available"
else
result=$(curl --connect-timeout 5 -s -H "accept: application/dns-json" "https://$dns_server/resolve?name=itdog.info&type=A")
fi fi
fi fi
elif [ "$dns_type" = "dot" ]; then
nc $dns_server 853 </dev/null >/dev/null 2>&1 & pid=$! if [ $? -eq 0 ] && echo "$result" | grep -q "data"; then
(sleep 3; kill $pid 2>/dev/null) & killpid=$! is_available=1
wait $pid >/dev/null 2>&1 status="available"
if [ $? -eq 0 ]; then fi
elif [ "$dns_type" = "dot" ]; then
(nc "$dns_server" 853 </dev/null >/dev/null 2>&1) & pid=$!
sleep 2
if kill -0 $pid 2>/dev/null; then
kill $pid 2>/dev/null
wait $pid 2>/dev/null
else
is_available=1 is_available=1
status="available" status="available"
fi fi
kill $killpid 2>/dev/null
elif [ "$dns_type" = "udp" ]; then elif [ "$dns_type" = "udp" ]; then
if nslookup -timeout=2 itdog.info $dns_server >/dev/null 2>&1; then if nslookup -timeout=2 itdog.info $dns_server >/dev/null 2>&1; then
is_available=1 is_available=1
@@ -2070,7 +2133,7 @@ check_dns_available() {
local_dns_status="available" local_dns_status="available"
fi fi
echo "{\"dns_type\":\"$dns_type\",\"dns_server\":\"$dns_server\",\"is_available\":$is_available,\"status\":\"$status\",\"local_dns_working\":$local_dns_working,\"local_dns_status\":\"$local_dns_status\"}" echo "{\"dns_type\":\"$dns_type\",\"dns_server\":\"$display_dns_server\",\"is_available\":$is_available,\"status\":\"$status\",\"local_dns_working\":$local_dns_working,\"local_dns_status\":\"$local_dns_status\"}"
} }
sing_box_add_secure_dns_probe_domain() { sing_box_add_secure_dns_probe_domain() {
@@ -2109,9 +2172,8 @@ case "$1" in
stop) stop)
stop stop
;; ;;
restart) reload)
stop reload
start
;; ;;
main) main)
main main
@@ -2171,7 +2233,7 @@ case "$1" in
check_dns_available check_dns_available
;; ;;
*) *)
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}"
exit 1 exit 1
;; ;;
esac esac