Compare commits

..

15 Commits

Author SHA1 Message Date
remittor
116ce93c63 Bump version to v0.7.20251219 2025-12-19 17:23:10 +03:00
remittor
4f586e66b0 build: Delete riscv64 arch 2025-12-19 17:22:53 +03:00
remittor
3e19c9c9e2 luci: Fix for show menu Zapret2 2025-12-19 14:23:11 +03:00
remittor
980dd77ba1 def-cfg: Fix DAEMON_LOG_FILE value 2025-12-19 13:58:38 +03:00
remittor
aaef886826 updater: Add check for unzip installed 2025-12-19 11:12:27 +03:00
remittor
c8558cf6c1 updater: Adapt code for new version format 2025-12-19 10:44:49 +03:00
remittor
c6e2e79683 updater: Fix parsing package version (APK) 2025-12-19 10:23:52 +03:00
remittor
08e6776a81 zapret: Add depends from luajit 2025-12-18 18:11:45 +03:00
remittor
509b834729 zapret: Makefile: Fix Package-install section 2025-12-18 17:43:49 +03:00
remittor
003160cb05 build: Fix compile packages 2025-12-18 17:22:18 +03:00
remittor
682d153742 zapret: Add depends from liblua 2025-12-18 17:02:33 +03:00
remittor
e2810bbe98 build: Fix detection tag-version 2025-12-18 16:49:04 +03:00
remittor
7aecaa4ab7 config: Add new options for AutoHostList 2025-12-18 16:42:41 +03:00
remittor
03e8513703 luci: Rename files: zapret -> zapret2 2025-12-18 16:38:57 +03:00
remittor
7a4825a708 Add support Zapret2
Sources: https://github.com/bol-van/zapret2
2025-12-18 16:35:13 +03:00
42 changed files with 1813 additions and 4043 deletions

View File

@@ -1,80 +0,0 @@
---
name: 🐛 Bug Report
description: Report a reproducible bug
title: "[BUG] "
labels: ["bug"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thanks for reporting a bug! Please fill out the form below.
Before sending, please:
- Check [existing issues](https://github.com/remittor/zapret-openwrt/issues)
- Read [documentation](https://github.com/remittor/zapret-openwrt/wiki/)
- type: textarea
id: description
attributes:
label: 📝 Bug description
description: A clear and concise description of what is not working
placeholder: A clear and concise description of the bug
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Steps to reproduce
description: Steps to reproduce the problem. If you're following a manual, please include a link to it.
placeholder: |
1.
2.
3.
4.
validations:
required: true
- type: textarea
id: expected
attributes:
label: ✅ Expected behavior
description: A clear and concise description of what was to happen
placeholder: Describe the expected behavior
validations:
required: true
- type: textarea
id: environment
attributes:
label: 🖥️ System Information
description: |
Information about your system (fill in all that used)
value: |
- **OpenWrt version**:
- **Zapret version**:
- **Router model**:
render: markdown
validations:
required: true
- type: textarea
id: strategy
attributes:
label: ✅ The NFQWS strategy used
description: All parameters of the NFQWS strategy, or its name
placeholder: If the problem is caused by the NFQWS strategy
- type: textarea
id: config
attributes:
label: ⚙️ System Configurations
description: |
Relevant parts of the configuration (remove sensitive information!)
placeholder: |
For example:
- Contents of /etc/config/zapret
- Firewall configuration (Flow offloading, etc.)
- Additional configurations required for wireless/network/dhcp, etc.
render: shell

View File

@@ -1,80 +0,0 @@
---
name: 🐛 Сообщение об ошибке
description: Сообщить об ошибке
title: "[BUG] "
labels: ["bug"]
assignees: []
body:
- type: markdown
attributes:
value: |
Спасибо за создание отчета об ошибке!
Перед отправкой, пожалуйста:
- Проверьте [существующие issues](https://github.com/remittor/zapret-openwrt/issues)
- Просмотрите [документацию](https://github.com/remittor/zapret-openwrt/wiki/)
- type: textarea
id: description
attributes:
label: 📝 Описание проблемы
description: Четкое и краткое описание того, что не работает
placeholder: Опишите проблему
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Шаги для воспроизведения
description: Шаги для воспроизведения проблемы. Если вы настраваете что-то по какому либо мануалу, приложите ссылку на него.
placeholder: |
1.
2.
3.
4.
validations:
required: true
- type: textarea
id: expected
attributes:
label: ✅ Ожидаемое поведение
description: Четкое и краткое описание того, что должно было произойти
placeholder: Опишите ожидаемое поведение
validations:
required: true
- type: textarea
id: environment
attributes:
label: 🖥️ Информация о системе
description: |
Информация о вашей системе (заполните всё применяемое)
value: |
- **OpenWrt версия**:
- **Zapret версия**:
- **Роутер модель**:
render: markdown
validations:
required: true
- type: textarea
id: strategy
attributes:
label: ✅ Используемая стратегия NFQWS
description: Все параметры стратегии NFQWS, либо её название
placeholder: Если проблема вызвана стратегией NFQWS
- type: textarea
id: config
attributes:
label: ⚙️ Конфигурация
description: |
Релевантные части конфигурации (удалите чувствительную информацию!)
placeholder: |
Например:
- Содержимое /etc/config/zapret
- Конфигурация файервола (опция Flow offloading и т.п.)
- Дополнительные конфиги, которые потребуются wireless/network/dhcp и т.д.
render: shell

View File

@@ -1,9 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Installation instructions / Инструкция по установке
url: https://github.com/remittor/zapret-openwrt/wiki/Installing-zapret%E2%80%90openwrt-package
about: Installation instructions / Инструкция по установке
- name: 📚 Original documetation / Оригинальная документация к zapret'у
url: https://github.com/bol-van/zapret/blob/master/docs/readme.md
about: README zapret

View File

@@ -1,66 +0,0 @@
---
name: ✨ Feature Request
description: Suggest a new feature or improvement
title: "[FEATURE] "
labels: ["enhancement", "needs-discussion"]
assignees: []
body:
- type: markdown
attributes:
value: |
Before sending, please:
- Check [existing requests](https://github.com/remittor/zapret-openwrt/issues?q=is%3Aissue+label%3Aenhancement)
- Make sure the function doesn't exist in [documentation](https://github.com/remittor/zapret-openwrt/wiki/)
- type: textarea
id: summary
attributes:
label: Brief description
description: Brief description of the proposed function
placeholder: In one sentence, describe what you want to add...
validations:
required: true
- type: textarea
id: problem
attributes:
label: The problem it solves
description: |
Description of the problem or inconvenience this feature will solve
placeholder: |
There is no possibility now [...]
validations:
required: true
- type: textarea
id: solution
attributes:
label: 💡 Proposed solution
description: A clear and concise description of what you want to achieve
placeholder: |
I want Zapret to be able to [...]
I suggest adding a feature that [...]
Could be improved [...]
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Workaround
description: |
Describe any alternative solutions or features you considered.
Are there any workarounds you currently use?
placeholder: |
I'm currently solving this problem by [...]
An alternative would be [...]
I tried using [...], but it doesn't work because [...]
- type: textarea
id: implementation
attributes:
label: Implementation ideas (optional)
description: |
If you have any ideas on how this could be implemented, please share them. Please keep LuCI's limitations in mind.
placeholder: |
This can be achieved using [...]

View File

@@ -1,68 +0,0 @@
---
name: ✨ Запрос новой функции
description: Предложите новую функцию или улучшение для Zapret
title: "[FEATURE] "
labels: ["enhancement", "needs-discussion"]
assignees: []
body:
- type: markdown
attributes:
value: |
Спасибо за предложение новой функции!
Перед отправкой, пожалуйста:
- Проверьте [существующие запросы](https://github.com/remittor/zapret-openwrt/issues?q=is%3Aissue+label%3Aenhancement)
- Убедитесь, что функции не существует в [документации](https://github.com/remittor/zapret-openwrt/wiki/)
- type: textarea
id: summary
attributes:
label: Краткое описание
description: Краткое описание предлагаемой функции
placeholder: В одном предложении опишите, что вы хотите добавить...
validations:
required: true
- type: textarea
id: problem
attributes:
label: Проблема, которую решает
description: |
Описание проблемы или неудобства, которое решит эта функция
placeholder: |
Сейчас нет возможности [...]
validations:
required: true
- type: textarea
id: solution
attributes:
label: 💡 Предлагаемое решение
description: Четкое и краткое описание того, что вы хотите реализовать
placeholder: |
Я хочу, чтобы Zapret мог [...]
Предлагаю добавить функцию, которая [...]
Можно было бы улучшить [...] путем [...]
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Workaround
description: |
Опишите альтернативные решения или функции, которые вы рассматривали
Есть ли обходные пути, которые вы используете сейчас?
placeholder: |
Сейчас я решаю это проблему путем [...]
Альтернативой могло бы быть [...]
Пробовал использовать [...], но это не подходит потому что [...]
- type: textarea
id: implementation
attributes:
label: Идеи реализации (опционально)
description: |
Если у вас есть идеи о том, как это можно реализовать, поделитесь ими. Помните про ограничения LuCI.
placeholder: |
Это можно реализовать с помощью [...]

View File

@@ -1,78 +0,0 @@
---
name: 🆘 Help wanted
description: Ask for help or propose to help
title: "[HELP] "
labels: ["help wanted"]
assignees: []
body:
- type: markdown
attributes:
value: |
Before sending, please:
- Check [existing issues](https://github.com/remittor/zapret-openwrt/issues)
- Read [documentation](https://github.com/remittor/zapret-openwrt/wiki/)
- type: textarea
id: description
attributes:
label: 📝 Problem description
description: What do you need help with?
placeholder: A clear and concise description of the problem
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Steps to reproduce
description: Steps to reproduce the problem. If you're following a manual, please include a link to it.
placeholder: |
1.
2.
3.
4.
validations:
required: true
- type: textarea
id: expected
attributes:
label: ✅ Expected behavior
description: A clear and concise description of what was to happen
placeholder: Describe the expected behavior
validations:
required: true
- type: textarea
id: environment
attributes:
label: 🖥️ System Information
description: |
Information about your system (fill in all that used)
value: |
- **OpenWrt version**:
- **Zapret version**:
- **Router model**:
render: markdown
validations:
required: true
- type: textarea
id: strategy
attributes:
label: ✅ The NFQWS strategy used
description: All parameters of the NFQWS strategy, or its name
placeholder: If the problem is caused by the NFQWS strategy
- type: textarea
id: config
attributes:
label: ⚙️ System Configurations
description: |
Relevant parts of the configuration (remove sensitive information!)
placeholder: |
For example:
- Contents of /etc/config/zapret
- Firewall configuration (Flow offloading, etc.)
- Additional configurations required for wireless/network/dhcp, etc.
render: shell

View File

@@ -1,78 +0,0 @@
---
name: 🆘 Нужна помощь
description: Нужна помощь
title: "[HELP] "
labels: ["help wanted"]
assignees: []
body:
- type: markdown
attributes:
value: |
Перед отправкой, пожалуйста:
- Проверьте [существующие issues](https://github.com/remittor/zapret-openwrt/issues)
- Просмотрите [документацию](https://github.com/remittor/zapret-openwrt/wiki/)
- type: textarea
id: description
attributes:
label: 📝 Описание проблемы
description: В чём именно нужна помощь?
placeholder: Опишите проблему
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Шаги для воспроизведения
description: Шаги для воспроизведения проблемы. Если вы настраваете что-то по какому либо мануалу, приложите ссылку на него.
placeholder: |
1.
2.
3.
4.
validations:
required: true
- type: textarea
id: expected
attributes:
label: ✅ Ожидаемое поведение
description: Четкое и краткое описание того, что должно было произойти
placeholder: Опишите ожидаемое поведение
validations:
required: true
- type: textarea
id: environment
attributes:
label: 🖥️ Информация о системе
description: |
Информация о вашей системе (заполните всё применяемое)
value: |
- **OpenWrt версия**:
- **Zapret версия**:
- **Роутер модель**:
render: markdown
validations:
required: true
- type: textarea
id: strategy
attributes:
label: ✅ Используемая стратегия NFQWS
description: Все параметры стратегии NFQWS, либо её название
placeholder: Если проблема вызвана стратегией NFQWS
- type: textarea
id: config
attributes:
label: ⚙️ Конфигурация
description: |
Релевантные части конфигурации (удалите чувствительную информацию!)
placeholder: |
Например:
- Содержимое /etc/config/zapret
- Конфигурация файервола (опция Flow offloading и т.п.)
- Дополнительные конфиги, которые потребуются wireless/network/dhcp и т.д.
render: shell

View File

@@ -27,7 +27,6 @@ on:
options: options:
- true - true
- false - false
push: push:
tags: tags:
- v[0-9]+* - v[0-9]+*
@@ -37,19 +36,17 @@ env:
FAKE_BUILD: ${{ github.event.inputs.fake_build == 'true' }} FAKE_BUILD: ${{ github.event.inputs.fake_build == 'true' }}
MAX_SPEED: ${{ github.event.inputs.max_speed != 'false' }} MAX_SPEED: ${{ github.event.inputs.max_speed != 'false' }}
TAG_SUFFIX: ${{ github.event.inputs.fake_build == 'true' && '-fake' || github.event.inputs.test_build == 'true' && '-test' || '' }} TAG_SUFFIX: ${{ github.event.inputs.fake_build == 'true' && '-fake' || github.event.inputs.test_build == 'true' && '-test' || '' }}
REPO_NAME: zapret-openwrt
REPO_URL: https://github.com/remittor/zapret-openwrt REPO_URL: https://github.com/remittor/zapret-openwrt
REPO_LNK: remittor/zapret-openwrt REPO_LNK: remittor/zapret-openwrt
REPO_BRANCH: master REPO_BRANCH: master
PKGDIR: ${{ github.workspace }}/zapret-openwrt BUILD_ROOT: ${{ github.workspace }}/builder
SDKDIR: /builder
BUILD_DATE: unknown BUILD_DATE: unknown
REPO_DATE: unknown REPO_DATE: unknown
LUCI_ARCH: aarch64_cortex-a53 LUCI_ARCH: aarch64_cortex-a53
jobs: jobs:
check: check:
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
outputs: outputs:
tag: ${{ steps.gh.outputs.tag }} tag: ${{ steps.gh.outputs.tag }}
date: ${{ steps.gh.outputs.date }} date: ${{ steps.gh.outputs.date }}
@@ -106,29 +103,14 @@ jobs:
fi fi
echo "is_active=$is_active" >> $GITHUB_OUTPUT echo "is_active=$is_active" >> $GITHUB_OUTPUT
var:
runs-on: ubuntu-24.04
outputs:
IPK_BRANCH: ${{ steps.set.outputs.IPK_BRANCH }}
APK_BRANCH: ${{ steps.set.outputs.APK_BRANCH }}
XXX_BRANCH: ${{ steps.set.outputs.XXX_BRANCH }}
steps:
- id: set
run: |
echo "IPK_BRANCH=v24.10.5" >> "$GITHUB_OUTPUT"
echo "APK_BRANCH=v25.12.0-rc2" >> "$GITHUB_OUTPUT"
echo "XXX_BRANCH=SNAPSHOT" >> "$GITHUB_OUTPUT"
build: build:
needs: [ check, var ] needs: check
#if: needs.check.outputs.is_active == 'true' #if: needs.check.outputs.is_active == 'true'
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
branch: branch: [ openwrt-24.10, SNAPSHOT ]
- ${{ needs.var.outputs.IPK_BRANCH }}
- ${{ needs.var.outputs.APK_BRANCH }}
arch: arch:
- aarch64_cortex-a53 - aarch64_cortex-a53
- aarch64_cortex-a72 - aarch64_cortex-a72
@@ -155,73 +137,37 @@ jobs:
- mipsel_24kc_24kf - mipsel_24kc_24kf
- mipsel_74kc - mipsel_74kc
- mipsel_mips32 - mipsel_mips32
- riscv64_riscv64
- riscv64_generic
- x86_64 - x86_64
isTestOrFake: isTestOrFake:
- ${{ needs.check.outputs.test_build == 'true' || needs.check.outputs.fake_build == 'true' }} - ${{ needs.check.outputs.test_build == 'true' || needs.check.outputs.fake_build == 'true' }}
exclude: exclude:
- branch: ${{ needs.var.outputs.APK_BRANCH }} - branch: SNAPSHOT
arch: arm_cortex-a9_vfpv3-d16 arch: arm_cortex-a9_vfpv3-d16
- branch: ${{ needs.var.outputs.APK_BRANCH }}
arch: mips_4kec
- branch: ${{ needs.var.outputs.APK_BRANCH }}
arch: riscv64_riscv64
- branch: ${{ needs.var.outputs.IPK_BRANCH }}
arch: riscv64_generic
- { isTestOrFake: true } - { isTestOrFake: true }
include: include:
- branch: ${{ needs.var.outputs.IPK_BRANCH }} - branch: openwrt-24.10
arch: x86_64 arch: x86_64
- branch: ${{ needs.var.outputs.IPK_BRANCH }} - branch: openwrt-24.10
arch: aarch64_cortex-a53 arch: aarch64_cortex-a53
- branch: ${{ needs.var.outputs.APK_BRANCH }} - branch: SNAPSHOT
arch: aarch64_cortex-a53 arch: aarch64_cortex-a53
container: container:
image: ghcr.io/openwrt/sdk:${{ matrix.arch }}-${{ matrix.branch }} image: openwrt/sdk:${{ matrix.arch }}-${{ matrix.branch }}
options: --user root options: --user root
outputs: outputs:
pkgver: ${{ steps.prepare.outputs.pkgver }} pkgver: ${{ steps.build.outputs.pkgver }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
repository: ${{ env.REPO_LNK }} repository: ${{ env.REPO_LNK }}
path: ${{ env.REPO_NAME }} path: zapret-openwrt
- name: Fix SDK paths
run: |
mkdir -p $SDKDIR/shared-workdir
rm -rf $SDKDIR/shared-workdir/build
ln -sf $SDKDIR $SDKDIR/shared-workdir/build
- name: Initialization environment
working-directory: ${{ env.SDKDIR }}
env:
DEBIAN_FRONTEND: noninteractive
ARCH_TAG: ${{ matrix.arch }}
BRANCH: ${{ matrix.branch }}
FAKE_BUILD: ${{ env.FAKE_BUILD == 'true' || ( env.TEST_BUILD == 'true' && matrix.branch == needs.var.outputs.APK_BRANCH ) }}
run: |
if [ "$BRANCH" = "${{ needs.var.outputs.IPK_BRANCH }}" ]; then
echo "PKGTYPE=ipk" >> $GITHUB_ENV
else
echo "PKGTYPE=apk" >> $GITHUB_ENV
fi
mkdir -p ./logs
#echo ============== $SDKDIR ======================
#ls -la $SDKDIR
#echo ----------------------------------------------
echo "FAKE_BUILD=$FAKE_BUILD" >> $GITHUB_ENV
echo "ARCH_TAG=$ARCH_TAG" >> $GITHUB_ENV
echo "BRANCH=$BRANCH" >> $GITHUB_ENV
echo "TZ=UTC" >> $GITHUB_ENV
- name: Setup OpenWrt SDK - name: Setup OpenWrt SDK
if: false working-directory: /builder
working-directory: ${{ env.SDKDIR }} env:
BRANCH: ${{ matrix.branch }}
shell: bash
run: | run: |
# gpg --verbose --recv-keys 0x1D53D1877742E911 # gpg --verbose --recv-keys 0x1D53D1877742E911
# gpg --verbose --import <(wget -qO- 'https://git.openwrt.org/?p=keyring.git;a=blob_plain;f=gpg/0x1D53D1877742E911.asc') # gpg --verbose --import <(wget -qO- 'https://git.openwrt.org/?p=keyring.git;a=blob_plain;f=gpg/0x1D53D1877742E911.asc')
@@ -232,122 +178,120 @@ jobs:
sed -r -i 's/^rm.+//' setup.sh sed -r -i 's/^rm.+//' setup.sh
./setup.sh ./setup.sh
ls -lh ls -lh
if [ "$BRANCH" = "openwrt-24.10" ]; then
echo "PKGTYPE=ipk" >> $GITHUB_ENV
else
echo "PKGTYPE=apk" >> $GITHUB_ENV
fi
- name: Setup ccache - name: Setup ccache
if: false
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: ${{ env.SDKDIR }}/.ccache path: '/builder/.ccache'
key: ccache-${{ matrix.arch }}-${{ matrix.branch }}-${{ github.run_id }} key: ccache-${{ matrix.arch }}-${{ matrix.branch }}-${{ github.run_id }}
restore-keys: | restore-keys: |
ccache-${{ matrix.arch }}-${{ matrix.branch }}- ccache-${{ matrix.arch }}-${{ matrix.branch }}-
- name: Prepare packages - name: Init packages
id: prepare id: init
working-directory: ${{ env.SDKDIR }} working-directory: '/builder'
env:
FAKE_BUILD: ${{ env.FAKE_BUILD == 'true' || ( env.TEST_BUILD == 'true' && matrix.branch == 'SNAPSHOT' ) }}
BUILD_DATE: ${{ needs.check.outputs.build_date }}
ARCH: ${{ matrix.arch }}
BRANCH: ${{ matrix.branch }}
SIGN_KEY: ${{ secrets.SIGN_PRIVATE_KEY }}
CCACHE_DIR: '/builder/.ccache'
shell: bash
run: | run: |
MKFN=$( ls -1 $PKGDIR/luci-app-zapret*/Makefile ) PKGDIR=$GITHUB_WORKSPACE/zapret-openwrt
MKFN=$PKGDIR/luci-app-zapret/Makefile
PKGVER=$( grep -s '^PKG_VERSION:=.*' $MKFN | cut -d'=' -f2 ) PKGVER=$( grep -s '^PKG_VERSION:=.*' $MKFN | cut -d'=' -f2 )
PKGREL=$( grep -s '^PKG_RELEASE:=.*' $MKFN | cut -d'=' -f2 ) PKGREL=$( grep -s '^PKG_RELEASE:=.*' $MKFN | cut -d'=' -f2 )
[ "$PKGREL" != "1" ] && PKGVER=$PKGVER-r$PKGREL [ "$PKGREL" != "1" ] && PKGVER=$PKGVER-r$PKGREL
echo "PKG_VERSION = $PKGVER" echo "PKG_VERSION = $PKGVER"
cp -vr $PKGDIR ./package/$REPO_NAME/ cp -vr $PKGDIR ./package/zapret-openwrt/
echo "PKGVER=$PKGVER" >> $GITHUB_ENV
echo "pkgver=$PKGVER" >> $GITHUB_OUTPUT
echo "status=success" >> $GITHUB_OUTPUT
- name: Init packages
id: init
if: steps.prepare.outputs.status == 'success'
working-directory: ${{ env.SDKDIR }}
run: |
mv feeds.conf.default feeds.conf mv feeds.conf.default feeds.conf
sed -i -e 's|base.*\.git|base https://github.com/openwrt/openwrt.git|' feeds.conf sed -i -e 's|base.*\.git|base https://github.com/openwrt/openwrt.git|' feeds.conf
sed -i -e 's|packages.*\.git|packages https://github.com/openwrt/packages.git|' feeds.conf sed -i -e 's|packages.*\.git|packages https://github.com/openwrt/packages.git|' feeds.conf
sed -i -e 's|luci.*\.git|luci https://github.com/openwrt/luci.git|' feeds.conf sed -i -e 's|luci.*\.git|luci https://github.com/openwrt/luci.git|' feeds.conf
./scripts/feeds update base packages luci mkdir -p ./logs
./scripts/feeds install -a
if [ "$FAKE_BUILD" = "false" ]; then
./scripts/feeds update base packages luci
./scripts/feeds install -a
fi
echo "FAKE_BUILD=$FAKE_BUILD" >> $GITHUB_ENV
echo "PKGVER=$PKGVER" >> $GITHUB_ENV
echo "pkgver=$PKGVER" >> $GITHUB_OUTPUT
echo "status=success" >> $GITHUB_OUTPUT echo "status=success" >> $GITHUB_OUTPUT
- name: Init config - name: Build packages
id: config
if: steps.init.outputs.status == 'success'
working-directory: ${{ env.SDKDIR }}
run: |
make defconfig
sed -i 's/CONFIG_LUCI_JSMIN=y/CONFIG_LUCI_JSMIN=n/g' .config
sed -i 's/CONFIG_LUCI_CSSMIN=y/CONFIG_LUCI_CSSMIN=n/g' .config
grep -q '^CONFIG_LUCI_CSSMIN=' .config || echo 'CONFIG_LUCI_CSSMIN=n' >> .config
echo "status=success" >> $GITHUB_OUTPUT
- name: Show config
working-directory: ${{ env.SDKDIR }}
run: |
cat .config || echo "File .config not found"
- name: Build packages
id: build id: build
if: steps.config.outputs.status == 'success' && env.FAKE_BUILD != 'true' if: steps.init.outputs.status == 'success'
working-directory: ${{ env.SDKDIR }} working-directory: '/builder'
env: env:
ARCH_TAG: ${{ matrix.arch }} BUILD_DATE: ${{ needs.check.outputs.build_date }}
run: | ARCH: ${{ matrix.arch }}
PKGLIST="package/zapret-openwrt/zapret/compile" BRANCH: ${{ matrix.branch }}
if [ "$ARCH_TAG" = "$LUCI_ARCH" ]; then
PKGLIST="$PKGLIST package/zapret-openwrt/luci-app-zapret/compile"
fi
MAKE_JOBS=$(nproc)
echo "$MAKE_JOBS thread compile"
if [ "$MAX_SPEED" != "true" ]; then
make $PKGLIST V=sc BUILD_LOG=1
else
make $PKGLIST -j$MAKE_JOBS
fi
echo "status=success" >> $GITHUB_OUTPUT
- name: Build packages (FAKE)
id: build_fake
if: env.FAKE_BUILD == 'true'
working-directory: ${{ env.SDKDIR }}
env:
ARCH_TAG: ${{ matrix.arch }}
run: |
OUT_DIR=./bin/packages/dev_x/base
mkdir -p $OUT_DIR
touch $OUT_DIR/zapret_$PKGVER-$ARCH_TAG.$PKGTYPE
touch $OUT_DIR/luci-app-zapret_$PKGVER-all.$PKGTYPE
echo "status=success" >> $GITHUB_OUTPUT
- name: Install packages
id: install
if: steps.build.outputs.status == 'success' || steps.build_fake.outputs.status == 'success'
working-directory: ${{ env.SDKDIR }}
env:
ARCH_TAG: ${{ matrix.arch }}
SIGN_KEY: ${{ secrets.SIGN_PRIVATE_KEY }} SIGN_KEY: ${{ secrets.SIGN_PRIVATE_KEY }}
CCACHE_DIR: '/builder/.ccache'
shell: bash
run: | run: |
find ./bin/packages/*/base -type f ! -regex ".*\(zapret\).*\.[ai]pk$" -delete MAKE_JOBS=$(($(nproc)+1))
echo "$MAKE_JOBS thread compile"
if [ "$FAKE_BUILD" = "false" ]; then
make defconfig
sed -i 's/CONFIG_LUCI_JSMIN=y/CONFIG_LUCI_JSMIN=n/g' .config
echo "------------- .config BEG -------------------"
cat .config
echo "------------- .config END -------------------"
if [ "$ARCH" = "$LUCI_ARCH" ]; then
PKGLIST=`echo package/zapret-openwrt/{zapret,zapret-mdig,zapret-ip2net,luci-app-zapret}/compile`
else
PKGLIST=`echo package/zapret-openwrt/{zapret,zapret-mdig,zapret-ip2net}/compile`
fi
if [ "$MAX_SPEED" = "false" ]; then
make $PKGLIST V=s CONFIG_CCACHE=1 BUILD_LOG=1
else
make -j$MAKE_JOBS $PKGLIST CONFIG_CCACHE=1
fi
else
OUT_DIR=./bin/packages/dev_x/base
mkdir -p $OUT_DIR
touch $OUT_DIR/zapret2_$PKGVER-$ARCH.$PKGTYPE
touch $OUT_DIR/luci-app-zapret2_$PKGVER-all.$PKGTYPE
fi
find ./bin/packages/*/base -type f ! -regex ".*\(zapret2\).*\.[ai]pk$" -delete
#echo ">>>>>>> build a repository index to make the output directory usable as local OPKG source" #echo ">>>>>>> build a repository index to make the output directory usable as local OPKG source"
#ln -s `which usign` staging_dir/host/bin/usign #ln -s `which usign` staging_dir/host/bin/usign
#echo "$SIGN_KEY" | base64 -d > key-build #echo "$SIGN_KEY" | base64 -d > key-build
#make package/index #make package/index
OUTDIR=$GITHUB_WORKSPACE/$PKGTYPE-$ARCH_TAG
OUTDIR=$GITHUB_WORKSPACE/$PKGTYPE-$ARCH
mkdir -p $OUTDIR mkdir -p $OUTDIR
cp -R ./bin/packages/*/base/. $OUTDIR/ cp -R ./bin/packages/*/base/. $OUTDIR/
./staging_dir/host/bin/ccache --max-size=10M --show-stats
echo "OUTDIR=$OUTDIR" >> $GITHUB_ENV echo "OUTDIR=$OUTDIR" >> $GITHUB_ENV
echo "pkgver=$PKGVER" >> $GITHUB_OUTPUT
echo "status=success" >> $GITHUB_OUTPUT echo "status=success" >> $GITHUB_OUTPUT
- name: Compress build logs - name: Compress build logs
if: always() if: always()
env: env:
ARCH_TAG: ${{ matrix.arch }} ARCH: ${{ matrix.arch }}
BRANCH: ${{ matrix.branch }} BRANCH: ${{ matrix.branch }}
LOGS_DIR: ${{ env.SDKDIR }}/logs LOGS_DIR: '/builder/logs'
run: | run: |
tar -cJvf logs-$BRANCH-$ARCH_TAG.tar.xz $LOGS_DIR tar -cJvf logs-$BRANCH-$ARCH.tar.xz $LOGS_DIR
- name: Upload packages - name: Upload packages
if: steps.install.outcome == 'success' if: steps.build.outcome == 'success'
uses: actions/upload-artifact@main uses: actions/upload-artifact@main
with: with:
path: ${{ env.OUTDIR }} path: ${{ env.OUTDIR }}
@@ -365,7 +309,7 @@ jobs:
needs: [ check, build ] needs: [ check, build ]
permissions: permissions:
contents: write contents: write
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
steps: steps:
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@@ -392,7 +336,7 @@ jobs:
find ./sorted -mindepth 1 -maxdepth 1 -type d -exec cp -f "$LUCI_IPK" "{}/" \; find ./sorted -mindepth 1 -maxdepth 1 -type d -exec cp -f "$LUCI_IPK" "{}/" \;
find ./sorted -mindepth 2 -maxdepth 2 -type d -name "apk" -exec cp -f "$LUCI_APK" "{}/" \; find ./sorted -mindepth 2 -maxdepth 2 -type d -name "apk" -exec cp -f "$LUCI_APK" "{}/" \;
mkdir -p public mkdir -p public
find ./sorted -mindepth 1 -maxdepth 1 -type d -exec sh -c '7z a ./public/zapret_v${PKGVER}_$(basename "{}" | cut -d, -f3).zip {}/*' \; find ./sorted -mindepth 1 -maxdepth 1 -type d -exec sh -c '7z a ./public/zapret2_v${PKGVER}_$(basename "{}" | cut -d, -f3).zip {}/*' \;
ls -lh ./public/*.zip ls -lh ./public/*.zip
- name: Upload assets - name: Upload assets
@@ -404,7 +348,7 @@ jobs:
draft: ${{ env.TEST_BUILD == 'true' || env.FAKE_BUILD == 'true' }} draft: ${{ env.TEST_BUILD == 'true' || env.FAKE_BUILD == 'true' }}
prerelease: true prerelease: true
tag_name: v${{ needs.build.outputs.pkgver }}${{ env.TAG_SUFFIX }} tag_name: v${{ needs.build.outputs.pkgver }}${{ env.TAG_SUFFIX }}
name: zapret v${{ needs.build.outputs.pkgver }} name: zapret2 v${{ needs.build.outputs.pkgver }}
body: | body: |
zapret v${{ needs.build.outputs.pkgver }} for OpenWrt zapret2 v${{ needs.build.outputs.pkgver }} for OpenWrt
files: ./public/*.zip files: ./public/*.zip

View File

@@ -5,7 +5,7 @@ on:
workflows: ["build"] workflows: ["build"]
types: [completed] types: [completed]
release: release:
types: [published, unpublished, created, edited, deleted, prereleased] types: [published, created, edited]
permissions: permissions:
contents: write contents: write
@@ -25,62 +25,6 @@ jobs:
ref: gh-pages ref: gh-pages
continue-on-error: true continue-on-error: true
- name: Wait for GitHub API consistency (release events)
if: github.event_name == 'release'
env:
REPO: ${{ github.repository }}
ACTION: ${{ github.event.action }}
TARGET_ID: ${{ github.event.release.id }}
TARGET_NAME: ${{ github.event.release.name }}
run: |
set -e
echo "Release action: $ACTION"
echo "Target release id: $TARGET_ID"
max=10
delay=6
check() {
curl -s https://api.github.com/repos/$REPO/releases
}
for iter in $(seq 1 $max); do
case "$ACTION" in
created)
echo "Release created (draft). No API wait needed."
exit 0
;;
published|prereleased)
if check | jq "any(.[]; .id == $TARGET_ID)"; then
echo "Release appeared in API"
exit 0
fi
;;
deleted)
if ! check | jq "any(.[]; .id == $TARGET_ID)"; then
echo "Release disappeared from API"
exit 0
fi
;;
unpublished)
if check | jq "any(.[]; .id == $TARGET_ID and .draft == true)"; then
echo "Release is now draft"
exit 0
fi
;;
edited)
if check | jq "any(.[]; .id == $TARGET_ID and .name == \"$TARGET_NAME\")"; then
echo "Release updated"
exit 0
fi
;;
*)
echo "No consistency wait needed for action: $ACTION"
exit 0
;;
esac
echo "Retry $iter/$max..."
sleep "$delay"
done
echo "WARNING: API consistency timeout for action $ACTION"
- name: Save FULL releases.json - name: Save FULL releases.json
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -2,12 +2,13 @@
[![Github All Releases](https://img.shields.io/github/downloads/remittor/zapret-openwrt/total.svg)](https://github.com/remittor/zapret-openwrt/releases) [![Github All Releases](https://img.shields.io/github/downloads/remittor/zapret-openwrt/total.svg)](https://github.com/remittor/zapret-openwrt/releases)
[![Github Latest Release](https://img.shields.io/github/downloads/remittor/zapret-openwrt/latest/total.svg)](https://github.com/remittor/zapret-openwrt/releases) [![Github Latest Release](https://img.shields.io/github/downloads/remittor/zapret-openwrt/latest/total.svg)](https://github.com/remittor/zapret-openwrt/releases)
[![ViewCount](https://views.whatilearened.today/views/github/remittor/zapret-openwrt.svg)](https://github.com/remittor/zapret-openwrt) [![ViewCount](https://views.whatilearened.today/views/github/remittor/zapret-openwrt.svg)](https://github.com/remittor/zapret-openwrt)
[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fremittor%2Fzapret-openwrt&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://github.com/remittor/zapret-openwrt/releases)
[![Donations Page](https://github.com/andry81-cache/gh-content-static-cache/raw/master/common/badges/donate/donate.svg)](https://github.com/remittor/donate) [![Donations Page](https://github.com/andry81-cache/gh-content-static-cache/raw/master/common/badges/donate/donate.svg)](https://github.com/remittor/donate)
# zapret-openwrt # zapret-openwrt
Zapret is not a VPN! Zapret is an Anti-DPI utility! Zapret2 is not a VPN! Zapret2 is an Anti-DPI utility!
[Instructions for installing](https://github.com/remittor/zapret-openwrt/wiki) [Instructions for installing](https://github.com/remittor/zapret-openwrt/wiki/Installing-zapretopenwrt-package)
[Download page](https://github.com/remittor/zapret-openwrt/releases) [Download page](https://github.com/remittor/zapret-openwrt/releases)

View File

@@ -4,14 +4,14 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-zapret PKG_NAME:=luci-app-zapret2
PKG_VERSION:=72.20260128 PKG_VERSION:=0.7.20251219
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_LICENSE:=MIT PKG_LICENSE:=MIT
PKG_MAINTAINER:=remittor <https://github.com/remittor> PKG_MAINTAINER:=remittor <https://github.com/remittor>
LUCI_TITLE:=LuCI support for zapret LUCI_TITLE:=LuCI support for zapret2
LUCI_DEPENDS:=+zapret LUCI_DEPENDS:=+zapret2
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
define Package/$(PKG_NAME)/postinst define Package/$(PKG_NAME)/postinst

View File

@@ -1,170 +0,0 @@
'use strict';
'require baseclass';
'require fs';
'require poll';
'require uci';
'require ui';
'require view';
'require view.zapret.tools as tools';
const btn_style_neutral = 'btn';
const btn_style_action = 'btn cbi-button-action';
const btn_style_positive = 'btn cbi-button-save important';
const btn_style_negative = 'btn cbi-button-reset important';
const btn_style_warning = 'btn cbi-button-negative';
const btn_style_success = 'btn cbi-button-success important';
const fn_dwc_sh = '/opt/'+tools.appName+'/dwc.sh';
return baseclass.extend({
appendLog: function(msg, end = '\n')
{
this.logArea.value += msg + end;
this.logArea.scrollTop = this.logArea.scrollHeight;
},
setBtnMode: function(check1, check2, cancel)
{
this.btn_dpicheck.disabled = check1 ? false : true;
this.btn_sitescheck.disabled = check2 ? false : true;
this.btn_cancel.disabled = cancel ? false : true;
},
dpiCheck: async function()
{
this._action = 'dpiCheck';
this.setBtnMode(0, 0, 0);
this.appendLog('DPI check [tcp 16-20]...');
this.appendLog('Original sources: https://github.com/hyperion-cs/dpi-checkers');
this.appendLog('WEB-version: https://hyperion-cs.github.io/dpi-checkers/ru/tcp-16-20/');
let cmd = [ fn_dwc_sh ];
let resolve_dns = document.getElementById('cfg_resolve_dns');
let dns_ip = resolve_dns.options[resolve_dns.selectedIndex].text;
if (dns_ip && dns_ip != 'default') {
cmd.push(...[ '-d', dns_ip.trim() ]);
}
cmd.push('-R'); // show recommendations
return tools.execAndRead({
cmd: cmd,
log: '/tmp/'+tools.appName+'_dwc.log',
logArea: this.logArea,
callback: this.execAndReadCallback,
ctx: this,
});
},
sitesCheck: async function()
{
this._action = 'dpiCheck';
this.setBtnMode(0, 0, 0);
this.appendLog('Sites check...');
let cmd = [ fn_dwc_sh ];
let resolve_dns = document.getElementById('cfg_resolve_dns');
let dns_ip = resolve_dns.options[resolve_dns.selectedIndex].text;
if (dns_ip && dns_ip != 'default') {
cmd.push(...[ '-d', dns_ip.trim() ]);
}
cmd.push('-s'); // mode: check sites
return tools.execAndRead({
cmd: cmd,
log: '/tmp/'+tools.appName+'_dwc.log',
logArea: this.logArea,
callback: this.execAndReadCallback,
ctx: this,
});
},
execAndReadCallback: function(rc, txt = '')
{
this.setBtnMode(1, 1, 1);
if (rc == 0 && txt) {
this.appendLog('=========================================================');
return;
}
if (rc >= 500) {
if (txt) {
this.appendLog(txt.startsWith('ERROR') ? txt : 'ERROR: ' + txt);
} else {
this.appendLog('ERROR: ' + this._action + ': Terminated with error code = ' + rc);
}
} else {
this.appendLog('ERROR: Process finished with retcode = ' + rc);
}
this.appendLog('=========================================================');
},
openDiagnostDialog: function(pkg_arch)
{
this.pkg_arch = pkg_arch;
let DNS_LIST = [
'8.8.8.8', // Google
'8.8.4.4', // Google
'1.1.1.1', // Cloudflare
'1.0.0.1', // Cloudflare
'9.9.9.9', // Quad9
'149.112.112.112', // Quad9
'208.67.222.222', // OpenDNS
'208.67.220.220', // OpenDNS
'8.26.56.26', // Comodo
'8.20.247.20', // Comodo
'64.6.64.6', // Verisign
'64.6.65.6', // Verisign
];
let dns_list = [ ];
dns_list.push( E('option', { value: 'dns_default' }, [ 'default' ] ) );
for (let id = 0; id < DNS_LIST.length; id++) {
let dns_ipaddr = '' + DNS_LIST[id];
let val = 'dns_' + dns_ipaddr.replace(/\./g, "_");
dns_list.push( E('option', { value: val }, [ dns_ipaddr ] ));
}
let resolve_dns = E('label', [
_('Resolve IP-Addr via') + ': ',
E('select', { id: 'cfg_resolve_dns' }, dns_list)
]);
this.logArea = E('textarea', {
'id': 'widget.modal_content',
'readonly': true,
'style': 'width:100% !important; font-family: monospace;',
'rows': 26,
'wrap': 'off',
});
this.btn_cancel = E('button', {
'id': 'btn_cancel',
'name': 'btn_cancel',
'class': btn_style_warning,
}, _('Cancel'));
this.btn_cancel.onclick = ui.hideModal;
this.btn_dpicheck = E('button', {
'id': 'btn_dpicheck',
'name': 'btn_dpicheck',
'class': btn_style_action,
}, _('DPI check'));
this.btn_dpicheck.onclick = ui.createHandlerFn(this, this.dpiCheck);
this.btn_sitescheck = E('button', {
'id': 'btn_sitescheck',
'name': 'btn_sitescheck',
'class': btn_style_action,
}, _('Sites check'));
this.btn_sitescheck.onclick = ui.createHandlerFn(this, this.sitesCheck);
ui.showModal(_('Diagnostics'), [
E('div', { 'class': 'cbi-section' }, [
resolve_dns,
E('br'), E('br'),
this.logArea,
]),
E('div', { 'class': 'right' }, [
this.btn_sitescheck,
' ',
this.btn_dpicheck,
' ',
this.btn_cancel,
])
]);
}
});

View File

@@ -1,70 +0,0 @@
'use strict';
'require baseclass';
return baseclass.extend({
packager : { },
appName : 'zapret',
AppName : 'Zapret',
execPath : '/etc/init.d/zapret',
appDir : '/opt/zapret',
syncCfgPath : '/opt/zapret/sync_config.sh',
defCfgPath : '/opt/zapret/def-cfg.sh',
defaultCfgPath : '/opt/zapret/restore-def-cfg.sh',
hostsGoogleFN : '/opt/zapret/ipset/zapret-hosts-google.txt',
hostsUserFN : '/opt/zapret/ipset/zapret-hosts-user.txt',
hostsUserExcludeFN: '/opt/zapret/ipset/zapret-hosts-user-exclude.txt',
iplstExcludeFN : '/opt/zapret/ipset/zapret-ip-exclude.txt',
iplstUserFN : '/opt/zapret/ipset/zapret-ip-user.txt',
iplstUserExcludeFN: '/opt/zapret/ipset/zapret-ip-user-exclude.txt',
custFileMax : 4,
custFileTemplate : '/opt/zapret/ipset/cust%s.txt',
customdPrefixList : [ 10, 20, 50, 60, 90 ] ,
customdFileFormat : '/opt/zapret/init.d/openwrt/custom.d/%s-script.sh',
discord_num : 50,
discord_url : [ 'https://github.com/bol-van/zapret/blob/4e8e3a9ed9dbeb1156db68dfaa7b353051c13797/init.d/custom.d.examples.linux/50-discord',
'https://github.com/bol-van/zapret/blob/b251ea839cc8f04c45090314ef69fce69f2c00f2/init.d/custom.d.examples.linux/50-discord-media',
'https://github.com/bol-van/zapret/blob/b251ea839cc8f04c45090314ef69fce69f2c00f2/init.d/custom.d.examples.linux/50-stun4all',
'https://github.com/bol-van/zapret/tree/master/init.d/custom.d.examples.linux'
],
nfqws_opt_url : 'https://github.com/remittor/zapret-openwrt/discussions/168',
autoHostListFN : '/opt/zapret/ipset/zapret-hosts-auto.txt',
autoHostListDbgFN : '/opt/zapret/ipset/zapret-hosts-auto-debug.log',
load_env: function(ctx)
{
let env_proto = Object.getPrototypeOf(this);
Object.getOwnPropertyNames(env_proto).forEach(function(key) {
if (key === 'constructor' || key.startsWith('__')) {
return;
}
if (key === 'load_env' || key === 'load_feat_env') {
return;
}
ctx[key] = env_proto[key];
});
ctx.skey_pkg_dict = this.appName + '-pkg-dict';
ctx.skey_deffered_action = this.appName + '-deffered-action';
try {
L.hasSystemFeature('opkg');
this.load_feat_env(ctx);
} catch(e) {
// nothing
}
},
load_feat_env: function(ctx)
{
ctx.packager = { };
if (L.hasSystemFeature('apk')) {
ctx.packager.name = 'apk';
ctx.packager.path = '/usr/bin/apk';
ctx.packager.args = [ 'list', '-I', '*'+this.appName+'*' ];
} else {
ctx.packager.name = 'opkg';
ctx.packager.path = '/bin/opkg';
ctx.packager.args = [ 'list-installed', '*'+this.appName+'*' ];
}
},
});

View File

@@ -1,8 +0,0 @@
textarea, .cbi-value textarea
{
white-space: pre;
overflow-x: auto;
font-family: monospace;
pointer-events: auto !important;
user-select: text !important;
}

View File

@@ -1,995 +0,0 @@
'use strict';
'require baseclass';
'require fs';
'require rpc';
'require ui';
'require uci';
'require view.zapret.env as env_tools';
document.head.append(E('style', {'type': 'text/css'},
`
.label-status {
display: inline;
margin: 0 2px 0 0 !important;
padding: 2px 4px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
font-weight: bold;
color: #fff !important;
}
.starting {
background-color: #9c994c !important;
}
.running {
background-color: #2ea256 !important;
}
.updating {
background-color: #1e82ff !important;
}
.stopped {
background-color: #8a8a8a !important;
}
.error {
background-color: #ff4e54 !important;
}
`));
return baseclass.extend({
__init__() {
env_tools.load_env(this);
//console.log('appName: ' + this.appName);
//console.log('PACKAGER: ' + this.packager.name);
},
load_feat_env: function()
{
env_tools.load_feat_env(this);
},
infoLabelRunning : '<span class="label-status running">' + _('Running') + '</span>',
infoLabelStarting : '<span class="label-status starting">' + _('Starting') + '</span>',
infoLabelStopped : '<span class="label-status stopped">' + _('Stopped') + '</span>',
infoLabelDisabled : '<span class="label-status stopped">' + _('Disabled') + '</span>',
infoLabelError : '<span class="label-status error">' + _('Error') + '</span>',
infoLabelUpdating : '<span class="label-status updating">' + _('Updating') + '</span>',
statusDict: {
error : { code: 0, name: _('Error') , label: this.infoLabelError },
disabled : { code: 1, name: _('Disabled') , label: this.infoLabelDisabled },
stopped : { code: 2, name: _('Stopped') , label: this.infoLabelStopped },
starting : { code: 3, name: _('Starting') , label: this.infoLabelStarting },
running : { code: 4, name: _('Running') , label: this.infoLabelRunning },
},
callServiceList: rpc.declare({
object: 'service',
method: 'list',
params: [ 'name', 'verbose' ],
expect: { '': {} }
}),
callInitState: rpc.declare({
object: 'luci',
method: 'getInitList',
params: [ 'name' ],
expect: { '': {} }
}),
callInitAction: rpc.declare({
object: 'luci',
method: 'setInitAction',
params: [ 'name', 'action' ],
expect: { result: false }
}),
getSvcInfo: function(svc_name = null) {
let name = (svc_name) ? svc_name : this.appName;
let verbose = 1;
return this.callServiceList(name, verbose).then(res => {
return res;
}).catch(e => {
ui.addNotification(null, E('p', _('Failed to get %s service info: %s').format(name, e)));
});
},
getInitState: function(name) {
return this.callInitState(name).then(res => {
if (res) {
return res[name].enabled ? true : false;
} else {
throw _('Command failed');
}
}).catch(e => {
ui.addNotification(null, E('p', _('Failed to get %s init status: %s').format(name, e)));
});
},
getPackageDict: function()
{
let exec_cmd = this.packager.path;
let exec_arg = this.packager.args;
return fs.exec(exec_cmd, exec_arg).then(res => {
let pdict_json = localStorage.getItem(this.skey_pkg_dict);
if (res.code != 0) {
console.log(this.appName + ': Unable to enumerate installed packages. code = ' + res.code);
if (pdict_json != null) {
return JSON.parse(pdict_json); // return cached value
}
return null;
}
let pdict = this.decode_pkg_list(res.stdout);
if (pdict != pdict_json) {
localStorage.setItem(this.skey_pkg_dict, JSON.stringify(pdict)); // renew cache
}
return pdict;
}).catch(e => {
ui.addNotification(null, E('p', _('Unable to enumerate installed packages.') + ' Error: %s'.format(e)));
});
},
getStratList: function() {
let exec_cmd = '/bin/busybox';
let exec_arg = [ 'awk', '-F', '"', '/if \\[ "\\$strat" = "/ {print $4}', this.defCfgPath ];
return fs.exec(exec_cmd, exec_arg).then(res => {
if (res.code == 0) {
return this.getWordsArray(res.stdout);
}
return [ ];
}).catch(e => {
ui.addNotification(null, E('p', _('Failed to get strat list: %s').format(e)));
});
},
handleServiceAction: function(name, action, throwed = false)
{
console.log('handleServiceAction: '+name+' '+action);
return this.callInitAction(name, action).then(success => {
if (!success) {
throw _('Command failed');
}
return true;
}).catch(e => {
ui.addNotification(null, E('p', _('Service action failed "%s %s": %s').format(name, action, e)));
if (throwed) {
throw e;
}
});
},
serviceActionEx: async function(action, args = [ ], throwed = false)
{
let errmsg = null;
try {
let exec_cmd = null;
let exec_arg = [ ];
if (action == 'start' || action == 'restart') {
exec_cmd = this.syncCfgPath;
errmsg = _('Unable to run sync_config.sh script.');
}
if (action == 'reset') {
exec_cmd = this.defaultCfgPath;
exec_arg = args; // (reset_ipset)(sync) ==> restore all configs + sync config
errmsg = _('Unable to run restore-def-cfg.sh script.');
action = null;
}
if (exec_cmd) {
let res = await fs.exec(exec_cmd, exec_arg);
if (res.code != 0) {
throw Error('res.code = ' + res.code);
}
}
errmsg = null;
if (action) {
await this.handleServiceAction(this.appName, action, throwed);
}
} catch(e) {
if (throwed) {
throw e;
} else {
let msg = errmsg ? errmsg : _('Unable to run service action') + ' "' + action + '".';
ui.addNotification(null, E('p', msg + ' Error: ' + e.message));
}
}
},
promiseAllDict: function(promisesDict)
{
const keys = Object.keys(promisesDict);
const promises = keys.map(key => promisesDict[key]);
return Promise.all(promises)
.then(results => {
const resultDict = { };
keys.forEach((key, index) => {
resultDict[key] = results[index];
});
return resultDict;
});
},
baseLoad: function(ctx, callback)
{
return Promise.all([
L.probeSystemFeatures(),
this.getSvcInfo(), // svc_info
uci.load(this.appName),
])
.then( ([ sys_feat, svcInfo, uci_data ]) => {
let svc_info = this.decodeSvcInfo(svcInfo);
let ret = { sys_feat, svc_info, uci_data };
if (typeof(callback) === 'function') {
const res = callback.call(ctx, ret);
if (res && typeof(res.then) === 'function') {
return res.then(() => res);
}
return ret;
}
return ret;
})
.catch(e => {
ui.addNotification(null, E('p', _('Unable to read the contents') + ' (baseLoad): %s '.format(e.message) ));
return null;
});
},
decodeSvcInfo: function(svc_info, svc_autorun = true, proc_list = [ ])
{
if (svc_info?.autorun !== undefined && svc_info?.dmn !== undefined) {
return svc_info;
}
if (svc_info != null && typeof(svc_info) == 'object') {
return this.decode_svc_info(svc_autorun, svc_info, proc_list);
}
return null;
},
setDefferedAction: function(action, svcInfo = null, forced = false)
{
let svc_info = this.decodeSvcInfo(svcInfo);
if (action == 'start' && svc_info?.dmn.inited) {
action = 'restart';
}
if (action == 'start') {
if (!forced && svc_info?.dmn.inited) {
action = null;
}
}
if (action == 'restart') {
if (!forced && !svc_info?.dmn.inited) {
action = null;
}
}
if (action && localStorage.getItem(this.skey_deffered_action) == null) {
localStorage.setItem(this.skey_deffered_action, action);
console.log('setDefferedAction: '+this.skey_deffered_action+' = '+action);
}
},
execDefferedAction: function(svcInfo = null)
{
let svc_info = this.decodeSvcInfo(svcInfo);
//console.log('execDefferedAction: svc_info = '+JSON.stringify(svc_info));
let action = localStorage.getItem(this.skey_deffered_action);
if (action) {
localStorage.removeItem(this.skey_deffered_action);
console.log('execDefferedAction: '+action);
this.serviceActionEx(action);
}
},
checkUnsavedChanges: function()
{
if (!ui.changes) return false;
if (!ui.changes.changes) return false;
return ui.changes.changes[this.appName] ? true : false;
},
normalizeValue: function(v) {
return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
},
getWordsArray: function (text, { trim = true, removeEmpty = true } = {}) {
const rawLines = text.split(/\n/);
const processed = trim ? rawLines.map(line => line.trim()) : rawLines.slice();
return removeEmpty ? processed.filter(line => line.length > 0) : processed;
},
getConfigPar: function(txt, key, defval = null) {
const re = new RegExp(`^${key}\\s*=\\s*(['"])(.*?)\\1`, 'm');
const m = txt.match(re);
return m ? m[2] : defval;
},
decode_pkg_list: function(pkg_list) {
let pkg_dict = { };
if (!pkg_list) {
return pkg_dict;
}
let lines = pkg_list.trim().split('\n');
for (let i = 0; i < lines.length; i++) {
let line = lines[i].trim();
let name;
let ver;
let rev = -1;
if (this.packager.name == 'apk') {
let fullname = line.split(' ')[0];
let match = fullname.match(/^(.*)-r(\d+)$/);
if (match) {
fullname = match[1];
rev = parseInt(match[2], 10);
}
let mpos = fullname.lastIndexOf('-');
if (mpos <= 0)
continue; // incorrect format
name = fullname.slice(0, mpos).trim();
ver = fullname.slice(mpos + 1).trim();
} else {
if (!line.includes(' - '))
continue; // incorrect format
name = line.split(' - ')[0].trim();
ver = line.split(' - ')[1].trim();
let spos = ver.indexOf(" ");
if (spos > 0) {
ver = ver.substring(0, spos);
}
let match = ver.match(/^(.*)-r(\d+)$/);
if (match) {
ver = match[1];
rev = parseInt(match[2], 10);
}
}
if (rev >= 0) {
ver += '-r' + rev;
}
pkg_dict[name] = ver;
}
return pkg_dict;
},
get_pid_list: function(proc_list) {
let plist = [ ];
let lines = proc_list.trim().split('\n');
for (let i = 0; i < lines.length; i++) {
let line = lines[i].trim();
if (line.length > 5) {
let word_list = line.split(/\s+/);
let pid = word_list[0];
let isnum = /^\d+$/.test(pid);
if (isnum) {
plist.push(parseInt(pid));
}
}
}
return plist;
},
decode_svc_info: function(svc_autorun, svc_info, proc_list, cfg = null)
{
let result = {
"autorun": svc_autorun,
"dmn": {
inited: false,
total: 0,
running: 0,
working: 0,
},
"status": this.statusDict.error,
};
let plist = proc_list;
if (proc_list?.code !== undefined) {
if (proc_list.code != 0) {
return -2;
}
plist = this.get_pid_list(proc_list.stdout);
if (plist.length < 4) {
return -3;
}
}
if (svc_info == null) {
return null;
}
if (typeof(svc_info) !== 'object') {
return -4;
}
let jdata = svc_info;
if (typeof(jdata[this.appName]) == 'object') {
result.dmn.inited = true;
let dmn_list = jdata[this.appName].instances;
if (typeof(dmn_list) == 'object') {
for (const [dmn_name, daemon] of Object.entries(dmn_list)) {
result.dmn.total += 1;
if (daemon.running) {
result.dmn.running += 1;
}
if (daemon.pid !== undefined && daemon.pid != null) {
if (plist.includes(daemon.pid)) {
result.dmn.working += 1;
}
}
}
}
}
//console.log('SVC_DAEMONS: ' + result.dmn.working + ' / ' + result.dmn.total);
if (result.dmn.total == 0) {
result.status = (!svc_autorun) ? this.statusDict.disabled : this.statusDict.stopped;
} else {
result.status = (result.dmn.inited) ? this.statusDict.started : this.statusDict.running;
}
return result;
},
makeStatusString: function(svcinfo, pkg_arch, bllist_preset) {
let svc_autorun = _('Unknown');
let svc_daemons = _('Unknown');
if (typeof(svcinfo) == 'object' && svcinfo?.autorun !== undefined) {
svc_autorun = (svcinfo.autorun) ? _('Enabled') : _('Disabled');
if (!svcinfo.dmn.inited) {
svc_daemons = _('Stopped');
} else {
svc_daemons = (!svcinfo.dmn.working) ? _('Starting') : _('Running');
svc_daemons += ' [' + svcinfo.dmn.working + '/' + svcinfo.dmn.total + ']';
}
}
let td_name_width = 40;
let td_name_style = `style="width: ${td_name_width}%; min-width:${td_name_width}%; max-width:${td_name_width}%;"`;
let out = `
<table class="table">
<tr class="tr">
<td class="td left" ${td_name_style}>
${_('CPU architecture')}:
</td>
<td class="td left">
${pkg_arch}
</td>
</tr>
<tr class="tr">
<td class="td left" ${td_name_style}>
${_('Service autorun status')}:
</td>
<td class="td left">
${svc_autorun}
</td>
</tr>
<tr class="tr">
<td class="td left" ${td_name_style}>
${_('Service daemons status')}:
</td>
<td class="td left %s">
${svc_daemons}
</td>
</tr>
<tr class="tr">
<td class="td left" ${td_name_style}>
</td>
<td class="td left">
</td>
</tr>
</table>`;
return out;
},
getLineCount: function(mstr) {
let count = 0;
let c = '\n'.charAt(0);
for (let i = 0; i < mstr.length; ++i) {
if (c === mstr.charAt(i)) {
++count;
}
}
return count;
},
fileEditDialog: baseclass.extend({
__init__: function(opts = {})
{
Object.assign(this, {
file: '',
title: '',
desc: '',
aux: '',
rows: 10,
callback: null,
file_exists: false,
setperm: 644,
}, opts);
},
load: function() {
return L.resolveDefault(fs.read(this.file), '');
},
render: function(content) {
let descr = this.desc;
if (this.aux)
descr += '<br />' + this.aux;
ui.showModal(this.title, [
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'cbi-section-descr' }, descr),
E('div', { 'class': 'cbi-section' },
E('p', {},
E('textarea', {
'id': 'widget.modal_content',
'class': 'cbi-input-textarea',
'style': 'width:100% !important',
'rows': this.rows,
'wrap': 'off',
'spellcheck': 'false',
},
content)
)
),
]),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': ui.hideModal,
}, _('Dismiss')),
' ',
E('button', {
'id': 'btn_save',
'class': 'btn cbi-button-positive important',
'click': ui.createHandlerFn(this, this.handleSaveAdv),
}, _('Save')),
]),
]);
},
writeAdv: async function(fileName, data, chunkSize = 8000)
{
let tmpFile = fileName + '.tmp';
try {
for (let wsize = 0; wsize <= data.length; wsize += chunkSize) {
let chunk = data.slice(wsize, wsize + chunkSize);
if (wsize > 0 && chunk.length == 0) {
break; // EOF
}
chunk = chunk.replace(/'/g, `'\"'\"'`);
let teeArg = (wsize === 0) ? '' : '-a';
let cmd = `printf %s '${chunk}' | tee ${teeArg} '${tmpFile}'`;
let res = await fs.exec('/bin/busybox', [ 'sh', '-c', cmd ]);
if (res.code !== 0) {
throw new Error('tee failed, rc = ' + res.code);
}
}
if (this.setperm) {
let res = await fs.exec('/bin/busybox', [ 'chmod', '' + this.setperm, tmpFile ]);
if (res.code != 0) {
throw new Error('chmod failed, rc = ' + res.code);
}
}
let res = await fs.exec('/bin/busybox', [ 'mv', '-f', tmpFile, fileName ]);
if (res.code != 0) {
throw new Error('mv failed, rc = ' + res.code);
}
} catch(e) {
try {
await fs.exec('/bin/busybox', [ 'rm', '-f', tmpFile ]);
} catch(e2) {
// nothing
}
throw e;
}
return fs.stat(fileName);
},
handleSaveAdv: async function(ev)
{
let txt = document.getElementById('widget.modal_content');
let value = txt.value.trim().replace(/\r\n/g, '\n');
if (value.length > 0) {
value += '\n';
}
return this.writeAdv(this.file, value).then(async rc => {
txt.value = value;
ui.addNotification(null, E('p', _('Contents have been saved.')), 'info');
if (this.callback) {
return this.callback(rc);
}
}).catch(e => {
ui.addNotification(null, E('p', _('Unable to save the contents') + ': %s'.format(e.message)));
}).finally(() => {
ui.hideModal();
});
},
error: function(e) {
if (!this.file_exists && e instanceof Error && e.name === 'NotFoundError') {
return this.render();
} else {
ui.showModal(this.title, [
E('div', { 'class': 'cbi-section' },
E('p', {}, _('Unable to read the contents') + ': %s'.format(e.message))
),
E('div', { 'class': 'right' },
E('button', {
'class': 'btn',
'click': ui.hideModal,
}, _('Dismiss'))
),
]);
}
},
show: function() {
ui.showModal(null,
E('p', { 'class': 'spinning' }, _('Loading'))
);
this.load().then(content => {
ui.hideModal();
return this.render(content);
}).catch(e => {
ui.hideModal();
return this.error(e);
});
},
}),
longstrEditDialog: baseclass.extend({
__init__: function(opts = {})
{
Object.assign(this, {
cfgsec: '',
cfgparam: '',
title: '',
desc: '',
rows: 10,
multiline: false // may be 2
}, opts);
env_tools.load_env(this);
},
load: function() {
let value = uci.get(this.appName, this.cfgsec, this.cfgparam);
if (typeof(value) === 'string') {
value = value.trim();
if (this.multiline == 2) {
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n --/g, "\n--");
value = value.replace(/\n --/g, "\n--");
value = value.replace(/ --/g, "\n--");
}
}
return value;
},
render: function(content) {
ui.showModal(this.title, [
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'cbi-section-descr' }, this.desc),
E('div', { 'class': 'cbi-section' },
E('p', {},
E('textarea', {
'id': 'widget.modal_content',
'class': 'cbi-input-textarea',
'style': 'width:100% !important',
'rows': this.rows,
'wrap': 'off',
'spellcheck': 'false',
},
content)
)
),
]),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': ui.hideModal,
}, _('Dismiss')),
' ',
E('button', {
'id': 'btn_save',
'class': 'btn cbi-button-positive important',
'click': ui.createHandlerFn(this, this.handleSaveAdv),
}, _('Save')),
]),
]);
},
handleSaveAdv: function(ev) {
let txt = document.getElementById('widget.modal_content');
let value = txt.value.trim();
if (this.multiline) {
value = value.replace(/\r/g, '');
if (value != "" && value != "\t") {
value = '\n' + value + '\n';
if (this.multiline == 2) {
if (value.includes('"')) {
alert(_('Unable to save the contents') + ':\n' + _('text cannot contain quotes!'));
return false;
}
value = value.replace(/"/g, '');
}
}
} else {
value = value.replace(/\r\n/g, ' ');
value = value.replace(/\r/g, ' ');
value = value.replace(/\n/g, ' ');
value = value.trim();
}
if (value == "") {
value = "\t";
}
value = value.replace(/˂/g, '<');
value = value.replace(/˃/g, '>');
try {
let elem = document.getElementById("widget.cbid." + this.appName + ".config._" + this.cfgparam);
if (elem) {
let val = value.trim();
elem.textContent = val;
}
} catch(e) {
console.error('ERROR: cannot found elem for ' + this.cfgsec + '.' + this.cfgparam);
}
uci.set(this.appName, this.cfgsec, this.cfgparam, value);
uci.save().then(ui.hideModal);
},
error: function(e) {
let msg = (typeof(e) == 'object') ? e.message : ''+e;
ui.showModal(this.title, [
E('div', { 'class': 'cbi-section' },
E('p', {}, _('Unable to read the contents') + ': %s'.format(msg))
),
E('div', { 'class': 'right' },
E('button', {
'class': 'btn',
'click': ui.hideModal,
}, _('Dismiss'))
),
]);
},
show: function() {
ui.showModal(null,
E('p', { 'class': 'spinning' }, _('Loading'))
);
L.resolveDefault(this.load(), null)
.then(content => {
ui.hideModal();
return this.render(content);
}).catch(e => {
ui.hideModal();
return this.error(e);
})
},
}),
execAndRead: async function({ cmd = [ ], log = '', logArea = null, callback = null, ctx = null, hiderow = [ ], rpc_timeout = 5, rpc_root = false } = {})
{
function appendLog(msg, end = '\n')
{
logArea.value += msg + end;
logArea.scrollTop = logArea.scrollHeight;
}
function fixLogEnd()
{
if (logArea.value && logArea.value.slice(-1) != '\n') {
appendLog('');
}
}
let hide_rows = Array.isArray(hiderow) ? hiderow : [ hiderow ];
let rpc_opt = { "timeout": rpc_timeout*1000 };
if (rpc_root) {
rpc_opt.uid = 0; // run under root
}
const logFile = log; // file for reading: '/tmp/zapret_pkg_install.log'
const rcFile = logFile + '.rc';
try {
await fs.exec('/bin/busybox', [ 'rm', '-f', logFile + '*' ], null, rpc_opt);
appendLog('Output file cleared!');
} catch (e) {
return callback.call(ctx, 500, 'ERROR: Failed to clear output file');
}
try {
let opt_list = [ logFile ];
opt_list.push(...cmd);
let res = await fs.exec(this.appDir+'/script-exec.sh', opt_list, null, rpc_opt);
if (res.code != 0) {
return callback.call(ctx, 525, 'ERROR: cannot run "' + cmd[0] + '" script! (error = ' + res.code + ')');
}
appendLog('Process started...');
} catch (e) {
return callback.call(ctx, 520, 'ERROR: Failed on execute process: ' + e.message);
}
let lastLen = 0;
let retCode = -1;
return await new Promise(async (resolve, reject) => {
async function epoll()
{
try {
let res = await fs.exec('/bin/cat', [ logFile ], null, rpc_opt);
if (res.stdout && res.stdout.length > lastLen) {
let log = res.stdout.slice(lastLen);
hide_rows.forEach(re => {
log = log.replace(re, '');
});
appendLog(log, '');
lastLen = res.stdout.length;
}
if (retCode < 0) {
let rc = await fs.exec('/bin/cat', [ rcFile ], null, rpc_opt);
if (rc.code != 0) {
fixLogEnd();
resolve(callback.call(ctx, 545, 'ERROR: cannot read file "' + rcFile + '"'));
return;
}
if (rc.stdout) {
retCode = parseInt(rc.stdout.trim(), 10);
}
}
if (retCode >= 0) {
fixLogEnd();
if (retCode == 0 && res.stdout) {
resolve(callback.call(ctx, 0, res.stdout));
return;
}
resolve(callback.call(ctx, retCode, 'ERROR: Process failed with error ' + retCode));
return;
}
setTimeout(epoll, 500);
} catch (e) {
let skip_err = false;
if (e.message?.includes('RPC call to file/exec failed with error -32000: Object not found')) {
skip_err = true;
}
if (e.message?.includes('XHR request timed out')) {
skip_err = true;
}
if (skip_err) {
console.warn('WARN: execAndRead: ' + e.message);
setTimeout(epoll, 500);
return; // goto next epoll iteration
}
fixLogEnd();
let errtxt = 'ERROR: execAndRead: ' + e.message;
errtxt += 'ERROR: execAndRead: ' + e.stack?.trim().split('\n')[0];
callback.call(ctx, 540, errtxt);
reject(e);
}
}
epoll();
});
},
POLLER: baseclass.extend({
__init__: function(opts = { })
{
Object.assign(this, {
interval: 1000, // milliseconds
func: null,
active: false,
running: false,
}, opts);
env_tools.load_env(this);
this.ticks = 0;
this.timer = null;
this.mode = 0;
},
init: function(func, interval = null)
{
this.func = func;
if (interval) {
this.interval = interval;
}
},
start: function(delay = 0)
{
if (this.active) {
return;
}
this.ticks = 0;
this.active = true;
if (delay === null) {
this.step();
delay = this.interval;
}
this.timer = window.setTimeout(this.step.bind(this), delay);
return true;
},
stop: function()
{
this.active = false;
if (this.timer) {
window.clearTimeout(this.timer);
this.timer = null;
}
},
step: function()
{
if (!this.active) {
return;
}
if (this.timer) {
window.clearTimeout(this.timer);
}
if (this.mode == 1 && this.running) {
this.timer = window.setTimeout(this.step.bind(this), 100);
return;
}
this.ticks += 1;
this.running = true;
Promise.resolve(this.func()).finally((function() {
if (this.mode == 0) {
this.running = false;
}
this.timer = null;
if (this.active) {
this.timer = window.setTimeout(this.step.bind(this), this.interval);
}
}).bind(this));
},
stopAndWait: async function(interval = 50)
{
this.stop();
if (!this.running) {
return;
}
return new Promise((resolve) => {
if (!this.running) {
return resolve();
}
const timer = setInterval(() => {
if (!this.running) {
resolve();
}
}, interval);
});
},
}),
// original code: https://github.com/openwrt/luci/blob/95319793a27a3554be06070db8c6db71c6e28df1/modules/luci-base/htdocs/luci-static/resources/ui.js#L5342
createHandlerFnEx: function(ctx, fn, opts = { }, ...args)
{
if (typeof(fn) === 'string') {
fn = ctx[fn];
}
if (typeof(fn) !== 'function') {
return null;
}
const {
callback = null, // callback(btn, result, error)
keepDisabled = false,
noSpin = false
} = opts;
return L.bind(function() {
const btn = arguments[args.length].currentTarget;
if (!noSpin) {
btn.classList.add('spinning');
}
btn.disabled = true;
if (btn.blur) btn.blur();
let result, error;
return Promise
.resolve()
.then(() => fn.apply(ctx, arguments))
.then(r => { result = r; })
.catch(e => { error = e; })
.finally(() => {
if (!noSpin) {
btn.classList.remove('spinning');
}
if (!keepDisabled) {
btn.disabled = false;
}
if (typeof(callback) === 'function') {
callback.call(ctx, btn, result, error);
}
if (error) {
throw error;
}
});
}, ctx, ...args);
},
});

View File

@@ -1,213 +0,0 @@
'use strict';
'require baseclass';
'require fs';
'require poll';
'require uci';
'require ui';
'require view';
'require view.zapret.tools as tools';
const btn_style_neutral = 'btn';
const btn_style_action = 'btn cbi-button-action';
const btn_style_positive = 'btn cbi-button-save important';
const btn_style_negative = 'btn cbi-button-reset important';
const btn_style_warning = 'btn cbi-button-negative';
const btn_style_success = 'btn cbi-button-success important';
const fn_update_pkg_sh = '/opt/'+tools.appName+'/update-pkg.sh';
return baseclass.extend({
releasesUrlPrefix : 'https://raw.githubusercontent.com/remittor/zapret-openwrt/gh-pages/releases/',
appendLog: function(msg, end = '\n')
{
this.logArea.value += msg + end;
this.logArea.scrollTop = this.logArea.scrollHeight;
},
setBtnMode: function(check, install, cancel)
{
this.btn_check.disabled = check ? false : true;
this.btn_install.disabled = install ? false : true;
this.btn_cancel.disabled = cancel ? false : true;
},
setStage: function(stage, btn_flag = true)
{
if (stage == 0) this.setBtnMode(1, 0, 1);
if (stage == 1) this.setBtnMode(0, 0, 1);
if (stage == 2) this.setBtnMode(1, 1, 1);
if (stage == 3) this.setBtnMode(0, 0, 0);
if (stage == 8) this.setBtnMode(0, 0, 1);
if (stage >= 9) this.setBtnMode(0, 0, 0);
this.stage = stage;
},
checkUpdates: async function(ev)
{
this._action = 'checkUpdates';
this.setStage(1);
this.pkg_url = null;
this.appendLog(_('Checking for updates...'));
let cmd = [ fn_update_pkg_sh, '-c' ]; // check for updates
if (document.getElementById('cfg_exclude_prereleases').checked == false) {
cmd.push('-p'); // include prereleases ZIP-files
}
this.forced_reinstall = document.getElementById('cfg_forced_reinstall').checked;
return tools.execAndRead({
cmd: cmd,
log: '/tmp/'+tools.appName+'_pkg_check.log',
logArea: this.logArea,
callback: this.execAndReadCallback,
ctx: this,
});
},
installUpdates: async function(ev)
{
if (!this.pkg_url || this.pkg_url.length < 10) {
this.appendLog('ERROR: pkg_url = null');
this.setStage(9);
return;
}
this._action = 'installUpdates';
this.setStage(3);
this.appendLog(_('Install updates...'));
let cmd = [ fn_update_pkg_sh, '-u', this.pkg_url ]; // update packages
if (document.getElementById('cfg_forced_reinstall').checked == true) {
cmd.push('-f'); // forced reinstall if same version
}
//this._test = 1; cmd.push('-t'); cmd.push('45'); // only for testing
return tools.execAndRead({
cmd: cmd,
log: '/tmp/'+tools.appName+'_pkg_install.log',
logArea: this.logArea,
hiderow: /^ \* resolve_conffiles.*(?:\r?\n|$)/gm,
callback: this.execAndReadCallback,
ctx: this,
});
},
execAndReadCallback: function(rc, txt = '')
{
//console.log('execAndReadCallback = ' + rc + '; _action = ' + this._action);
if (rc == 0 && txt) {
let code = txt.match(/^RESULT:\s*\(([^)]+)\)\s+.+$/m);
if (this._action == 'checkUpdates') {
this.appendLog('=========================================================');
if (code && code[1] == 'E') {
this.btn_install.textContent = _('Reinstall');
} else {
this.btn_install.textContent = _('Install');
}
let pkg_url = txt.match(/^ZAP_PKG_URL\s*=\s*(.+)$/m);
if (code && pkg_url) {
if (!this.forced_reinstall) {
if (code[1] == 'E' || code[1] == 'G') {
this.setStage(0); // install not needed
return;
}
}
this.pkg_url = pkg_url[1];
this.setStage(2); // enable all buttons
return; // install allowed
}
}
if (this._action == 'installUpdates') {
if (this._test || (code && code[1] == '+')) {
this.setStage(9);
this.appendLog('Please update WEB-page (press F5)');
return;
}
}
}
this.setStage(0);
if (rc >= 500) {
if (txt) {
this.appendLog(txt.startsWith('ERROR') ? txt : 'ERROR: ' + txt);
} else {
this.appendLog('ERROR: ' + this._action + ': Terminated with error code = ' + rc);
}
} else {
this.appendLog('ERROR: Process finished with retcode = ' + rc);
}
this.appendLog('=========================================================');
},
openUpdateDialog: function(pkg_arch)
{
if (tools.checkUnsavedChanges()) {
ui.addNotification(null, E('p', _('You have unapplied changes')));
return;
}
this.stage = 0;
this.pkg_arch = pkg_arch;
this.pkg_url = null;
let exclude_prereleases = E('label', [
E('input', { type: 'checkbox', id: 'cfg_exclude_prereleases', checked: true }),
' ', _('Exclude PreReleases')
]);
let forced_reinstall = E('label', [
E('input', { type: 'checkbox', id: 'cfg_forced_reinstall'}),
' ', _('Forced reinstall packages')
]);
this.logArea = E('textarea', {
'id': 'widget.modal_content',
'readonly': true,
'style': 'width:100% !important; font-family: monospace;',
'rows': 20,
'wrap': 'off',
});
this.btn_cancel = E('button', {
'id': 'btn_cancel',
'name': 'btn_cancel',
'class': btn_style_warning,
}, _('Cancel'));
this.btn_cancel.onclick = ui.hideModal;
this.btn_check = E('button', {
'id': 'btn_check',
'name': 'btn_check',
'class': btn_style_action,
}, _('Check'));
this.btn_check.onclick = ui.createHandlerFn(this, this.checkUpdates);
this.btn_install = E('button', {
'id': 'btn_install',
'name': 'btn_install',
'class': btn_style_positive,
}, _('Install'));
this.btn_install.onclick = ui.createHandlerFn(this, async () => {
let res = await this.installUpdates();
if (true) {
setTimeout(() => {
this.btn_install.disabled = true;
}, 0);
}
});
this.setStage(0);
ui.showModal(_('Check for updates and install'), [
E('div', { 'class': 'cbi-section' }, [
exclude_prereleases,
E('br'), E('br'),
forced_reinstall,
E('br'), E('br'),
E('hr'),
this.logArea,
]),
E('div', { 'class': 'right' }, [
this.btn_check,
' ',
this.btn_install,
' ',
this.btn_cancel,
])
]);
}
});

View File

@@ -8,17 +8,15 @@
'require view.zapret.tools as tools'; 'require view.zapret.tools as tools';
return view.extend({ return view.extend({
POLL: new tools.POLLER( { } ), retrieveLog: async function() {
return Promise.all([
retrieveLog: async function() L.resolveDefault(fs.stat('/bin/cat'), null),
{ fs.exec('/usr/bin/find', [ '/tmp', '-maxdepth', '1', '-type', 'f', '-name', 'zapret2+*.log' ]),
return tools.promiseAllDict({ uci.load(tools.appName),
filereader : L.resolveDefault(fs.stat('/bin/cat'), null), ]).then(function(status_array) {
log_data : fs.exec('/usr/bin/find', [ '/tmp', '-maxdepth', '1', '-type', 'f', '-name', tools.appName+'+*.log' ]), var filereader = status_array[0] ? status_array[0].path : null;
}).then( (data) => { var log_data = status_array[1]; // stdout: multiline text
var filereader = data.filereader ? data.filereader.path : null; if (log_data.code != 0) {
var log_data = data.log_data; // stdout: multiline text
if (log_data?.code === undefined || log_data.code != 0) {
ui.addNotification(null, E('p', _('Unable to get log files') + '(code = ' + log_data.code + ') : retrieveLog()')); ui.addNotification(null, E('p', _('Unable to get log files') + '(code = ' + log_data.code + ') : retrieveLog()'));
return null; return null;
} }
@@ -66,24 +64,21 @@ return view.extend({
}).catch(function(e) { }).catch(function(e) {
ui.addNotification(null, E('p', _('Unable to execute or read contents') ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ ': %s [ %s | %s | %s ]'.format( + ': %s [ %s | %s | %s ]'.format(
e.message, 'retrieveLogData', 'uci.'+tools.appName e.message, 'retrieveLogData', 'uci.zapret'
))); )));
return null; return null;
}); });
}).catch( (e) => { }).catch(function(e) {
const [, lineno, colno] = e.stack.match(/(\d+):(\d+)/); const [, lineno, colno] = e.stack.match(/(\d+):(\d+)/);
ui.addNotification(null, E('p', _('Unable to execute or read contents') ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ ': %s [ lineno: %s | %s | %s | %s ]'.format( + ': %s [ lineno: %s | %s | %s | %s ]'.format(
e.message, lineno, 'retrieveLog', 'uci.'+tools.appName e.message, lineno, 'retrieveLog', 'uci.zapret'
))); )));
return null; return null;
}).finally( () => {
this.POLL.running = false;
}); });
}, },
pollLog: async function() pollLog: async function() {
{
let logdate_len = -2; let logdate_len = -2;
let logdata; let logdata;
for (let txt_id = 0; txt_id < 10; txt_id++) { for (let txt_id = 0; txt_id < 10; txt_id++) {
@@ -95,49 +90,47 @@ return view.extend({
logdate_len = (Array.isArray(logdata)) ? logdata.length : -1; logdate_len = (Array.isArray(logdata)) ? logdata.length : -1;
} }
let elem_name = elem.getAttribute("name"); let elem_name = elem.getAttribute("name");
let found = false; let founded = false;
if (logdate_len > 0) { if (logdate_len > 0) {
for (let log_num = 0; log_num < logdate_len; log_num++) { for (let log_num = 0; log_num < logdate_len; log_num++) {
if (logdata[log_num].filename == elem_name) { if (logdata[log_num].filename == elem_name) {
if (logdata[log_num].data) { if (logdata[log_num].data) {
elem.value = logdata[log_num].data; elem.value = logdata[log_num].data;
elem.rows = logdata[log_num].rows; elem.rows = logdata[log_num].rows;
found = true; founded = true;
//console.log('POLL: updated ' + elem_name); //console.log('POLL: updated ' + elem_name);
} }
break; break;
} }
} }
} }
if (!found) { if (!founded) {
elem.value = ''; elem.value = '';
elem.rows = 0; elem.rows = 0;
} }
} }
}, },
load: function() load: async function() {
{ poll.add(this.pollLog.bind(this));
return tools.baseLoad(this, (data) => { return await this.retrieveLog();
tools.load_feat_env();
this.svc_info = data.svc_info;
return this.retrieveLog();
});
}, },
render: function(logdata) render: function(logdata) {
{ if (!logdata) {
return;
}
if (typeof(logdata) === 'string') { if (typeof(logdata) === 'string') {
return E('div', {}, [ return E('div', {}, [
E('p', {'class': 'cbi-title-field'}, [ logdata ]), E('p', {'class': 'cbi-title-field'}, [ logdata ]),
]); ]);
} }
if (!logdata || !Array.isArray(logdata)) { if (!Array.isArray(logdata)) {
ui.addNotification(null, E('p', _('Unable to get log files') + ' : render()')); ui.addNotification(null, E('p', _('Unable to get log files') + ' : render()'));
return; return;
} }
var h2 = E('div', {'class' : 'cbi-title-section'}, [ var h2 = E('div', {'class' : 'cbi-title-section'}, [
E('h2', {'class': 'cbi-title-field'}, [ ]), E('h2', {'class': 'cbi-title-field'}, [ _('Zapret2') + ' - ' + _('Log Viewer') ]),
]); ]);
var tabs = E('div', {}, E('div')); var tabs = E('div', {}, E('div'));
@@ -147,11 +140,7 @@ return view.extend({
var logfn = logdata[log_num].filename; var logfn = logdata[log_num].filename;
let filename = logfn.replace(/.*\//, ''); let filename = logfn.replace(/.*\//, '');
let fname = filename.split('.')[0]; let fname = filename.split('.')[0];
if (tools.appName == 'zapret2') { fname = fname.replace(/^(zapret2\+)/, '');
fname = fname.replace(/^(zapret2\+)/, '');
} else {
fname = fname.replace(/^(zapret\+)/, '');
}
let fn = fname.split('+'); let fn = fname.split('+');
let tabNameText = fname.replace(/\+/g, ' '); let tabNameText = fname.replace(/\+/g, ' ');
@@ -200,11 +189,8 @@ return view.extend({
tabs.firstElementChild.appendChild(tab); tabs.firstElementChild.appendChild(tab);
} }
ui.tabs.initTabGroup(tabs.firstElementChild.childNodes); ui.tabs.initTabGroup(tabs.firstElementChild.childNodes);
//this.pollFn = L.bind(this.handleScanRefresh, this);
this.POLL.mode = 1; //poll.add(this.pollFn);
this.POLL.init( this.pollLog.bind(this), 1000 ); // interval 1000 ms
this.POLL.start();
return E('div', { }, [ h2, tabs ]); return E('div', { }, [ h2, tabs ]);
}, },

View File

@@ -4,9 +4,8 @@
'require uci'; 'require uci';
'require ui'; 'require ui';
'require view'; 'require view';
'require view.zapret.tools as tools'; 'require view.zapret2.tools as tools';
'require view.zapret.diagnost as diagnost'; 'require view.zapret2.updater as updater';
'require view.zapret.updater as updater';
const btn_style_neutral = 'btn'; const btn_style_neutral = 'btn';
const btn_style_action = 'btn cbi-button-action'; const btn_style_action = 'btn cbi-button-action';
@@ -16,18 +15,15 @@ const btn_style_warning = 'btn cbi-button-negative';
const btn_style_success = 'btn cbi-button-success important'; const btn_style_success = 'btn cbi-button-success important';
return view.extend({ return view.extend({
POLL: new tools.POLLER( { } ),
get_svc_buttons: function(elems = { }) { get_svc_buttons: function(elems = { }) {
return { return {
"enable" : elems.btn_enable || document.getElementById('btn_enable'), enable : elems.btn_enable || document.getElementById('btn_enable'),
"disable" : elems.btn_disable || document.getElementById('btn_disable'), disable : elems.btn_disable || document.getElementById('btn_disable'),
"start" : elems.btn_start || document.getElementById('btn_start'), start : elems.btn_start || document.getElementById('btn_start'),
"restart" : elems.btn_restart || document.getElementById('btn_restart'), restart : elems.btn_restart || document.getElementById('btn_restart'),
"stop" : elems.btn_stop || document.getElementById('btn_stop'), stop : elems.btn_stop || document.getElementById('btn_stop'),
"reset" : elems.btn_reset || document.getElementById('btn_reset'), reset : elems.btn_reset || document.getElementById('btn_reset'),
"diag" : elems.btn_diag || document.getElementById('btn_diag'), update : elems.btn_update || document.getElementById('btn_update'),
"update" : elems.btn_update || document.getElementById('btn_update'),
}; };
}, },
@@ -46,54 +42,59 @@ return view.extend({
btn.update.disabled = (error_code == 0) ? flag : false; btn.update.disabled = (error_code == 0) ? flag : false;
}, },
getAppStatus: function() getAppStatus: function() {
{ return Promise.all([
return tools.promiseAllDict({ tools.getInitState(tools.appName), // svc_boot
svc_boot : tools.getInitState(tools.appName), fs.exec(tools.execPath, [ 'enabled' ]), // svc_en
svc_en : fs.exec(tools.execPath, [ 'enabled' ]), tools.getSvcInfo(), // svc_info
svc_info : tools.getSvcInfo(), fs.exec('/bin/busybox', [ 'ps' ]), // process list
proc_list : fs.exec('/bin/busybox', [ 'ps' ]), fs.exec(tools.packager.path, tools.packager.args), // installed packages
pkg_dict : tools.getPackageDict(), tools.getStratList(), // nfqws strategy list
strat_list : tools.getStratList(), fs.exec('/bin/cat', [ '/etc/openwrt_release' ]), // CPU arch
sys_info : fs.exec('/bin/cat', [ '/etc/openwrt_release' ]), uci.load(tools.appName), // config
uci_data : uci.load(tools.appName), ]).catch(e => {
}).catch(e => {
ui.addNotification(null, E('p', _('Unable to execute or read contents') ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ ': %s [ %s | %s | %s ]'.format( + ': %s [ %s | %s | %s ]'.format(
e.message, tools.execPath, 'tools.getInitState', 'uci.'+tools.appName e.message, tools.execPath, 'tools.getInitState', 'uci.zapret2'
))); )));
}); });
}, },
setAppStatus: function(data, elems = { }, force_app_status = 0) setAppStatus: function(status_array, elems = { }, force_app_status = 0) {
{
tools.execDefferedAction();
let cfg = uci.get(tools.appName, 'config'); let cfg = uci.get(tools.appName, 'config');
if (!data || cfg == null || typeof(cfg) !== 'object') { if (!status_array || cfg == null || typeof(cfg) !== 'object') {
let elem_status = elems.status || document.getElementById("status"); let elem_status = elems.status || document.getElementById("status");
elem_status.innerHTML = tools.makeStatusString(null, '', ''); elem_status.innerHTML = tools.makeStatusString(null, '', '');
ui.addNotification(null, E('p', _('Unable to read the contents') + ': setAppStatus()')); ui.addNotification(null, E('p', _('Unable to read the contents') + ': setAppStatus()'));
this.disableButtons(true, -1, elems); this.disableButtons(true, -1, elems);
return; return;
} }
let svc_boot = data.svc_boot ? true : false; let svc_boot = status_array[0] ? true : false;
this.nfqws_strat_list = data.strat_list; let svc_en = status_array[1]; // stdout: empty or error text
this.pkg_arch = tools.getConfigPar(data.sys_info.stdout, 'DISTRIB_ARCH', 'unknown'); let svc_info = status_array[2]; // stdout: JSON as text
//console.log('svc_en: ' + data.svc_en.code + ' poll.running = ' + this.POLL.running); let proc_list = status_array[3]; // stdout: multiline text
let svc_en = (data.svc_en.code == 0) ? true : false; let pkg_list = status_array[4]; // stdout: installed packages
let stratlist = status_array[5]; // array of strat names
let sys_info = status_array[6]; // stdout: openwrt distrib info
if (typeof(data.svc_info) !== 'object') { this.nfqws_strat_list = stratlist;
this.pkg_arch = tools.getConfigPar(sys_info.stdout, 'DISTRIB_ARCH', 'unknown');
//console.log('svc_en: ' + svc_en.code);
svc_en = (svc_en.code == 0) ? true : false;
if (typeof(svc_info) !== 'object') {
ui.addNotification(null, E('p', _('Unable to read the service info') + ': setAppStatus()')); ui.addNotification(null, E('p', _('Unable to read the service info') + ': setAppStatus()'));
this.disableButtons(true, -1, elems); this.disableButtons(true, -1, elems);
return; return;
} }
if (data.proc_list.code != 0) { if (proc_list.code != 0) {
ui.addNotification(null, E('p', _('Unable to read process list') + ': setAppStatus()')); ui.addNotification(null, E('p', _('Unable to read process list') + ': setAppStatus()'));
this.disableButtons(true, -1, elems); this.disableButtons(true, -1, elems);
return; return;
} }
if (!data.pkg_dict) { if (pkg_list.code != 0) {
ui.addNotification(null, E('p', _('Unable to enumerate installed packages') + ': getPackageDict()')); ui.addNotification(null, E('p', _('Unable to enumerate installed packages') + ': setAppStatus()'));
this.disableButtons(true, -1, elems); this.disableButtons(true, -1, elems);
return; return;
} }
@@ -101,7 +102,7 @@ return view.extend({
if (force_app_status) { if (force_app_status) {
svcinfo = force_app_status; svcinfo = force_app_status;
} else { } else {
svcinfo = tools.decode_svc_info(svc_en, data.svc_info, data.proc_list, cfg); svcinfo = tools.decode_svc_info(svc_en, svc_info, proc_list, cfg);
} }
let btn = this.get_svc_buttons(elems); let btn = this.get_svc_buttons(elems);
btn.reset.disabled = false; btn.reset.disabled = false;
@@ -126,66 +127,104 @@ return view.extend({
} }
let elem_status = elems.status || document.getElementById("status"); let elem_status = elems.status || document.getElementById("status");
elem_status.innerHTML = tools.makeStatusString(svcinfo, this.pkg_arch, ''); elem_status.innerHTML = tools.makeStatusString(svcinfo, this.pkg_arch, '');
this.POLL.running = false;
if (!poll.active()) {
poll.start();
}
}, },
serviceActionEx: async function(action, button, args = [ ], hide_modal = false) serviceAction: function(action, button) {
{ if (button) {
let btn = document.getElementById(button); let elem = document.getElementById(button);
if (btn?.create_args) { this.disableButtons(true, elem);
args = btn.create_args();
console.log('serviceActionEx: btn.args = '+JSON.stringify(args));
} }
if (action == 'reset') { poll.stop();
hide_modal = true;
} let _this = this;
await this.POLL.stopAndWait();
this.disableButtons(true, btn); return tools.handleServiceAction(tools.appName, action)
//console.log('serviceActionEx: poll.running = '+this.POLL.running); .then(() => {
try { return _this.getAppStatus().then(
if (action == 'start' || action == 'restart') { (status_array) => {
let apply_exec = tools.checkUnsavedChanges(); _this.setAppStatus(status_array);
if (apply_exec) {
ui.changes.apply(true); // apply_rollback
await new Promise(resolve => setTimeout(resolve, 1000));
tools.setDefferedAction(action, null, true);
return;
} }
);
})
.catch(e => {
ui.addNotification(null, E('p', _('Unable to run service action.') + ' Error: ' + e.message));
});
},
serviceActionEx: function(action, button, args = [ ], hide_modal = false) {
if (button) {
let elem = document.getElementById(button);
this.disableButtons(true, elem);
}
poll.stop();
let _this = this;
let exec_cmd = null;
let exec_arg = [ ];
let errmsg = 'ERROR:';
if (action == 'start' || action == 'restart') {
exec_cmd = tools.syncCfgPath;
errmsg = _('Unable to run sync_config.sh script.');
}
else if (action == 'reset') {
exec_cmd = tools.defaultCfgPath;
exec_arg = args; // (reset_ipset)(sync) ==> restore all configs + sync config
errmsg = _('Unable to run restore-def-cfg.sh script.');
action = null;
} else {
ui.addNotification(null, E('p', 'ERROR: unknown action'));
return null;
}
return fs.exec(exec_cmd, exec_arg)
.then(function(res) {
if (res.code != 0) {
ui.addNotification(null, E('p', errmsg + ' res.code = ' + res.code));
action = null; // return with error
} }
await tools.serviceActionEx(action, args, false);
if (hide_modal) { if (hide_modal) {
ui.hideModal(); ui.hideModal();
} }
} catch(e) { if (!action) {
//ui.addNotification(null, E('p', 'Error: ' + e.message)); return _this.getAppStatus().then(
(status_array) => {
_this.setAppStatus(status_array);
}
);
}
return _this.serviceAction(action, null);
})
.catch(e => {
ui.addNotification(null, E('p', errmsg + ' Error: ' + e.message));
});
},
appAction: function(action, button) {
if (button) {
let elem = document.getElementById(button);
this.disableButtons(true, elem);
} }
}, poll.stop();
return fs.exec_direct(tools.execPath, [ action ]).then(res => {
serviceActionExCallback: function(btn, result, error) return this.getAppStatus().then(
{ (status_array) => {
//console.log('serviceActionExCallback: poll.active = '+this.POLL.active); this.setAppStatus(status_array);
this.POLL.start(150); ui.hideModal();
}
);
});
}, },
createServiceHandlerFn: function(action, btn_name) statusPoll: function() {
{
let opt = { keepDisabled: true, callback: this.serviceActionExCallback };
return tools.createHandlerFnEx(this, 'serviceActionEx', opt, action, btn_name);
},
statusPoll: function()
{
this.getAppStatus().then( this.getAppStatus().then(
L.bind(this.setAppStatus, this) L.bind(this.setAppStatus, this)
); );
}, },
dialogResetCfg: function(ev) dialogResetCfg: function(ev) {
{
if (tools.checkUnsavedChanges()) {
ui.addNotification(null, E('p', _('You have unapplied changes')));
return;
}
ev.target.blur(); ev.target.blur();
let reset_base = E('label', [ let reset_base = E('label', [
@@ -203,26 +242,15 @@ return view.extend({
' ', _('Set AutoHostList mode') ' ', _('Set AutoHostList mode')
]); ]);
let erase_autohostlist = E('label', [
E('input', { type: 'checkbox', id: 'cfg_erase_autohostlist' }),
' ', _('Erase AutoHostList (ipset)')
]);
let enable_custom_d = E('label', [
E('input', { type: 'checkbox', id: 'cfg_enable_custom_d' }),
' ', _('Enable use custom.d scripts')
]);
let strat_list = [ ]; let strat_list = [ ];
strat_list.push( E('option', { value: 'strat__skip__' }, [ 'not change' ] ) ); strat_list.push( E('option', { value: 'strat__skip__' }, [ '-' ] ) );
for (let id = 0; id < this.nfqws_strat_list.length; id++) { for (let id = 0; id < this.nfqws_strat_list.length; id++) {
let strat = '' + this.nfqws_strat_list[id]; let strat = '' + this.nfqws_strat_list[id];
strat_list.push( E('option', { value: 'strat_' + id }, [ strat ] ) ); strat_list.push( E('option', { value: 'strat_' + id }, [ strat ] ) );
} }
let label_nfqws = (tools.appName == 'zapret2') ? _('NFQWS2_OPT strategy: ') : _('NFQWS_OPT strategy: ');
let nfqws_strat = E('label', [ let nfqws_strat = E('label', [
label_nfqws, _('NFQWS2_OPT strategy: '),
E('select', { id: 'cfg_nfqws_strat' }, strat_list) E('select', { id: 'cfg_nfqws2_strat' }, strat_list)
]); ]);
let cancel_button = E('button', { let cancel_button = E('button', {
@@ -231,11 +259,10 @@ return view.extend({
}, _('Cancel')); }, _('Cancel'));
let resetcfg_btn = E('button', { let resetcfg_btn = E('button', {
'id': 'resetcfg_btn',
'name': 'resetcfg_btn',
'class': btn_style_action, 'class': btn_style_action,
}, _('Reset settings')); }, _('Reset settings'));
resetcfg_btn.create_args = () => { resetcfg_btn.onclick = ui.createHandlerFn(this, () => {
//cancel_button.disabled = true;
let opt_flags = ''; let opt_flags = '';
if (document.getElementById('cfg_reset_base').checked == false) { if (document.getElementById('cfg_reset_base').checked == false) {
opt_flags += '(skip_base)'; opt_flags += '(skip_base)';
@@ -246,21 +273,14 @@ return view.extend({
if (document.getElementById('cfg_autohostlist').checked) { if (document.getElementById('cfg_autohostlist').checked) {
opt_flags += '(set_mode_autohostlist)'; opt_flags += '(set_mode_autohostlist)';
}; };
if (document.getElementById('cfg_erase_autohostlist').checked) { //console.log('RESET: opt_flags = ' + opt_flags);
opt_flags += '(erase_autohostlist)'; let sel_strat = document.getElementById('cfg_nfqws2_strat');
};
if (document.getElementById('cfg_enable_custom_d').checked) {
opt_flags += '(enable_custom_d)';
};
let sel_strat = document.getElementById('cfg_nfqws_strat');
let opt_strat = sel_strat.options[sel_strat.selectedIndex].text; let opt_strat = sel_strat.options[sel_strat.selectedIndex].text;
if (opt_strat == 'not change') { //console.log('RESET: strat = ' + opt_strat);
opt_strat = '-';
}
opt_flags += '(sync)'; opt_flags += '(sync)';
return [ opt_flags, opt_strat ]; let args = [ opt_flags, opt_strat ];
}; return this.serviceActionEx('reset', resetcfg_btn, args, true);
resetcfg_btn.onclick = this.createServiceHandlerFn('reset', 'resetcfg_btn'); });
ui.showModal(_('Reset settings to default'), [ ui.showModal(_('Reset settings to default'), [
E('div', { 'class': 'cbi-section' }, [ E('div', { 'class': 'cbi-section' }, [
@@ -270,10 +290,6 @@ return view.extend({
E('br'), E('br'), E('br'), E('br'),
set_autohostlist, set_autohostlist,
E('br'), E('br'), E('br'), E('br'),
erase_autohostlist,
E('br'), E('br'),
enable_custom_d,
E('br'), E('br'),
nfqws_strat, nfqws_strat,
E('br'), E('br') E('br'), E('br')
]), ]),
@@ -285,25 +301,24 @@ return view.extend({
]); ]);
}, },
load: function() load: function() {
{ var _this = this;
return tools.baseLoad(this, (data) => { return Promise.all([
//console.log('SYS FEATURES: '+JSON.stringify(data.sys_feat)); L.resolveDefault(fs.stat('/bin/cat'), null),
tools.load_feat_env(); ]).then(function(data) {
return this.getAppStatus(); return _this.getAppStatus();
}); });
}, },
render: function(data) render: function(status_array) {
{ if (!status_array) {
if (!data) {
return; return;
} }
let cfg = uci.get(tools.appName, 'config'); let cfg = uci.get(tools.appName, 'config');
let pkgdict = data.pkg_dict; let pkg_list = status_array[4];
if (pkgdict == null) { if (pkg_list === undefined || typeof(pkg_list) !== 'object' || pkg_list.code != 0) {
ui.addNotification(null, E('p', _('Unable to enumerate installed packages') + ': render()')); ui.addNotification(null, E('p', _('Unable to enumerate installed packages') + ': setAppStatus()'));
return; return;
} }
@@ -349,27 +364,23 @@ return view.extend({
}; };
let btn_enable = create_btn('btn_enable', btn_style_success, _('Enable')); let btn_enable = create_btn('btn_enable', btn_style_success, _('Enable'));
btn_enable.onclick = this.createServiceHandlerFn('enable', 'btn_enable'); btn_enable.onclick = ui.createHandlerFn(this, this.serviceAction, 'enable', 'btn_enable');
let btn_disable = create_btn('btn_disable', btn_style_warning, _('Disable')); let btn_disable = create_btn('btn_disable', btn_style_warning, _('Disable'));
btn_disable.onclick = this.createServiceHandlerFn('disable', 'btn_disable'); btn_disable.onclick = ui.createHandlerFn(this, this.serviceAction, 'disable', 'btn_disable');
layout_append(_('Service autorun control'), null, [ btn_enable, btn_disable ] ); layout_append(_('Service autorun control'), null, [ btn_enable, btn_disable ] );
let btn_start = create_btn('btn_start', btn_style_action, _('Start')); let btn_start = create_btn('btn_start', btn_style_action, _('Start'));
btn_start.onclick = this.createServiceHandlerFn('start', 'btn_start'); btn_start.onclick = ui.createHandlerFn(this, this.serviceActionEx, 'start', 'btn_start');
let btn_restart = create_btn('btn_restart', btn_style_action, _('Restart')); let btn_restart = create_btn('btn_restart', btn_style_action, _('Restart'));
btn_restart.onclick = this.createServiceHandlerFn('restart', 'btn_restart'); btn_restart.onclick = ui.createHandlerFn(this, this.serviceActionEx, 'restart', 'btn_restart');
let btn_stop = create_btn('btn_stop', btn_style_warning, _('Stop')); let btn_stop = create_btn('btn_stop', btn_style_warning, _('Stop'));
btn_stop.onclick = this.createServiceHandlerFn('stop', 'btn_stop'); btn_stop.onclick = ui.createHandlerFn(this, this.serviceAction, 'stop', 'btn_stop');
layout_append(_('Service daemons control'), null, [ btn_start, btn_restart, btn_stop ] ); layout_append(_('Service daemons control'), null, [ btn_start, btn_restart, btn_stop ] );
let btn_reset = create_btn('btn_reset', btn_style_action, _('Reset settings')); let btn_reset = create_btn('btn_reset', btn_style_action, _('Reset settings'));
btn_reset.onclick = L.bind(this.dialogResetCfg, this); btn_reset.onclick = L.bind(this.dialogResetCfg, this);
layout_append(_('Reset settings to default'), null, [ btn_reset ] ); layout_append(_('Reset settings to default'), null, [ btn_reset ] );
let btn_diag = create_btn('btn_diag', btn_style_action, _('Diagnostics'));
btn_diag.onclick = ui.createHandlerFn(this, () => { diagnost.openDiagnostDialog(this.pkg_arch) });
layout_append('Diagnostic tools', null, [ btn_diag ] );
let btn_update = create_btn('btn_update', btn_style_action, _('Update')); let btn_update = create_btn('btn_update', btn_style_action, _('Update'));
btn_update.onclick = ui.createHandlerFn(this, () => { updater.openUpdateDialog(this.pkg_arch) }); btn_update.onclick = ui.createHandlerFn(this, () => { updater.openUpdateDialog(this.pkg_arch) });
layout_append(_('Update package'), null, [ btn_update ] ); layout_append(_('Update package'), null, [ btn_update ] );
@@ -382,32 +393,29 @@ return view.extend({
"btn_restart": btn_restart, "btn_restart": btn_restart,
"btn_stop": btn_stop, "btn_stop": btn_stop,
"btn_reset": btn_reset, "btn_reset": btn_reset,
"btn_diag": btn_diag,
"btn_update": btn_update, "btn_update": btn_update,
}; };
this.setAppStatus(data, elems); this.setAppStatus(status_array, elems);
this.POLL.mode = 1; poll.add(L.bind(this.statusPoll, this));
this.POLL.init( L.bind(this.statusPoll, this), 2000 ); // interval 2 sec
this.POLL.start(500); // first step after 500 ms
let page_title = tools.AppName; let page_title = _('Zapret2');
let pkgdict = tools.decode_pkg_list(pkg_list.stdout, false);
page_title += ' &nbsp '; page_title += ' &nbsp ';
if (pkgdict[tools.appName] === undefined || pkgdict[tools.appName] == '') { if (pkgdict['zapret2'] === undefined || pkgdict['zapret2'] == '') {
page_title += 'unknown version'; page_title += 'unknown version';
} else { } else {
page_title += 'v' + pkgdict[tools.appName]; page_title += 'v' + pkgdict['zapret2'];
page_title = page_title.replace(/-r1$/, '');
} }
let aux1 = E('em'); let aux1 = E('em');
let aux2 = E('em'); let aux2 = E('em');
if (pkgdict[tools.appName] != pkgdict['luci-app-'+tools.appName]) { if (pkgdict['zapret2'] != pkgdict['luci-app-zapret2']) {
let errtxt = 'LuCI APP v' + pkgdict['luci-app-'+tools.appName] + ' [ incorrect version! ]'; let errtxt = 'LuCI APP v' + pkgdict['luci-app-zapret2'] + ' [ incorrect version! ]';
aux1 = E('div', { 'class': 'label-status error' }, errtxt); aux1 = E('div', { 'class': 'label-status error' }, errtxt);
aux2 = E('div', { }, '&nbsp'); aux2 = E('div', { }, '&nbsp');
} }
let url1 = 'https://github.com/bol-van/'+tools.appName; let url1 = 'https://github.com/bol-van/zapret2';
let url2 = 'https://github.com/remittor/zapret-openwrt'; let url2 = 'https://github.com/remittor/zapret-openwrt';
return E([ return E([

View File

@@ -5,36 +5,50 @@
'require uci'; 'require uci';
'require ui'; 'require ui';
'require view'; 'require view';
'require view.zapret.tools as tools'; 'require view.zapret2.tools as tools';
document.head.appendChild(E('link', {
rel: 'stylesheet',
href: L.resource('view/zapret/styles.css')
}));
return view.extend({ return view.extend({
svc_info: null, parsers: { },
load: function() appStatusCode: null,
{
return tools.baseLoad(this, (data) => { depends: function(elem, key, array, empty=true) {
//console.log('SYS FEATURES: '+JSON.stringify(data.sys_feat)); if (empty && array.length === 0) {
tools.load_feat_env(); elem.depends(key, '_dummy');
return data; } else {
array.forEach(e => elem.depends(key, e));
}
},
validateIpPort: function(section, value) {
return (/^$|^([0-9]{1,3}\.){3}[0-9]{1,3}(#[\d]{2,5})?$/.test(value)) ? true : _('Expecting:')
+ ` ${_('One of the following:')}\n - ${_('valid IP address')}\n - ${_('valid address#port')}\n`;
},
validateUrl: function(section, value) {
return (/^$|^https?:\/\/[\w.-]+(:[0-9]{2,5})?[\w\/~.&?+=-]*$/.test(value)) ? true : _('Expecting:')
+ ` ${_('valid URL')}\n`;
},
load: function() {
return Promise.all([
{ code: -1}, // L.resolveDefault(fs.exec(tools.execPath, [ 'raw-status' ]), 1),
null, // L.resolveDefault(fs.list(tools.parsersDir), null),
uci.load(tools.appName),
]).catch(e => {
ui.addNotification(null, E('p', _('Unable to read the contents') + ': %s '.format(e.message) ));
}); });
}, },
render: function(data) render: function(data) {
{
if (!data) { if (!data) {
return; return;
} }
this.svc_info = data.svc_info; this.appStatusCode = data[0].code;
tools.execDefferedAction(this.svc_info);
let m, s, o, tabname; let m, s, o, tabname;
m = new form.Map(tools.appName, tools.AppName + ' - ' + _('Settings')); m = new form.Map(tools.appName, _('Zapret2') + ' - ' + _('Settings'));
s = m.section(form.NamedSection, 'config'); s = m.section(form.NamedSection, 'config');
s.anonymous = true; s.anonymous = true;
@@ -90,51 +104,10 @@ return view.extend({
o.rmempty = false; o.rmempty = false;
o.default = 0; o.default = 0;
let current_size = uci.get(tools.appName, 'config', 'DAEMON_LOG_SIZE_MAX') || '0';
let has_valid_value = false;
let size_list = [ 500, 1000, 1500, 2000, 2500, 3000, 4000, 5000, 7000 ];
if (current_size && current_size != '0') {
try {
current_size = parseInt(current_size, 10);
if (!isNaN(current_size) && current_size > 0) {
has_valid_value = true;
if (!size_list.includes(current_size)) {
size_list.push(current_size);
size_list.sort((a, b) => a - b);
}
}
} catch(e) {
has_valid_value = false;
}
}
o = s.taboption(tabname, form.ListValue, 'DAEMON_LOG_SIZE_MAX', _('DAEMON_LOG_SIZE_MAX'));
o.rmempty = false;
if (!has_valid_value) {
o.value('', '');
o.default = '';
}
for (let idx = 0; idx < size_list.length; idx++) {
let fsize = size_list[idx];
o.value('' + fsize, fsize + ' KB');
if (has_valid_value && fsize === current_size) {
o.default = '' + fsize;
}
}
o.validate = function(section_id, value) {
if (!value || value === '') {
return _('Please select maximum log size');
}
return true;
};
/* NFQWS_OPT_DESYNC tab */ /* NFQWS_OPT_DESYNC tab */
tabname = 'nfqws_params'; tabname = 'nfqws2_params';
if (tools.appName == 'zapret2') { s.tab(tabname, _('NFQWS2 options'));
s.tab(tabname, _('NFQWS2 options'));
} else {
s.tab(tabname, _('NFQWS options'));
}
let add_delim = function(sec, url = null) { let add_delim = function(sec, url = null) {
let o = sec.taboption(tabname, form.DummyValue, '_hr'); let o = sec.taboption(tabname, form.DummyValue, '_hr');
@@ -151,10 +124,8 @@ return view.extend({
let btn = sec.taboption(tabname, form.Button, '_' + param + '_btn', locname); let btn = sec.taboption(tabname, form.Button, '_' + param + '_btn', locname);
btn.inputtitle = _('Edit'); btn.inputtitle = _('Edit');
btn.inputstyle = 'edit btn'; btn.inputstyle = 'edit btn';
let val = sec.taboption(tabname, form.TextValue, '_' + param); let val = sec.taboption(tabname, form.DummyValue, '_' + param);
val.readonly = true; val.rawhtml = multiline ? true : false;
val.rows = rows + 5;
val.wrap = false;
val.cfgvalue = function(section_id) { val.cfgvalue = function(section_id) {
let value = uci.get(tools.appName, section_id, param); let value = uci.get(tools.appName, section_id, param);
if (value == null) { if (value == null) {
@@ -166,30 +137,24 @@ return view.extend({
value = value.replace(/\n --/g, "\n--"); value = value.replace(/\n --/g, "\n--");
value = value.replace(/ --/g, "\n--"); value = value.replace(/ --/g, "\n--");
} }
if (val.rawhtml) {
value = value.replace(/</g, '˂');
value = value.replace(/>/g, '˃');
value = value.replace(/\n/g, '<br/>');
}
return value; return value;
}; };
val.validate = function(section_id, value) { val.validate = function(section_id, value) {
return true; return (value) ? value.trim() : "";
}; };
let desc = locname; let desc = locname;
if (multiline == 2) { if (multiline == 2) {
desc += '<br/>' + _('Example') + ': <a target=_blank href=%s>%s</a>'.format(tools.nfqws_opt_url); desc += '<br/>' + _('Example') + ': <a target=_blank href=%s>%s</a>'.format(tools.nfqws_opt_url);
} }
btn.onclick = () => new tools.longstrEditDialog({ btn.onclick = () => new tools.longstrEditDialog('config', param, param, desc, rows, multiline).show();
cfgsec: 'config',
cfgparam: param,
title: param,
desc: desc,
rows: rows,
multiline: multiline,
}).show();
}; };
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Flag, 'NFQWS2_ENABLE', _('NFQWS2_ENABLE'));
o = s.taboption(tabname, form.Flag, 'NFQWS2_ENABLE', _('NFQWS2_ENABLE'));
} else {
o = s.taboption(tabname, form.Flag, 'NFQWS_ENABLE', _('NFQWS_ENABLE'));
}
o.rmempty = false; o.rmempty = false;
o.default = 1; o.default = 1;
@@ -208,77 +173,41 @@ return view.extend({
o.validate = function(section_id, value) { return true; }; o.validate = function(section_id, value) { return true; };
o.write = function(section_id, value) { return form.Value.prototype.write.call(this, section_id, (value == null || value.trim() == '') ? "\t" : value.trim()); }; o.write = function(section_id, value) { return form.Value.prototype.write.call(this, section_id, (value == null || value.trim() == '') ? "\t" : value.trim()); };
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'NFQWS2_PORTS_TCP', _('NFQWS2_PORTS_TCP'));
o = s.taboption(tabname, form.Value, 'NFQWS2_PORTS_TCP', _('NFQWS2_PORTS_TCP'));
} else {
o = s.taboption(tabname, form.Value, 'NFQWS_PORTS_TCP', _('NFQWS_PORTS_TCP'));
}
o.rmempty = false; o.rmempty = false;
o.datatype = 'string'; o.datatype = 'string';
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'NFQWS2_PORTS_UDP', _('NFQWS2_PORTS_UDP'));
o = s.taboption(tabname, form.Value, 'NFQWS2_PORTS_UDP', _('NFQWS2_PORTS_UDP'));
} else {
o = s.taboption(tabname, form.Value, 'NFQWS_PORTS_UDP', _('NFQWS_PORTS_UDP'));
}
o.rmempty = false; o.rmempty = false;
o.datatype = 'string'; o.datatype = 'string';
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'NFQWS2_TCP_PKT_OUT', _('NFQWS2_TCP_PKT_OUT'));
o = s.taboption(tabname, form.Value, 'NFQWS2_TCP_PKT_OUT', _('NFQWS2_TCP_PKT_OUT'));
} else {
o = s.taboption(tabname, form.Value, 'NFQWS_TCP_PKT_OUT', _('NFQWS_TCP_PKT_OUT'));
}
o.rmempty = false; o.rmempty = false;
o.datatype = 'string'; o.datatype = 'string';
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'NFQWS2_TCP_PKT_IN', _('NFQWS2_TCP_PKT_IN'));
o = s.taboption(tabname, form.Value, 'NFQWS2_TCP_PKT_IN', _('NFQWS2_TCP_PKT_IN'));
} else {
o = s.taboption(tabname, form.Value, 'NFQWS_TCP_PKT_IN', _('NFQWS_TCP_PKT_IN'));
}
o.rmempty = false; o.rmempty = false;
o.datatype = 'string'; o.datatype = 'string';
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'NFQWS2_UDP_PKT_OUT', _('NFQWS2_UDP_PKT_OUT'));
o = s.taboption(tabname, form.Value, 'NFQWS2_UDP_PKT_OUT', _('NFQWS2_UDP_PKT_OUT'));
} else {
o = s.taboption(tabname, form.Value, 'NFQWS_UDP_PKT_OUT', _('NFQWS_UDP_PKT_OUT'));
}
o.rmempty = false; o.rmempty = false;
o.datatype = 'string'; o.datatype = 'string';
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'NFQWS2_UDP_PKT_IN', _('NFQWS2_UDP_PKT_IN'));
o = s.taboption(tabname, form.Value, 'NFQWS2_UDP_PKT_IN', _('NFQWS2_UDP_PKT_IN'));
} else {
o = s.taboption(tabname, form.Value, 'NFQWS_UDP_PKT_IN', _('NFQWS_UDP_PKT_IN'));
}
o.rmempty = false; o.rmempty = false;
o.datatype = 'string'; o.datatype = 'string';
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'NFQWS2_PORTS_TCP_KEEPALIVE', _('NFQWS2_PORTS_TCP_KEEPALIVE'));
o = s.taboption(tabname, form.Value, 'NFQWS2_PORTS_TCP_KEEPALIVE', _('NFQWS2_PORTS_TCP_KEEPALIVE'));
} else {
o = s.taboption(tabname, form.Value, 'NFQWS_PORTS_TCP_KEEPALIVE', _('NFQWS_PORTS_TCP_KEEPALIVE'));
}
o.rmempty = false; o.rmempty = false;
o.datatype = 'uinteger'; o.datatype = 'uinteger';
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'NFQWS_PORTS_UDP_KEEPALIVE', _('NFQWS_PORTS_UDP_KEEPALIVE'));
o = s.taboption(tabname, form.Value, 'NFQWS2_PORTS_UDP_KEEPALIVE', _('NFQWS2_PORTS_UDP_KEEPALIVE'));
} else {
o = s.taboption(tabname, form.Value, 'NFQWS_PORTS_UDP_KEEPALIVE', _('NFQWS_PORTS_UDP_KEEPALIVE'));
}
o.rmempty = false; o.rmempty = false;
o.datatype = 'uinteger'; o.datatype = 'uinteger';
add_delim(s, tools.nfqws_opt_url); add_delim(s, tools.nfqws_opt_url);
if (tools.appName == 'zapret2') { add_param(s, 'NFQWS2_OPT', null, 21, 2);
add_param(s, 'NFQWS2_OPT', null, 21, 2);
} else {
add_param(s, 'NFQWS_OPT', null, 21, 2);
}
/* AutoHostList settings */ /* AutoHostList settings */
tabname = 'autohostlist_tab'; tabname = 'autohostlist_tab';
@@ -298,19 +227,13 @@ return view.extend({
return uci.set(tools.appName, section_id, 'MODE_FILTER', value === '1' ? 'autohostlist' : 'hostlist'); return uci.set(tools.appName, section_id, 'MODE_FILTER', value === '1' ? 'autohostlist' : 'hostlist');
}; };
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_INCOMING_MAXSEQ', _('INCOMING_MAXSEQ'));
o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_INCOMING_MAXSEQ', _('INCOMING_MAXSEQ')); o.rmempty = false;
o.rmempty = false; o.datatype = 'uinteger';
o.datatype = 'uinteger';
o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_RETRANS_MAXSEQ', _('RETRANS_MAXSEQ')); o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_RETRANS_MAXSEQ', _('RETRANS_MAXSEQ'));
o.rmempty = false; o.rmempty = false;
o.datatype = 'uinteger'; o.datatype = 'uinteger';
o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_RETRANS_RESET', _('RETRANS_RESET'));
o.rmempty = false;
o.datatype = 'uinteger';
}
o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_RETRANS_THRESHOLD', _('RETRANS_THRESHOLD')); o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_RETRANS_THRESHOLD', _('RETRANS_THRESHOLD'));
o.rmempty = false; o.rmempty = false;
@@ -324,26 +247,25 @@ return view.extend({
o.rmempty = false; o.rmempty = false;
o.datatype = 'uinteger'; o.datatype = 'uinteger';
if (tools.appName == 'zapret2') { o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_UDP_IN', _('UDP_IN'));
o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_UDP_IN', _('UDP_IN')); o.rmempty = false;
o.rmempty = false; o.datatype = 'uinteger';
o.datatype = 'uinteger';
o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_UDP_OUT', _('UDP_OUT')); o = s.taboption(tabname, form.Value, 'AUTOHOSTLIST_UDP_OUT', _('UDP_OUT'));
o.rmempty = false; o.rmempty = false;
o.datatype = 'uinteger'; o.datatype = 'uinteger';
}
o = s.taboption(tabname, form.Button, '_auto_host_btn', _('Auto host list entries')); o = s.taboption(tabname, form.Button, '_auto_host_btn', _('Auto host list entries'));
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = tools.autoHostListFN; o.description = tools.autoHostListFN;
o.onclick = () => new tools.fileEditDialog({ o.onclick = () => new tools.fileEditDialog(
file: tools.autoHostListFN, tools.autoHostListFN,
title: _('Auto host list'), _('Auto host list'),
desc: '', '',
rows: 15, '',
}).show(); 15
).show();
o = s.taboption(tabname, form.Flag, 'AUTOHOSTLIST_DEBUGLOG', _('DEBUGLOG')); o = s.taboption(tabname, form.Flag, 'AUTOHOSTLIST_DEBUGLOG', _('DEBUGLOG'));
o.rmempty = false; o.rmempty = false;
@@ -353,12 +275,13 @@ return view.extend({
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = tools.autoHostListDbgFN; o.description = tools.autoHostListDbgFN;
o.onclick = () => new tools.fileEditDialog({ o.onclick = () => new tools.fileEditDialog(
file: tools.autoHostListDbgFN, tools.autoHostListDbgFN,
title: _('Auto host debug list'), _('Auto host debug list'),
desc: '', '',
rows: 15, '',
}).show(); 15
).show();
/* HostList settings */ /* HostList settings */
@@ -369,37 +292,37 @@ return view.extend({
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = tools.hostsGoogleFN; o.description = tools.hostsGoogleFN;
o.onclick = () => new tools.fileEditDialog({ o.onclick = () => new tools.fileEditDialog(
file: tools.hostsGoogleFN, tools.hostsGoogleFN,
title: _('Google hostname entries'), _('Google hostname entries'),
desc: _('One hostname per line.<br />Examples:'), _('One hostname per line.<br />Examples:'),
aux: '<code>youtube.com<br />googlevideo.com</code>', '<code>youtube.com<br />googlevideo.com</code>',
rows: 15, 15
}).show(); ).show();
o = s.taboption(tabname, form.Button, '_user_entries_btn', _('User hostname entries <HOSTLIST>')); o = s.taboption(tabname, form.Button, '_user_entries_btn', _('User hostname entries <HOSTLIST>'));
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = tools.hostsUserFN; o.description = tools.hostsUserFN;
o.onclick = () => new tools.fileEditDialog({ o.onclick = () => new tools.fileEditDialog(
file: tools.hostsUserFN, tools.hostsUserFN,
title: _('User entries'), _('User entries'),
desc: _('One hostname per line.<br />Examples:'), _('One hostname per line.<br />Examples:'),
aux: '<code>domain.net<br />sub.domain.com<br />facebook.com</code>', '<code>domain.net<br />sub.domain.com<br />facebook.com</code>',
rows: 15, 15
}).show(); ).show();
o = s.taboption(tabname, form.Button, '_user_excluded_entries_btn', _('User excluded hostname entries')); o = s.taboption(tabname, form.Button, '_user_excluded_entries_btn', _('User excluded hostname entries'));
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = tools.hostsUserExcludeFN; o.description = tools.hostsUserExcludeFN;
o.onclick = () => new tools.fileEditDialog({ o.onclick = () => new tools.fileEditDialog(
file: tools.hostsUserExcludeFN, tools.hostsUserExcludeFN,
title: _('User excluded entries'), _('User excluded entries'),
desc: _('One hostname per line.<br />Examples:'), _('One hostname per line.<br />Examples:'),
aux: '<code>domain.net<br />sub.domain.com<br />gosuslugi.ru</code>', '<code>domain.net<br />sub.domain.com<br />gosuslugi.ru</code>',
rows: 15, 15
}).show(); ).show();
add_delim(s); add_delim(s);
@@ -407,37 +330,37 @@ return view.extend({
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = tools.iplstExcludeFN; o.description = tools.iplstExcludeFN;
o.onclick = () => new tools.fileEditDialog({ o.onclick = () => new tools.fileEditDialog(
file: tools.iplstExcludeFN, tools.iplstExcludeFN,
title: _('Excluded IP filter'), _('Excluded IP filter'),
desc: _('Patterns can be strings or regular expressions. Each pattern in a separate line<br />Examples:'), _('Patterns can be strings or regular expressions. Each pattern in a separate line<br />Examples:'),
aux: '<code>128.199.0.0/16<br />34.217.90.52<br />162.13.190.77</code>', '<code>128.199.0.0/16<br />34.217.90.52<br />162.13.190.77</code>',
rows: 15, 15
}).show(); ).show();
o = s.taboption(tabname, form.Button, '_user_ip_filter_btn', _('User IP entries')); o = s.taboption(tabname, form.Button, '_user_ip_filter_btn', _('User IP entries'));
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = tools.iplstUserFN; o.description = tools.iplstUserFN;
o.onclick = () => new tools.fileEditDialog({ o.onclick = () => new tools.fileEditDialog(
file: tools.iplstUserFN, tools.iplstUserFN,
title: _('User IP filter'), _('User IP filter'),
desc: _('Patterns can be strings or regular expressions. Each pattern in a separate line<br />Examples:'), _('Patterns can be strings or regular expressions. Each pattern in a separate line<br />Examples:'),
aux: '<code>128.199.0.0/16<br />34.217.90.52<br />162.13.190.77</code>', '<code>128.199.0.0/16<br />34.217.90.52<br />162.13.190.77</code>',
rows: 15, 15
}).show(); ).show();
o = s.taboption(tabname, form.Button, '_user_excluded_ip_filter_btn', _('User excluded IP entries')); o = s.taboption(tabname, form.Button, '_user_excluded_ip_filter_btn', _('User excluded IP entries'));
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = tools.iplstUserExcludeFN; o.description = tools.iplstUserExcludeFN;
o.onclick = () => new tools.fileEditDialog({ o.onclick = () => new tools.fileEditDialog(
file: tools.iplstUserExcludeFN, tools.iplstUserExcludeFN,
title: _('User excluded IP filter'), _('User excluded IP filter'),
desc: _('Patterns can be strings or regular expressions. Each pattern in a separate line<br />Examples:'), _('Patterns can be strings or regular expressions. Each pattern in a separate line<br />Examples:'),
aux: '<code>128.199.0.0/16<br />34.217.90.52<br />162.13.190.77</code>', '<code>128.199.0.0/16<br />34.217.90.52<br />162.13.190.77</code>',
rows: 15, 15
}).show(); ).show();
add_delim(s); add_delim(s);
@@ -448,7 +371,7 @@ return view.extend({
o.inputtitle = _('Edit'); o.inputtitle = _('Edit');
o.inputstyle = 'edit btn'; o.inputstyle = 'edit btn';
o.description = fn; o.description = fn;
o.onclick = () => new tools.fileEditDialog({ file: fn, title: name, rows: 15}).show(); o.onclick = () => new tools.fileEditDialog(fn, name, '', '', 15).show();
} }
/* custom.d files */ /* custom.d files */
@@ -490,7 +413,7 @@ return view.extend({
desc += '<a target=_blank href=' + url + '>' + filename + '</a>'; desc += '<a target=_blank href=' + url + '>' + filename + '</a>';
} }
} }
o.onclick = () => new tools.fileEditDialog({ file: fn, title: name, desc: desc, rows: 15}).show(); o.onclick = () => new tools.fileEditDialog(fn, name, desc, '', 15).show();
} }
let map_promise = m.render(); let map_promise = m.render();
@@ -498,18 +421,12 @@ return view.extend({
return map_promise; return map_promise;
}, },
handleSaveApply: function(ev, mode) handleSaveApply: function(ev, mode) {
{
return this.handleSave(ev).then(() => { return this.handleSave(ev).then(() => {
let apply_exec = tools.checkUnsavedChanges(); ui.changes.apply(mode == '0');
if (apply_exec) { //if (this.appStatusCode != 1 && this.appStatusCode != 2) {
ui.changes.apply(mode == '0'); // window.setTimeout(() => fs.exec(tools.execPath, [ 'restart' ]), 3000);
tools.setDefferedAction('restart', this.svc_info); //}
} else {
if (this.svc_info?.dmn.inited) {
tools.serviceActionEx('restart');
}
}
}); });
}, },
}); });

View File

@@ -0,0 +1,601 @@
'use strict';
'require baseclass';
'require fs';
'require rpc';
'require ui';
'require uci';
document.head.append(E('style', {'type': 'text/css'},
`
.label-status {
display: inline;
margin: 0 2px 0 0 !important;
padding: 2px 4px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
font-weight: bold;
color: #fff !important;
}
.starting {
background-color: #9c994c !important;
}
.running {
background-color: #2ea256 !important;
}
.updating {
background-color: #1e82ff !important;
}
.stopped {
background-color: #8a8a8a !important;
}
.error {
background-color: #ff4e54 !important;
}
`));
return baseclass.extend({
packager : null,
appName : 'zapret2',
execPath : '/etc/init.d/zapret2',
syncCfgPath : '/opt/zapret2/sync_config.sh',
defCfgPath : '/opt/zapret2/def-cfg.sh',
defaultCfgPath : '/opt/zapret2/restore-def-cfg.sh',
hostsGoogleFN : '/opt/zapret2/ipset/zapret-hosts-google.txt',
hostsUserFN : '/opt/zapret2/ipset/zapret-hosts-user.txt',
hostsUserExcludeFN: '/opt/zapret2/ipset/zapret-hosts-user-exclude.txt',
iplstExcludeFN : '/opt/zapret2/ipset/zapret-ip-exclude.txt',
iplstUserFN : '/opt/zapret2/ipset/zapret-ip-user.txt',
iplstUserExcludeFN: '/opt/zapret2/ipset/zapret-ip-user-exclude.txt',
custFileMax : 4,
custFileTemplate : '/opt/zapret2/ipset/cust%s.txt',
customdPrefixList : [ 10, 20, 50, 60, 90 ] ,
customdFileFormat : '/opt/zapret2/init.d/openwrt/custom.d/%s-script.sh',
discord_num : 50,
discord_url : [ 'https://github.com/bol-van/zapret2/blob/master/init.d/custom.d.examples.linux/50-discord-media',
'https://github.com/bol-van/zapret2/blob/master/init.d/custom.d.examples.linux/50-stun4all',
'https://github.com/bol-van/zapret2/tree/master/init.d/custom.d.examples.linux'
],
nfqws_opt_url : 'https://github.com/remittor/zapret-openwrt/discussions/',
autoHostListFN : '/opt/zapret2/ipset/zapret-hosts-auto.txt',
autoHostListDbgFN : '/opt/zapret2/ipset/zapret-hosts-auto-debug.log',
infoLabelRunning : '<span class="label-status running">' + _('Running') + '</span>',
infoLabelStarting : '<span class="label-status starting">' + _('Starting') + '</span>',
infoLabelStopped : '<span class="label-status stopped">' + _('Stopped') + '</span>',
infoLabelDisabled : '<span class="label-status stopped">' + _('Disabled') + '</span>',
infoLabelError : '<span class="label-status error">' + _('Error') + '</span>',
infoLabelUpdating : '<span class="label-status updating">' + _('Updating') + '</span>',
statusDict: {
error : { code: 0, name: _('Error') , label: this.infoLabelError },
disabled : { code: 1, name: _('Disabled') , label: this.infoLabelDisabled },
stopped : { code: 2, name: _('Stopped') , label: this.infoLabelStopped },
starting : { code: 3, name: _('Starting') , label: this.infoLabelStarting },
running : { code: 4, name: _('Running') , label: this.infoLabelRunning },
},
callServiceList: rpc.declare({
object: 'service',
method: 'list',
params: [ 'name', 'verbose' ],
expect: { '': {} }
}),
callInitState: rpc.declare({
object: 'luci',
method: 'getInitList',
params: [ 'name' ],
expect: { '': {} }
}),
callInitAction: rpc.declare({
object: 'luci',
method: 'setInitAction',
params: [ 'name', 'action' ],
expect: { result: false }
}),
init_consts: function() {
if (!this.packager) {
this.packager = { };
if (L.hasSystemFeature('apk')) {
this.packager.name = 'apk';
this.packager.path = '/usr/bin/apk';
this.packager.args = [ 'list', '-I', '*zapret2*' ];
} else {
this.packager.name = 'opkg';
this.packager.path = '/bin/opkg';
this.packager.args = [ 'list-installed', '*zapret2*' ];
}
//console.log('PACKAGER: ' + this.packager.name);
}
},
getSvcInfo: function(svc_name = null) {
this.init_consts();
let name = (svc_name) ? svc_name : this.appName;
let verbose = 1;
return this.callServiceList(name, verbose).then(res => {
return res;
}).catch(e => {
ui.addNotification(null, E('p', _('Failed to get %s service info: %s').format(name, e)));
});
},
getInitState: function(name) {
this.init_consts();
return this.callInitState(name).then(res => {
if (res) {
return res[name].enabled ? true : false;
} else {
throw _('Command failed');
}
}).catch(e => {
ui.addNotification(null, E('p', _('Failed to get %s init status: %s').format(name, e)));
});
},
getStratList: function() {
this.init_consts();
let exec_cmd = '/bin/busybox';
let exec_arg = [ 'awk', '-F', '"', '/if \\[ "\\$strat" = "/ {print $4}', this.defCfgPath ];
return fs.exec(exec_cmd, exec_arg).then(res => {
if (res.code == 0) {
return this.getWordsArray(res.stdout);
}
return [ ];
}).catch(e => {
ui.addNotification(null, E('p', _('Failed to get strat list: %s').format(e)));
});
},
handleServiceAction: function(name, action) {
return this.callInitAction(name, action).then(success => {
if (!success) {
throw _('Command failed');
}
return true;
}).catch(e => {
ui.addNotification(null, E('p', _('Service action failed "%s %s": %s').format(name, action, e)));
});
},
normalizeValue: function(v) {
return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
},
getWordsArray: function (text, { trim = true, removeEmpty = true } = {}) {
const rawLines = text.split(/\n/);
const processed = trim ? rawLines.map(line => line.trim()) : rawLines.slice();
return removeEmpty ? processed.filter(line => line.length > 0) : processed;
},
getConfigPar: function(txt, key, defval = null) {
const re = new RegExp(`^${key}\\s*=\\s*(['"])(.*?)\\1`, 'm');
const m = txt.match(re);
return m ? m[2] : defval;
},
decode_pkg_list: function(pkg_list, with_suffix_r1 = true) {
let pkg_dict = { };
if (!pkg_list) {
return pkg_dict;
}
let lines = pkg_list.trim().split('\n');
for (let i = 0; i < lines.length; i++) {
let line = lines[i].trim();
let name;
let ver;
let rev = -1;
if (this.packager.name == 'apk') {
let fullname = line.split(' ')[0];
let match = fullname.match(/^(.*)-r(\d+)$/);
if (match) {
fullname = match[1];
rev = parseInt(match[2], 10);
}
let mpos = fullname.lastIndexOf('-');
if (mpos <= 0)
continue; // incorrect format
name = fullname.slice(0, mpos).trim();
ver = fullname.slice(mpos + 1).trim();
} else {
if (!line.includes(' - '))
continue; // incorrect format
name = line.split(' - ')[0].trim();
ver = line.split(' - ')[1].trim();
let spos = ver.indexOf(" ");
if (spos > 0) {
ver = ver.substring(0, spos);
}
let match = ver.match(/^(.*)-r(\d+)$/);
if (match) {
ver = match[1];
rev = parseInt(match[2], 10);
}
}
if (rev >= 0) {
if (rev == 1 && !with_suffix_r1) {
// nothing
} else {
ver += '-r' + rev;
}
}
pkg_dict[name] = ver;
}
return pkg_dict;
},
get_pid_list: function(proc_list) {
let plist = [ ];
let lines = proc_list.trim().split('\n');
for (let i = 0; i < lines.length; i++) {
let line = lines[i].trim();
if (line.length > 5) {
let word_list = line.split(/\s+/);
let pid = word_list[0];
let isnum = /^\d+$/.test(pid);
if (isnum) {
plist.push(parseInt(pid));
}
}
}
return plist;
},
decode_svc_info: function(svc_autorun, svc_info, proc_list, cfg) {
let result = {
"autorun": svc_autorun,
"dmn": {
inited: false,
total: 0,
running: 0,
working: 0,
},
"status": this.statusDict.error,
};
if (proc_list.code != 0) {
return -2;
}
let plist = this.get_pid_list(proc_list.stdout);
if (plist.length < 4) {
return -3;
}
if (typeof(svc_info) !== 'object') {
return -4;
}
let jdata = svc_info;
if (typeof(jdata.zapret2) == 'object') {
result.dmn.inited = true;
let dmn_list = jdata.zapret2.instances;
if (typeof(dmn_list) == 'object') {
for (const [dmn_name, daemon] of Object.entries(dmn_list)) {
result.dmn.total += 1;
if (daemon.running) {
result.dmn.running += 1;
}
if (daemon.pid !== undefined && daemon.pid != null) {
if (plist.includes(daemon.pid)) {
result.dmn.working += 1;
}
}
}
}
}
//console.log('SVC_DAEMONS: ' + result.dmn.working + ' / ' + result.dmn.total);
if (result.dmn.total == 0) {
result.status = (!svc_autorun) ? this.statusDict.disabled : this.statusDict.stopped;
} else {
result.status = (result.dmn.inited) ? this.statusDict.started : this.statusDict.running;
}
return result;
},
makeStatusString: function(svcinfo, pkg_arch, bllist_preset) {
let svc_autorun = _('Unknown');
let svc_daemons = _('Unknown');
if (typeof(svcinfo) == 'object') {
svc_autorun = (svcinfo.autorun) ? _('Enabled') : _('Disabled');
if (!svcinfo.dmn.inited) {
svc_daemons = _('Stopped');
} else {
svc_daemons = (!svcinfo.dmn.working) ? _('Starting') : _('Running');
svc_daemons += ' [' + svcinfo.dmn.working + '/' + svcinfo.dmn.total + ']';
}
}
let td_name_width = 40;
let td_name_style = `style="width: ${td_name_width}%; min-width:${td_name_width}%; max-width:${td_name_width}%;"`;
let out = `
<table class="table">
<tr class="tr">
<td class="td left" ${td_name_style}>
${_('CPU architecture')}:
</td>
<td class="td left">
${pkg_arch}
</td>
</tr>
<tr class="tr">
<td class="td left" ${td_name_style}>
${_('Service autorun status')}:
</td>
<td class="td left">
${svc_autorun}
</td>
</tr>
<tr class="tr">
<td class="td left" ${td_name_style}>
${_('Service daemons status')}:
</td>
<td class="td left %s">
${svc_daemons}
</td>
</tr>
<tr class="tr">
<td class="td left" ${td_name_style}>
</td>
<td class="td left">
</td>
</tr>
</table>`;
return out;
},
getLineCount: function(mstr) {
let count = 0;
let c = '\n'.charAt(0);
for (let i = 0; i < mstr.length; ++i) {
if (c === mstr.charAt(i)) {
++count;
}
}
return count;
},
fileEditDialog: baseclass.extend({
__init__: function(file, title, desc, aux = null, rows = 10, callback, file_exists = false) {
this.file = file;
this.title = title;
this.desc = desc;
this.aux = aux;
this.rows = rows,
this.callback = callback;
this.file_exists = file_exists;
},
load: function() {
return L.resolveDefault(fs.read(this.file), '');
},
render: function(content) {
let descr = this.desc;
if (this.aux)
descr += '<br />' + this.aux;
ui.showModal(this.title, [
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'cbi-section-descr' }, descr),
E('div', { 'class': 'cbi-section' },
E('p', {},
E('textarea', {
'id': 'widget.modal_content',
'class': 'cbi-input-textarea',
'style': 'width:100% !important',
'rows': this.rows,
'wrap': 'off',
'spellcheck': 'false',
},
content)
)
),
]),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': ui.hideModal,
}, _('Dismiss')),
' ',
E('button', {
'id': 'btn_save',
'class': 'btn cbi-button-positive important',
'click': ui.createHandlerFn(this, this.handleSave),
}, _('Save')),
]),
]);
},
handleSave: function(ev) {
let txt = document.getElementById('widget.modal_content');
let value = txt.value.trim().replace(/\r\n/g, '\n') + '\n';
return fs.write(this.file, value).then(async rc => {
txt.value = value;
ui.addNotification(null, E('p', _('Contents have been saved.')), 'info');
if (this.callback) {
return this.callback(rc);
}
}).catch(e => {
ui.addNotification(null, E('p', _('Unable to save the contents') + ': %s'.format(e.message)));
}).finally(() => {
ui.hideModal();
});
},
error: function(e) {
if (!this.file_exists && e instanceof Error && e.name === 'NotFoundError') {
return this.render();
} else {
ui.showModal(this.title, [
E('div', { 'class': 'cbi-section' },
E('p', {}, _('Unable to read the contents') + ': %s'.format(e.message))
),
E('div', { 'class': 'right' },
E('button', {
'class': 'btn',
'click': ui.hideModal,
}, _('Dismiss'))
),
]);
}
},
show: function() {
ui.showModal(null,
E('p', { 'class': 'spinning' }, _('Loading'))
);
this.load().then(content => {
ui.hideModal();
return this.render(content);
}).catch(e => {
ui.hideModal();
return this.error(e);
});
},
}),
longstrEditDialog: baseclass.extend({
__init__: function(cfgsec, cfgparam, title, desc, rows = 10, multiline = false) {
this.cfgsec = cfgsec;
this.cfgparam = cfgparam;
this.title = title;
this.desc = desc;
this.rows = rows;
this.multiline = multiline;
},
load: function() {
let value = uci.get('zapret2', this.cfgsec, this.cfgparam);
if (typeof(value) === 'string') {
value = value.trim();
if (this.multiline == 2) {
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n\t/g, "\n");
value = value.replace(/\n --/g, "\n--");
value = value.replace(/\n --/g, "\n--");
value = value.replace(/ --/g, "\n--");
}
}
return value;
},
render: function(content) {
ui.showModal(this.title, [
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'cbi-section-descr' }, this.desc),
E('div', { 'class': 'cbi-section' },
E('p', {},
E('textarea', {
'id': 'widget.modal_content',
'class': 'cbi-input-textarea',
'style': 'width:100% !important',
'rows': this.rows,
'wrap': 'on',
'spellcheck': 'false',
},
content)
)
),
]),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': ui.hideModal,
}, _('Dismiss')),
' ',
E('button', {
'id': 'btn_save',
'class': 'btn cbi-button-positive important',
'click': ui.createHandlerFn(this, this.handleSave),
}, _('Save')),
]),
]);
},
handleSave: function(ev) {
let txt = document.getElementById('widget.modal_content');
let value = txt.value.trim();
if (this.multiline) {
value = value.replace(/\r/g, '');
if (value != "" && value != "\t") {
value = '\n' + value + '\n';
if (this.multiline == 2) {
value = value.replace(/"/g, '');
value = value.replace(/'/g, '');
}
}
} else {
value = value.replace(/\r\n/g, ' ');
value = value.replace(/\r/g, ' ');
value = value.replace(/\n/g, ' ');
value = value.trim();
}
if (value == "") {
value = "\t";
}
value = value.replace(/˂/g, '<');
value = value.replace(/˃/g, '>');
uci.set('zapret2', this.cfgsec, this.cfgparam, value);
uci.save();
let elem = document.getElementById("cbi-zapret-" + this.cfgsec + "-_" + this.cfgparam);
if (elem) {
let val = value.trim();
if (this.multiline) {
val = val.replace(/</g, '˂');
val = val.replace(/>/g, '˃');
val = val.replace(/\n/g, '<br/>');
elem.querySelector('div').innerHTML = val;
} else {
elem.querySelector('div').textContent = val;
}
}
ui.hideModal();
/*
return uci.save()
.then(L.bind(ui.changes.init, ui.changes))
.then(L.bind(ui.changes.displayChanges, ui.changes))
//.then(L.bind(ui.changes.apply, ui.changes))
.then(ui.addNotification(null, E('p', _('Contents have been saved.')), 'info'))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save the contents') + ': %s'.format(e.message)));
}).finally(() => {
ui.hideModal();
});
*/
},
error: function(e) {
let msg = (typeof(e) == 'object') ? e.message : ''+e;
ui.showModal(this.title, [
E('div', { 'class': 'cbi-section' },
E('p', {}, _('Unable to read the contents') + ': %s'.format(msg))
),
E('div', { 'class': 'right' },
E('button', {
'class': 'btn',
'click': ui.hideModal,
}, _('Dismiss'))
),
]);
},
show: function() {
//ui.showModal(null, E('p', { 'class': 'spinning' }, _('Loading')) );
let content = this.load();
//ui.hideModal();
if (content === null) {
return this.error('Cannot load parameter');
}
return this.render(content);
},
}),
});

View File

@@ -0,0 +1,238 @@
'use strict';
'require baseclass';
'require fs';
'require poll';
'require uci';
'require ui';
'require view';
'require view.zapret2.tools as tools';
const btn_style_neutral = 'btn';
const btn_style_action = 'btn cbi-button-action';
const btn_style_positive = 'btn cbi-button-save important';
const btn_style_negative = 'btn cbi-button-reset important';
const btn_style_warning = 'btn cbi-button-negative';
const btn_style_success = 'btn cbi-button-success important';
const fn_update_pkg_sh = '/opt/zapret2/update-pkg.sh';
return baseclass.extend({
releasesUrlPrefix : 'https://raw.githubusercontent.com/remittor/zapret-openwrt/gh-pages/releases/',
appendLog: function(msg, end = '\n') {
this.logArea.value += msg + end;
this.logArea.scrollTop = this.logArea.scrollHeight;
},
setBtnMode: function(enable) {
this.btn_cancel.disabled = enable ? false : true;
this.btn_action.disabled = (enable == 2) ? false : true;
},
setStage: function(stage, btn_flag = true) {
if (stage == 0) {
this.btn_action.textContent = _('Check for updates');
this.btn_action.classList.remove('hidden');
} else
if (stage == 1) {
this.btn_action.textContent = _('Update packages');
this.btn_action.classList.remove('hidden');
} else {
this.btn_action.classList.add('hidden');
}
if (stage > 1 && typeof(this.btn_action) == 'object') {
this.setBtnMode(1);
}
this.stage = stage;
},
checkUpdates: function() {
this.setStage(0);
this.setBtnMode(0);
this.pkg_url = null;
this.appendLog(_('Checking for updates...'));
let opt_list = [ '-c' ]; // check for updates
if (document.getElementById('cfg_exclude_prereleases').checked == false) {
opt_list.push('-p'); // include prereleases ZIP-files
}
let forced_reinstall = document.getElementById('cfg_forced_reinstall').checked;
let rpc_opt = { timeout: 20*1000 }
//rpc_opt.uid = 0; // run under root
let res = fs.exec(fn_update_pkg_sh, opt_list, null, rpc_opt).then(res => {
let log = res.stdout.trim();
this.appendLog(log);
let code = log.match(/^RESULT:\s*\(([^)]+)\)\s+.+$/m);
let pkg_url = log.match(/^ZAP_PKG_URL\s*=\s*(.+)$/m);
if (res.code == 0 && code && pkg_url) {
this.pkg_url = pkg_url[1];
code = code[1];
if (code == 'E' && !forced_reinstall) {
this.setStage(999);
return 0;
}
this.setStage(1);
this.setBtnMode(2); // enable all buttons
} else {
if (res.code != 0) {
this.appendLog('ERROR: Check for updates failed with error ' + res.code);
}
this.setStage(999);
}
return res.code;
}).catch(e => {
this.appendLog('ERROR: ' + _('Updates checking failed'));
this.appendLog('ERROR: ' + e);
this.setStage(999);
return 1;
}).finally(() => {
this.appendLog('=========================================================');
});
},
installUpdates: async function() {
this.setStage(1);
this.setBtnMode(0);
if (!this.pkg_url || this.pkg_url.length < 10) {
this.appendLog('ERROR: pkg_url = null');
this.setStage(999);
return 1;
}
this.appendLog(_('Install updates...'));
let opt_list = [ '-u', this.pkg_url ]; // update packages
if (document.getElementById('cfg_forced_reinstall').checked == true) {
opt_list.push('-f'); // forced reinstall if same version
}
let rpc_opt = { timeout: 5*1000 }
//rpc_opt.uid = 0; // run under root
const logFile = '/tmp/zapret2_pkg_install.log';
const rcFile = logFile + '.rc';
try {
await fs.exec('/bin/busybox', [ 'rm', '-f', logFile + '*' ], null, rpc_opt);
this.appendLog('Install log cleared.');
} catch (e) {
this.appendLog('ERROR: Failed to clear log file');
this.setStage(999);
return 1;
}
try {
let opt = [ logFile, fn_update_pkg_sh ];
//opt.push('-t'); opt.push('0'); // only for testing
opt.push(...opt_list);
let res = await fs.exec('/opt/zapret2/script-exec.sh', opt, null, rpc_opt);
if (res.code == 0) {
this.appendLog('Process started...');
} else {
this.appendLog('ERROR: cannot run ' + fn_update_pkg_sh + ' script! (error = ' + res.code + ')');
throw new Error('cannot run script');
}
} catch (e) {
this.appendLog('ERROR: Failed to start process: ' + e.message);
this.setStage(999);
return 1;
}
let lastLen = 0;
let retCode = -1;
let timer = setInterval(async () => {
try {
let res = await fs.exec('/bin/cat', [ logFile ], null, rpc_opt);
if (res.stdout && res.stdout.length > lastLen) {
let log = res.stdout.slice(lastLen);
log = log.replace(/^ \* resolve_conffiles.*(?:\r?\n|$)/gm, '');
this.appendLog(log, '');
lastLen = res.stdout.length;
}
if (retCode < 0) {
let rc = await fs.exec('/bin/cat', [ rcFile ], null, rpc_opt);
if (rc.code != 0) {
throw new Error('cannot read file "' + rcFile + '"');
}
if (rc.stdout) {
retCode = parseInt(rc.stdout.trim(), 10);
}
}
if (retCode >= 0) {
clearInterval(timer);
this.appendLog('\n' + 'Process finished.');
if (res.stdout) {
let code = res.stdout.match(/^RESULT:\s*\(([^)]+)\)\s+.+$/m);
if (retCode == 0 && code && code[1] == '+') {
this.stage = 999;
this.btn_action.textContent = _('OK');
this.btn_action.disabled = false;
this.btn_cancel.disabled = true;
return 0;
}
}
this.appendLog('ERROR: Install updates failed with error ' + retCode);
this.setStage(999);
}
} catch (e) {
clearInterval(timer);
this.appendLog('ERROR: installUpdates: ' + e.message);
this.setStage(999);
}
}, 500);
},
openUpdateDialog: function(pkg_arch) {
this.stage = 0;
this.pkg_arch = pkg_arch;
this.pkg_url = null;
let exclude_prereleases = E('label', [
E('input', { type: 'checkbox', id: 'cfg_exclude_prereleases', checked: true }),
' ', _('Exclude PreReleases')
]);
let forced_reinstall = E('label', [
E('input', { type: 'checkbox', id: 'cfg_forced_reinstall'}),
' ', _('Forced reinstall packages')
]);
this.logArea = E('textarea', {
'readonly': true,
'style': 'width:100%; height:400px; font-family: monospace;'
});
this.btn_cancel = E('button', {
'id': 'btn_cancel',
'name': 'btn_cancel',
'class': btn_style_warning,
}, _('Cancel'));
this.btn_cancel.onclick = ui.hideModal;
this.btn_action = E('button', {
'id': 'btn_action',
'name': 'btn_action',
'class': btn_style_action,
}, 'BUTTON_ACTION');
this.btn_action.onclick = ui.createHandlerFn(this, () => {
if (this.stage == 0) {
return this.checkUpdates();
}
if (this.stage == 1) {
return this.installUpdates();
}
return ui.hideModal();
});
this.setStage(0);
this.setBtnMode(2);
ui.showModal(_('Package update'), [
E('div', { 'class': 'cbi-section' }, [
exclude_prereleases,
E('br'), E('br'),
forced_reinstall,
E('br'), E('br'),
E('hr'),
this.logArea,
]),
E('div', { 'class': 'right' }, [
this.btn_cancel,
' ',
this.btn_action,
])
]);
}
});

View File

@@ -1,46 +0,0 @@
{
"admin/services/zapret": {
"title": "Zapret",
"order": 61,
"action": {
"type": "alias",
"path": "admin/services/zapret/service"
},
"depends": {
"acl": [ "luci-app-zapret" ],
"fs": {
"/opt/zapret/sync_config.sh": "executable",
"/opt/zapret/restore-def-cfg.sh": "executable",
"/etc/init.d/zapret": "executable"
},
"uci": { "zapret": true }
}
},
"admin/services/zapret/service": {
"title": "Service",
"order": 10,
"action": {
"type": "view",
"path": "zapret/service"
}
},
"admin/services/zapret/settings": {
"title": "Settings",
"order": 20,
"action": {
"type": "view",
"path": "zapret/settings"
}
},
"admin/services/zapret/dmnlog": {
"title": "Log Viewer",
"order": 30,
"action": {
"type": "view",
"path": "zapret/dmnlog"
}
}
}

View File

@@ -0,0 +1,41 @@
{
"admin/services/zapret2": {
"title": "Zapret2",
"order": 62,
"action": {
"type": "alias",
"path": "admin/services/zapret2/service"
},
"depends": {
"acl": [ "luci-app-zapret2" ],
"uci": { "zapret2": true }
}
},
"admin/services/zapret2/service": {
"title": "Service",
"order": 10,
"action": {
"type": "view",
"path": "zapret2/service"
}
},
"admin/services/zapret2/settings": {
"title": "Settings",
"order": 20,
"action": {
"type": "view",
"path": "zapret2/settings"
}
},
"admin/services/zapret2/dmnlog": {
"title": "Log Viewer",
"order": 30,
"action": {
"type": "view",
"path": "zapret2/dmnlog"
}
}
}

View File

@@ -1,40 +0,0 @@
{
"luci-app-zapret": {
"description": "Grant access to zapret procedures",
"read": {
"cgi-io": [ "exec" ],
"file": {
"/opt/zapret/config": [ "read" ],
"/opt/zapret/ipset/*": [ "read" ],
"/opt/zapret/init.d/openwrt/custom.d/*": [ "read" ],
"/etc/crontabs/root": [ "read" ],
"/tmp/zapret*": [ "read" ],
"/etc/init.d/zapret*": [ "exec" ],
"/bin/ps*": [ "exec" ],
"/bin/cat*": [ "exec" ],
"/bin/busybox*": [ "exec" ],
"/bin/opkg*": [ "exec" ],
"/usr/bin/apk*": [ "exec" ],
"/usr/bin/find*": [ "exec" ],
"/opt/zapret/restore-def-cfg.sh*": [ "exec" ],
"/opt/zapret/script-exec.sh*": [ "exec" ],
"/opt/zapret/update-pkg.sh*": [ "exec" ],
"/opt/zapret/sync_config.sh*": [ "exec" ]
},
"uci": [ "zapret", "network" ],
"ubus": {
"luci": [ "getInitList", "setInitAction" ],
"service": [ "list" ]
}
},
"write": {
"file": {
"/opt/zapret/config": [ "write" ],
"/opt/zapret/ipset/*": [ "write" ],
"/opt/zapret/init.d/openwrt/custom.d/*": [ "write" ],
"/etc/crontabs/root": [ "write" ]
},
"uci": [ "zapret" ]
}
}
}

View File

@@ -0,0 +1,40 @@
{
"luci-app-zapret2": {
"description": "Grant access to zapret2 procedures",
"read": {
"cgi-io": [ "exec" ],
"file": {
"/opt/zapret2/config": [ "read" ],
"/opt/zapret2/ipset/*": [ "read" ],
"/opt/zapret2/init.d/openwrt/custom.d/*": [ "read" ],
"/etc/crontabs/root": [ "read" ],
"/tmp/zapret*": [ "read" ],
"/etc/init.d/zapret2*": [ "exec" ],
"/bin/ps*": [ "exec" ],
"/bin/cat*": [ "exec" ],
"/bin/busybox*": [ "exec" ],
"/bin/opkg*": [ "exec" ],
"/usr/bin/apk*": [ "exec" ],
"/usr/bin/find*": [ "exec" ],
"/opt/zapret2/restore-def-cfg.sh*": [ "exec" ],
"/opt/zapret2/script-exec.sh*": [ "exec" ],
"/opt/zapret2/update-pkg.sh*": [ "exec" ],
"/opt/zapret2/sync_config.sh*": [ "exec" ]
},
"uci": [ "zapret2", "network" ],
"ubus": {
"luci": [ "getInitList", "setInitAction" ],
"service": [ "list" ]
}
},
"write": {
"file": {
"/opt/zapret2/config": [ "write" ],
"/opt/zapret2/ipset/*": [ "write" ],
"/opt/zapret2/init.d/openwrt/custom.d/*": [ "write" ],
"/etc/crontabs/root": [ "write" ]
},
"uci": [ "zapret2" ]
}
}
}

45
zapret-ip2net/Makefile Normal file
View File

@@ -0,0 +1,45 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=zapret2-ip2net
PKG_VERSION:=0.7.20251219
PKG_RELEASE:=1
PKG_MAINTAINER:=bol-van
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=docs/LICENSE.txt
PKG_SOURCE_URL:=https://github.com/bol-van/zapret2.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=99482d06d469000d8cb15507cdcc8f337571c854
PKG_SOURCE_DATE:=2025-12-19
#PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
#PKG_SOURCE_URL:=https://github.com/bol-van/zapret2/archive/refs/tags/v$(PKG_VERSION).tar.gz?
#PKG_HASH:=skip
include $(INCLUDE_DIR)/package.mk
#TAR_OPTIONS:=--strip-components 1 $(TAR_OPTIONS)
#TAR_CMD=$(HOST_TAR) -C $(1) $(TAR_OPTIONS)
MAKE_PATH:=ip2net
define Package/$(PKG_NAME)
SECTION:=net
CATEGORY:=Network
TITLE:=ip2net
SUBMENU:=Zapret2
DEPENDS:=+zlib +zapret2
endef
define Build/Prepare
$(Build/Prepare/Default)
rm -f $(PKG_BUILD_DIR)/$(MAKE_PATH)/ip2net
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/opt/zapret2/ip2net
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(MAKE_PATH)/ip2net $(1)/opt/zapret2/ip2net/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

45
zapret-mdig/Makefile Normal file
View File

@@ -0,0 +1,45 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=zapret2-mdig
PKG_VERSION:=0.7.20251219
PKG_RELEASE:=1
PKG_MAINTAINER:=bol-van
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=docs/LICENSE.txt
PKG_SOURCE_URL:=https://github.com/bol-van/zapret2.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=99482d06d469000d8cb15507cdcc8f337571c854
PKG_SOURCE_DATE:=2025-12-19
#PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
#PKG_SOURCE_URL:=https://github.com/bol-van/zapret2/archive/refs/tags/v$(PKG_VERSION).tar.gz?
#PKG_HASH:=skip
include $(INCLUDE_DIR)/package.mk
#TAR_OPTIONS:=--strip-components 1 $(TAR_OPTIONS)
#TAR_CMD=$(HOST_TAR) -C $(1) $(TAR_OPTIONS)
MAKE_PATH:=mdig
define Package/$(PKG_NAME)
SECTION:=net
CATEGORY:=Network
TITLE:=mdig
SUBMENU:=Zapret2
DEPENDS:=+zlib +zapret2
endef
define Build/Prepare
$(Build/Prepare/Default)
rm -f $(PKG_BUILD_DIR)/$(MAKE_PATH)/mdig
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/opt/zapret2/mdig
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(MAKE_PATH)/mdig $(1)/opt/zapret2/mdig/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -1,24 +1,24 @@
# #
# Copyright (c) 2024 remittor # Copyright (c) 2025 remittor
# #
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=zapret PKG_NAME:=zapret2
PKG_VERSION:=72.20260128 PKG_VERSION:=0.7.20251219
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=bol-van PKG_MAINTAINER:=bol-van
PKG_LICENSE:=MIT PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=docs/LICENSE.txt PKG_LICENSE_FILES:=docs/LICENSE.txt
PKG_SOURCE_URL:=https://github.com/bol-van/zapret.git PKG_SOURCE_URL:=https://github.com/bol-van/zapret2.git
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=119e243b3664d6a512ed8b6ab61dcba00987105c PKG_SOURCE_VERSION:=99482d06d469000d8cb15507cdcc8f337571c854
PKG_SOURCE_DATE:=2026-01-28 PKG_SOURCE_DATE:=2025-12-19
#PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz #PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
#PKG_SOURCE_URL:=https://github.com/bol-van/zapret/archive/refs/tags/v$(PKG_VERSION).tar.gz? #PKG_SOURCE_URL:=https://github.com/bol-van/zapret2/archive/refs/tags/v$(PKG_VERSION).tar.gz?
#PKG_HASH:=skip #PKG_HASH:=skip
include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/package.mk
@@ -26,15 +26,15 @@ include $(INCLUDE_DIR)/package.mk
#TAR_OPTIONS:=--strip-components 1 $(TAR_OPTIONS) #TAR_OPTIONS:=--strip-components 1 $(TAR_OPTIONS)
#TAR_CMD=$(HOST_TAR) -C $(1) $(TAR_OPTIONS) #TAR_CMD=$(HOST_TAR) -C $(1) $(TAR_OPTIONS)
MAKE_PATH:=nfq MAKE_PATH:=nfq2
define Package/$(PKG_NAME) define Package/$(PKG_NAME)
SECTION:=net SECTION:=net
CATEGORY:=Network CATEGORY:=Network
TITLE:=$(PKG_NAME) TITLE:=$(PKG_NAME)
SUBMENU:=Zapret SUBMENU:=Zapret2
URL:=https://github.com/bol-van/zapret URL:=https://github.com/bol-van/zapret2
DEPENDS:= +nftables +curl +gzip DEPENDS:= +nftables +curl +gzip +liblua +luajit
DEPENDS+= +coreutils +coreutils-sort +coreutils-sleep DEPENDS+= +coreutils +coreutils-sort +coreutils-sleep
DEPENDS+= +kmod-nft-nat +kmod-nft-offload +kmod-nft-queue DEPENDS+= +kmod-nft-nat +kmod-nft-offload +kmod-nft-queue
DEPENDS+= +libnetfilter-queue +libcap +zlib DEPENDS+= +libnetfilter-queue +libcap +zlib
@@ -42,185 +42,95 @@ endef
define Build/Prepare define Build/Prepare
$(Build/Prepare/Default) $(Build/Prepare/Default)
rm -f $(PKG_BUILD_DIR)/$(MAKE_PATH)/nfqws rm -f $(PKG_BUILD_DIR)/$(MAKE_PATH)/nfqws2
rm -f $(PKG_BUILD_DIR)/ip2net/ip2net
rm -f $(PKG_BUILD_DIR)/mdig/mdig
endef endef
#define Build/Configure #define Build/Configure
#endef #endef
define Build/Compile #define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR)/$(MAKE_PATH) $(TARGET_CONFIGURE_OPTS) #endef
$(MAKE) -C $(PKG_BUILD_DIR)/ip2net $(TARGET_CONFIGURE_OPTS)
$(MAKE) -C $(PKG_BUILD_DIR)/mdig $(TARGET_CONFIGURE_OPTS)
endef
ZAPRET_DIR := /opt/zapret
define ZAPRET_CONFFILES_LIST
$(ZAPRET_DIR)/config
$(ZAPRET_DIR)/ipset/zapret-hosts-google.txt
$(ZAPRET_DIR)/ipset/zapret-hosts-user.txt
$(ZAPRET_DIR)/ipset/zapret-hosts-user-exclude.txt
$(ZAPRET_DIR)/ipset/zapret-ip-exclude.txt
$(ZAPRET_DIR)/ipset/zapret-hosts-auto.txt
$(ZAPRET_DIR)/ipset/cust1.txt
$(ZAPRET_DIR)/ipset/cust2.txt
$(ZAPRET_DIR)/ipset/cust3.txt
$(ZAPRET_DIR)/ipset/cust4.txt
$(ZAPRET_DIR)/init.d/openwrt/custom.d/10-script.sh
$(ZAPRET_DIR)/init.d/openwrt/custom.d/20-script.sh
$(ZAPRET_DIR)/init.d/openwrt/custom.d/50-script.sh
$(ZAPRET_DIR)/init.d/openwrt/custom.d/60-script.sh
$(ZAPRET_DIR)/init.d/openwrt/custom.d/90-script.sh
endef
$(eval ZAPRET_CONFFILES := $(foreach file,$(ZAPRET_CONFFILES_LIST),$(strip $(file))))
define Package/$(PKG_NAME)/conffiles define Package/$(PKG_NAME)/conffiles
$(ZAPRET_CONFFILES_LIST) /etc/config/zapret2
/opt/zapret2/config
/opt/zapret2/ipset/
/opt/zapret2/init.d/openwrt/custom.d/
endef endef
define Package/$(PKG_NAME)/install define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)$(ZAPRET_DIR) $(INSTALL_DIR) $(1)/opt/zapret2
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/$(MAKE_PATH) $(INSTALL_DIR) $(1)/opt/zapret2/$(MAKE_PATH)
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(MAKE_PATH)/nfqws $(1)$(ZAPRET_DIR)/$(MAKE_PATH)/ $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(MAKE_PATH)/nfqws2 $(1)/opt/zapret2/$(MAKE_PATH)/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/ip2net $(INSTALL_DIR) $(1)/opt/zapret2/common
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ip2net/ip2net $(1)$(ZAPRET_DIR)/ip2net/ $(CP) $(PKG_BUILD_DIR)/common/* $(1)/opt/zapret2/common/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/mdig $(INSTALL_DIR) $(1)/opt/zapret2/lua
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mdig/mdig $(1)$(ZAPRET_DIR)/mdig/ $(CP) $(PKG_BUILD_DIR)/lua/* $(1)/opt/zapret2/lua/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/common #$(INSTALL_DIR) $(1)/opt/zapret2/docs
$(CP) $(PKG_BUILD_DIR)/common/* $(1)$(ZAPRET_DIR)/common/ #$(CP) $(PKG_BUILD_DIR)/docs/* $(1)/opt/zapret2/docs/
#$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/docs $(INSTALL_DIR) $(1)/opt/zapret2/files
#$(CP) $(PKG_BUILD_DIR)/docs/* $(1)$(ZAPRET_DIR)/docs/ $(CP) $(PKG_BUILD_DIR)/files/* $(1)/opt/zapret2/files/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/files $(CP) ./files/* $(1)/opt/zapret2/files/
$(CP) $(PKG_BUILD_DIR)/files/* $(1)$(ZAPRET_DIR)/files/ $(INSTALL_DIR) $(1)/opt/zapret2/ipset
$(CP) ./files/* $(1)$(ZAPRET_DIR)/files/ $(CP) $(PKG_BUILD_DIR)/ipset/* $(1)/opt/zapret2/ipset/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/ipset $(INSTALL_DIR) $(1)/opt/zapret2/blockcheck2.d
$(CP) $(PKG_BUILD_DIR)/ipset/* $(1)$(ZAPRET_DIR)/ipset/ $(CP) $(PKG_BUILD_DIR)/blockcheck2.d/* $(1)/opt/zapret2/blockcheck2.d/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/blockcheck.sh $(1)$(ZAPRET_DIR)/blockcheck.sh $(INSTALL_BIN) $(PKG_BUILD_DIR)/blockcheck2.sh $(1)/opt/zapret2/blockcheck2.sh
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/tmp #$(INSTALL_DATA) $(PKG_BUILD_DIR)/config.default $(1)/opt/zapret2/config.default
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/init.d/openwrt $(INSTALL_DIR) $(1)/opt/zapret2/tmp
$(CP) $(PKG_BUILD_DIR)/init.d/openwrt/* $(1)$(ZAPRET_DIR)/init.d/openwrt/ $(INSTALL_DIR) $(1)/opt/zapret2/init.d/openwrt
$(CP) $(PKG_BUILD_DIR)/init.d/openwrt/* $(1)/opt/zapret2/init.d/openwrt/
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface $(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_BIN) $(PKG_BUILD_DIR)/init.d/openwrt/90-zapret $(1)/etc/hotplug.d/iface/90-zapret $(INSTALL_BIN) $(PKG_BUILD_DIR)/init.d/openwrt/90-zapret2 $(1)/etc/hotplug.d/iface/90-zapret2
$(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./init.d.sh $(1)/etc/init.d/zapret $(INSTALL_BIN) ./init.d.sh $(1)/etc/init.d/zapret2
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/init.d $(INSTALL_DATA) ./config.default $(1)/opt/zapret2/config.default
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/init.d/openwrt $(INSTALL_DATA) ./ipset/zapret-hosts-google.txt $(1)/opt/zapret2/ipset/zapret-hosts-google.txt
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/init.d/openwrt/custom.d $(INSTALL_DATA) ./ipset/zapret-hosts-user.txt $(1)/opt/zapret2/ipset/zapret-hosts-user.txt
$(INSTALL_DATA) ./ipset/zapret-hosts-user-exclude.txt $(1)/opt/zapret2/ipset/zapret-hosts-user-exclude.txt
$(INSTALL_DATA) ./ipset/zapret-ip-exclude.txt $(1)/opt/zapret2/ipset/zapret-ip-exclude.txt
$(INSTALL_DIR) $(1)/opt/zapret2/ipset_def
$(INSTALL_DATA) ./ipset/zapret-hosts-google.txt $(1)/opt/zapret2/ipset_def/zapret-hosts-google.txt
$(INSTALL_DATA) ./ipset/zapret-hosts-user.txt $(1)/opt/zapret2/ipset_def/zapret-hosts-user.txt
$(INSTALL_DATA) ./ipset/zapret-hosts-user-exclude.txt $(1)/opt/zapret2/ipset_def/zapret-hosts-user-exclude.txt
$(INSTALL_DATA) ./ipset/zapret-ip-exclude.txt $(1)/opt/zapret2/ipset_def/zapret-ip-exclude.txt
$(INSTALL_DIR) $(1)/opt/zapret2/init.d
$(INSTALL_DIR) $(1)/opt/zapret2/init.d/openwrt
$(INSTALL_DIR) $(1)/opt/zapret2/init.d/openwrt/custom.d
$(CP) ./custom.d/* $(1)/opt/zapret2/init.d/openwrt/custom.d/
$(INSTALL_DIR) $(1)/etc/uci-defaults $(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./uci-def-cfg.sh $(1)/etc/uci-defaults/zapret-uci-def-cfg.sh $(INSTALL_BIN) ./uci-def-cfg.sh $(1)/etc/uci-defaults/zapret2-uci-def-cfg.sh
# install all sh-scripts $(INSTALL_BIN) ./uci-def-cfg.sh $(1)/opt/zapret2/uci-def-cfg.sh
$(CP) ./*.sh $(1)$(ZAPRET_DIR)/ $(INSTALL_BIN) ./comfunc.sh $(1)/opt/zapret2/comfunc.sh
rm -f $(1)$(ZAPRET_DIR)/init.d.sh $(INSTALL_BIN) ./def-cfg.sh $(1)/opt/zapret2/def-cfg.sh
# Install conf files $(INSTALL_BIN) ./renew-cfg.sh $(1)/opt/zapret2/renew-cfg.sh
$(foreach cfg,$(ZAPRET_CONFFILES), \ $(INSTALL_BIN) ./restore-def-cfg.sh $(1)/opt/zapret2/restore-def-cfg.sh
rel="$(cfg:$(ZAPRET_DIR)/%=%)"; \ $(INSTALL_BIN) ./sync_config.sh $(1)/opt/zapret2/sync_config.sh
src="./$$$$rel"; \ $(INSTALL_BIN) ./script-exec.sh $(1)/opt/zapret2/script-exec.sh
if echo "$$$$rel" | grep -q "/custom.d/"; then \ $(INSTALL_BIN) ./update-pkg.sh $(1)/opt/zapret2/update-pkg.sh
src="./custom.d/$$$$(basename $$$$rel)"; \ # Fix permisions
fi; \ chmod 644 $(1)/opt/zapret2/ipset/*.txt
dst="$(1)$(cfg)"; \ chmod 644 $(1)/opt/zapret2/ipset_def/*.txt
mkdir -p "$(1)$(dir $(cfg))"; \ chmod 644 $(1)/opt/zapret2/init.d/openwrt/custom.d/*.sh
rm -f "$$$${dst}"; \ chmod 644 $(1)/opt/zapret2/config.default
if [ -f "$$$${src}" ]; then \ chmod 755 $(1)/opt/zapret2/*.sh
$(INSTALL_DATA) "$$$${src}" "$$$${dst}"; \
else \
$(INSTALL_DATA) /dev/null "$$$${dst}"; \
fi; \
)
# Fix main config file
rm -f $(1)$(ZAPRET_DIR)/config
$(INSTALL_DATA) ./config.default $(1)$(ZAPRET_DIR)/config
$(INSTALL_DATA) ./config.default $(1)$(ZAPRET_DIR)/config.default
# Install def conf files
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/ipset_def
$(CP) ./ipset/zapret*.txt $(1)$(ZAPRET_DIR)/ipset_def/
# Fix permissions
chmod 644 $(1)$(ZAPRET_DIR)/ipset/*.txt
chmod 644 $(1)$(ZAPRET_DIR)/ipset_def/*.txt
chmod 644 $(1)$(ZAPRET_DIR)/init.d/openwrt/custom.d/*.sh
chmod 644 $(1)$(ZAPRET_DIR)/config*
chmod 755 $(1)$(ZAPRET_DIR)/*.sh
chmod 755 $(1)$(ZAPRET_DIR)/$(MAKE_PATH)/*
chmod 755 $(1)$(ZAPRET_DIR)/ip2net/*
chmod 755 $(1)$(ZAPRET_DIR)/mdig/*
# Disable TPWS in blockcheck
grep -q '^SKIP_TPWS=' $(1)$(ZAPRET_DIR)/blockcheck.sh || sed -i '/^NFT_TABLE=blockcheck$$$$/a SKIP_TPWS=$$$${SKIP_TPWS:-1}' $(1)$(ZAPRET_DIR)/blockcheck.sh
endef endef
define Package/$(PKG_NAME)/preinst define Package/$(PKG_NAME)/preinst
#!/bin/sh #!/bin/sh
# check if we are on real system # check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then if [ -z "$${IPKG_INSTROOT}" ]; then
ZAPRET_DIR=/opt/zapret if [ -f "/etc/init.d/zapret2" ]; then
ZAPRET_INITD=/etc/init.d/zapret SCRIPT=$$( readlink /etc/init.d/zapret2 )
ZAPRET_CFG=/etc/config/zapret
if [ -f "$${ZAPRET_INITD}" ]; then
SCRIPT=$$( readlink "$${ZAPRET_INITD}" )
if [ -n "$${SCRIPT}" ]; then if [ -n "$${SCRIPT}" ]; then
echo "Please uninstall incompatible \"zapret\" service!" echo "Please uninstall original zapret2 utility!"
exit 44 exit 44
fi fi
fi fi
if command -v apk >/dev/null; then
PKG_MGR="apk"
PKG_CHECK="apk info -e "
PKG_REMOVE="apk del --force "
else
PKG_MGR="opkg"
PKG_CHECK="opkg status "
PKG_REMOVE="opkg remove --force-remove "
fi
if [ "$${PKG_UPGRADE}" = "1" ]; then if [ "$${PKG_UPGRADE}" = "1" ]; then
# stop service if PKG_UPGRADE # stop service if PKG_UPGRADE
if [ -x "$${ZAPRET_INITD}" ]; then if [ -x "/etc/init.d/zapret2" ]; then
$${ZAPRET_INITD} running && $${ZAPRET_INITD} stop >/dev/null 2>&1 /etc/init.d/zapret2 running && /etc/init.d/zapret2 stop >/dev/null 2>&1
fi
fi
if $${PKG_CHECK} zapret >/dev/null 2>&1; then
if [ ! -f "/opt/zapret/sync_config.sh" ]; then
echo "Please uninstall incompatible \"zapret\" package!"
exit 47
fi
if [ -f "$${ZAPRET_CFG}" ] && ! grep -q "run_on_boot" "$${ZAPRET_CFG}"; then
echo "Please uninstall incompatible \"zapret\" package!"
exit 48
fi
fi
if $${PKG_CHECK} luci-app-zapret >/dev/null 2>&1; then
SVC_FILE=/www/luci-static/resources/view/zapret/service.js
if [ ! -f "$${SVC_FILE}" ] || ! grep -Fq "/remittor/zapret-openwrt" "$${SVC_FILE}"; then
echo "Please uninstall incompatible \"luci-app-zapret\" package!"
exit 55
fi
fi
if [ -f "$${ZAPRET_CFG}" ] && ! grep -q "run_on_boot" "$${ZAPRET_CFG}"; then
if [ -x "$${ZAPRET_INITD}" ]; then
$${ZAPRET_INITD} running && $${ZAPRET_INITD} stop >/dev/null 2>&1
fi
rm -f $${ZAPRET_CFG}
rm -f $${ZAPRET_INITD}
[ -d "$${ZAPRET_DIR}" ] && rm -rf $${ZAPRET_DIR}
echo "All files of the previously installed package have been removed!"
fi
if $${PKG_CHECK} zapret-mdig >/dev/null 2>&1; then
$${PKG_REMOVE} zapret-mdig
fi
if $${PKG_CHECK} zapret-ip2net >/dev/null 2>&1; then
$${PKG_REMOVE} zapret-ip2net
fi
if [ ! -d "$${ZAPRET_DIR}" ]; then
mkdir -p $${ZAPRET_DIR}
fi
if [ ! -f "/opt/zapret/ipset/zapret-hosts-google.txt" ]; then
if [ -f "/opt/zapret/ipset/zapret-hosts-user.txt" ]; then
CFGLISTHASH=$$( md5sum "/opt/zapret/ipset/zapret-hosts-user.txt" | awk '{print $$1;}' )
if [ "$${CFGLISTHASH}" = "79e35df62b0d1ae455d0a7e04c4cecac" ]; then
rm -f "/opt/zapret/ipset/zapret-hosts-user.txt"
fi
fi fi
fi fi
fi fi
@@ -231,55 +141,32 @@ define Package/$(PKG_NAME)/postinst
#!/bin/sh #!/bin/sh
# check if we are on real system # check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then if [ -z "$${IPKG_INSTROOT}" ]; then
ZAPRET_DIR=/opt/zapret ZAPRET_CONFIG=/opt/zapret2/config
ZAPRET_INITD=/etc/init.d/zapret ZAPRET_CONFIG_DEF="/opt/zapret2/config.default"
ZAPRET_CFG=/etc/config/zapret
ZAPRET_CONFIG=/opt/zapret/config
ZAPRET_CONFIG_DEF="/opt/zapret/config.default"
# Fix permissions
chmod 644 $${ZAPRET_CFG} >/dev/null 2>&1
chmod 644 $${ZAPRET_DIR}/ipset/*.txt >/dev/null 2>&1
chmod 644 $${ZAPRET_DIR}/ipset_def/*.txt >/dev/null 2>&1
chmod 644 $${ZAPRET_DIR}/init.d/openwrt/custom.d/*.sh >/dev/null 2>&1
chmod 644 $${ZAPRET_DIR}/config* >/dev/null 2>&1
# cleanup custom.d directory
rm -f $${ZAPRET_DIR}/init.d/openwrt/custom.d/*-opkg*
rm -f $${ZAPRET_DIR}/init.d/openwrt/custom.d/*.opkg*
rm -f $${ZAPRET_DIR}/init.d/openwrt/custom.d/*.apk*
# creating main config if its not exists # creating main config if its not exists
if [ ! -f "$${ZAPRET_CONFIG}" ]; then if [ ! -f "$${ZAPRET_CONFIG}" ]; then
cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}" cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}"
fi fi
# check obsolete format for main config
if grep -qE "^NFQWS_OPT_DESYNC=|^MODE_HTTP=|^MODE_HTTPS=|^MODE_QUIC=|^MODE=" "$${ZAPRET_CONFIG}" ; then
echo "Detect obsolute format for main config!"
ZAPRET_CONFIG_BACKUP="$${ZAPRET_CONFIG}.backup"
cp -f "$${ZAPRET_CONFIG}" "$${ZAPRET_CONFIG_BACKUP}"
echo "Current file $${ZAPRET_CONFIG} backuped to $${ZAPRET_CONFIG_BACKUP}"
cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}"
fi
# remove fake uci-config
[ -f "$${ZAPRET_CFG}" ] && [ ! -s "$${ZAPRET_CFG}" ] && rm -f "$${ZAPRET_CFG}"
# check existing uci-config # check existing uci-config
[ -f "$${ZAPRET_CFG}" ] && ZAPRET_CFG_EXISTS=1 || ZAPRET_CFG_EXISTS=0 [ -f "/etc/config/zapret2" ] && ZAPRET_CFG_EXISTS=1 || ZAPRET_CFG_EXISTS=0
# create or merge uci-config # create or merge uci-config
/opt/zapret/uci-def-cfg.sh /opt/zapret2/uci-def-cfg.sh
[ "$${ZAPRET_CFG_EXISTS}" = "1" ] && echo "Config /etc/config/zapret merged with default uci-config" [ "$${ZAPRET_CFG_EXISTS}" = "1" ] && echo "Config /etc/config/zapret2 merged with default uci-config"
# remove uci-default script from system dir (used into /etc/init.d/boot) # remove uci-default script from system dir (used into /etc/init.d/boot)
rm -f /etc/uci-defaults/zapret-uci-def-cfg.sh rm -f /etc/uci-defaults/zapret2-uci-def-cfg.sh
# copy (sync) all params from uci-config to main config # copy (sync) all params from uci-config to main config
/opt/zapret/sync_config.sh /opt/zapret2/sync_config.sh
# check main config # check main config
sh -n "$${ZAPRET_CONFIG}" 2>/dev/null || cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}" sh -n "$${ZAPRET_CONFIG}" 2>/dev/null || cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}"
sh -n "$${ZAPRET_CONFIG}" 2>/dev/null || exit 58 sh -n "$${ZAPRET_CONFIG}" 2>/dev/null || exit 58
# enable main service # enable main service
$${ZAPRET_INITD} enable /etc/init.d/zapret2 enable
# stop all # stop all
$${ZAPRET_INITD} stop_fw >/dev/null 2>&1 /etc/init.d/zapret2 stop_fw
$${ZAPRET_INITD} stop_daemons >/dev/null 2>&1 /etc/init.d/zapret2 stop_daemons
ps w | grep '/opt/zapret/nfq/nfqws' | grep -v grep | awk '{print $$1}' | xargs -r kill -9 ps w | grep '/opt/zapret2/nfq2/nfqws2' | grep -v grep | awk '{print $$1}' | xargs -r kill -9
# start main service # start main service
$${ZAPRET_INITD} start /etc/init.d/zapret2 start
# restart firewall # restart firewall
[ -x /sbin/fw4 ] && fw4 -q restart || fw3 -q restart [ -x /sbin/fw4 ] && fw4 -q restart || fw3 -q restart
fi fi
@@ -290,17 +177,15 @@ define Package/$(PKG_NAME)/prerm
#!/bin/sh #!/bin/sh
# check if we are on real system # check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then if [ -z "$${IPKG_INSTROOT}" ]; then
ZAPRET_DIR=/opt/zapret EXEDIR=/opt/zapret2
ZAPRET_BASE=/opt/zapret ZAPRET_BASE=/opt/zapret2
ZAPRET_INITD=/etc/init.d/zapret ZAPRET_CONFIG=/opt/zapret2/config
ZAPRET_CFG=/etc/config/zapret ZAPRET_CONFIG_DEF="/opt/zapret2/config.default"
ZAPRET_CONFIG=/opt/zapret/config OPENWRT_FW_INCLUDE=/etc/firewall.zapret2
ZAPRET_CONFIG_DEF="/opt/zapret/config.default"
OPENWRT_FW_INCLUDE=/etc/firewall.zapret
# check main config # check main config
sh -n "$${ZAPRET_CONFIG}" 2>/dev/null || cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}" sh -n "$${ZAPRET_CONFIG}" 2>/dev/null || cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}"
if ! sh -n "$${ZAPRET_CONFIG}" 2>/dev/null ; then if ! sh -n "$${ZAPRET_CONFIG}" 2>/dev/null ; then
ps w | grep '/opt/zapret/nfq/nfqws' | grep -v grep | awk '{print $$1}' | xargs -r kill -9 ps w | grep '/opt/zapret2/nfq2/nfqws2' | grep -v grep | awk '{print $$1}' | xargs -r kill -9
exit 0 exit 0
fi fi
. "$${ZAPRET_CONFIG}" . "$${ZAPRET_CONFIG}"
@@ -308,9 +193,9 @@ if [ -z "$${IPKG_INSTROOT}" ]; then
. "$${ZAPRET_BASE}/common/fwtype.sh" . "$${ZAPRET_BASE}/common/fwtype.sh"
. "$${ZAPRET_BASE}/common/nft.sh" . "$${ZAPRET_BASE}/common/nft.sh"
. "$${ZAPRET_BASE}/common/installer.sh" . "$${ZAPRET_BASE}/common/installer.sh"
$${ZAPRET_INITD} running && $${ZAPRET_INITD} stop >/dev/null 2>&1 /etc/init.d/zapret2 running && /etc/init.d/zapret2 stop
$${ZAPRET_INITD} disable >/dev/null 2>&1 /etc/init.d/zapret2 disable
ps w | grep '/opt/zapret/nfq/nfqws' | grep -v grep | awk '{print $$1}' | xargs -r kill -9 ps w | grep '/opt/zapret2/nfq2/nfqws2' | grep -v grep | awk '{print $$1}' | xargs -r kill -9
remove_openwrt_firewall remove_openwrt_firewall
nft_del_table nft_del_table
restart_openwrt_firewall restart_openwrt_firewall
@@ -322,12 +207,10 @@ define Package/$(PKG_NAME)/postrm
#!/bin/sh #!/bin/sh
# check if we are on real system # check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then if [ -z "$${IPKG_INSTROOT}" ]; then
rm -f /etc/config/zapret-opkg* [ -f "/etc/config/zapret2-opkg" ] && rm -f "/etc/config/zapret2-opkg"
rm -f /etc/config/zapret.opkg* [ -f "/opt/zapret2/config" ] && cp -f /opt/zapret2/config "/opt/zapret2/config.backup"
rm -f /etc/config/zapret.apk* #rm -rf /opt/zapret2
[ -f "/opt/zapret/config" ] && cp -f /opt/zapret/config "/opt/zapret/config.backup" #echo "Directory /opt/zapret2 removed!"
#rm -rf /opt/zapret
#echo "Directory /opt/zapret removed!"
fi fi
exit 0 exit 0
endef endef

View File

@@ -1,22 +1,19 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2024 remittor # Copyright (c) 2024 remittor
EXEDIR=/opt/zapret EXEDIR=/opt/zapret2
ZAPRET_BASE=/opt/zapret ZAPRET_BASE=/opt/zapret2
ZAPRET_INITD=/etc/init.d/zapret ZAPRET_INITD=/etc/init.d/zapret2
ZAPRET_ORIG_INITD="$ZAPRET_BASE/init.d/openwrt/zapret" ZAPRET_ORIG_INITD="$ZAPRET_BASE/init.d/openwrt/zapret2"
ZAP_LOG_TAG=ZAPRET
ZAPRET_CONFIG="$ZAPRET_BASE/config" ZAPRET_CONFIG="$ZAPRET_BASE/config"
ZAPRET_CONFIG_NEW="$ZAPRET_BASE/config.new" ZAPRET_CONFIG_NEW="$ZAPRET_BASE/config.new"
ZAPRET_CONFIG_DEF="$ZAPRET_BASE/config.default" ZAPRET_CONFIG_DEF="$ZAPRET_BASE/config.default"
ZAPRET_CFG=/etc/config/zapret ZAPRET_CFG=/etc/config/zapret2
ZAPRET_CFG_NAME=zapret ZAPRET_CFG_NAME=zapret2
ZAPRET_CFG_SEC=$ZAPRET_CFG_NAME.config ZAPRET_CFG_SEC_NAME="$( uci -q get $ZAPRET_CFG_NAME.config )"
ZAPRET_CFG_SEC_NAME="$( uci -q get $ZAPRET_CFG_SEC )"
. $ZAPRET_BASE/def-cfg.sh . $ZAPRET_BASE/def-cfg.sh
@@ -130,7 +127,7 @@ function restore_all_ipset_cfg
restore_ipset_txt zapret-hosts-google.txt restore_ipset_txt zapret-hosts-google.txt
restore_ipset_txt zapret-hosts-user.txt restore_ipset_txt zapret-hosts-user.txt
restore_ipset_txt zapret-hosts-user-exclude.txt restore_ipset_txt zapret-hosts-user-exclude.txt
restore_ipset_txt zapret-ip-exclude.txt restore_ipset_txt zapret-ip-exclude.txt.txt
} }
function create_default_cfg function create_default_cfg
@@ -151,7 +148,7 @@ function merge_cfg_with_def_values
local cfgname=${1:-$ZAPRET_CFG_NAME} local cfgname=${1:-$ZAPRET_CFG_NAME}
local force=$2 local force=$2
local cfgfile=/etc/config/$cfgname local cfgfile=/etc/config/$cfgname
local NEWCFGNAME="$ZAPRET_CFG_NAME-default" local NEWCFGNAME="zapret2-default"
local NEWCFGFILE="/etc/config/$NEWCFGNAME" local NEWCFGFILE="/etc/config/$NEWCFGNAME"
local cfg_sec_name="$( uci -q get $ZAPRET_CFG_NAME.config )" local cfg_sec_name="$( uci -q get $ZAPRET_CFG_NAME.config )"
@@ -170,25 +167,17 @@ function merge_cfg_with_def_values
function remove_cron_task_logs function remove_cron_task_logs
{ {
[ ! -f $CRONTAB_FILE ] && return 0 if [ -f "$CRONTAB_FILE" ]; then
if grep -q -e "-name '$ZAPRET_CFG_NAME+\*\.log' -size " $CRONTAB_FILE; then sed -i "/-name 'zapret2\*.log' -size +/d" "$CRONTAB_FILE"
sed -i "/-name '$ZAPRET_CFG_NAME+\*.log' -size /d" $CRONTAB_FILE
#/etc/init.d/cron restart 2> /dev/null
fi fi
} }
function insert_cron_task_logs function insert_cron_task_logs
{ {
local daemon_log_size_max=${1:-2000} [ ! -f "$CRONTAB_FILE" ] && touch "$CRONTAB_FILE"
[ ! -f $CRONTAB_FILE ] && touch $CRONTAB_FILE [ ! -f "$CRONTAB_FILE" ] && return 1
[ ! -f $CRONTAB_FILE ] && return 1 if ! grep -q -e "-name 'zapret2\*\.log' -size \+" "$CRONTAB_FILE"; then
if ! grep -q -e "-name '$ZAPRET_CFG_NAME+\*\.log' -size " $CRONTAB_FILE; then echo "*/2 * * * * /usr/bin/find /tmp -maxdepth 1 -type f -name 'zapret2*.log' -size +2600k -exec rm -f {} \;" >> "$CRONTAB_FILE"
case "$daemon_log_size_max" in
''|'0'|*[!0-9]*)
daemon_log_size_max=2000
;;
esac
echo "*/1 * * * * /usr/bin/find /tmp -maxdepth 1 -type f -name '$ZAPRET_CFG_NAME+*.log' -size +${daemon_log_size_max}k -exec rm -f {} \;" >> $CRONTAB_FILE
/etc/init.d/cron restart 2> /dev/null /etc/init.d/cron restart 2> /dev/null
fi fi
return 0 return 0
@@ -196,19 +185,15 @@ function insert_cron_task_logs
function init_before_start function init_before_start
{ {
local daemon_log_enable=$1 local DAEMON_LOG_ENABLE=$1
local daemon_log_size_max=${2:-2000}
local HOSTLIST_FN="$ZAPRET_BASE/ipset/zapret-hosts-user.txt" local HOSTLIST_FN="$ZAPRET_BASE/ipset/zapret-hosts-user.txt"
[ ! -f "$HOSTLIST_FN" ] && touch "$HOSTLIST_FN" [ ! -f "$HOSTLIST_FN" ] && touch "$HOSTLIST_FN"
chmod 644 $ZAPRET_BASE/ipset/*.txt chmod 644 $ZAPRET_BASE/ipset/*.txt
chmod 666 $ZAPRET_BASE/ipset/*.log chmod 666 $ZAPRET_BASE/ipset/*.log
rm -f $ZAPRET_BASE/init.d/openwrt/custom.d/*-opkg* rm -f /tmp/zapret2*.log
rm -f $ZAPRET_BASE/init.d/openwrt/custom.d/*.opkg*
rm -f $ZAPRET_BASE/init.d/openwrt/custom.d/*.apk*
rm -f /tmp/$ZAPRET_CFG_NAME+*.log
#*/ #*/
if [ "$daemon_log_enable" = "1" ]; then if [ "$DAEMON_LOG_ENABLE" = "1" ]; then
insert_cron_task_logs "$daemon_log_size_max" insert_cron_task_logs
else else
remove_cron_task_logs remove_cron_task_logs
fi fi

View File

@@ -30,9 +30,15 @@ IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4"
IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5" IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5"
# options for auto hostlist # options for auto hostlist
# NOTE : in order for these adjustment to work it's required to redirect enough starting packets
# NOTE : set PKT_IN, PKT_OUT variables appropriately
AUTOHOSTLIST_INCOMING_MAXSEQ=4096
AUTOHOSTLIST_RETRANS_MAXSEQ=32768
AUTOHOSTLIST_RETRANS_THRESHOLD=3 AUTOHOSTLIST_RETRANS_THRESHOLD=3
AUTOHOSTLIST_FAIL_THRESHOLD=3 AUTOHOSTLIST_FAIL_THRESHOLD=3
AUTOHOSTLIST_FAIL_TIME=60 AUTOHOSTLIST_FAIL_TIME=60
AUTOHOSTLIST_UDP_IN=1
AUTOHOSTLIST_UDP_OUT=4
# 1 = debug autohostlist positives to ipset/zapret-hosts-auto-debug.log # 1 = debug autohostlist positives to ipset/zapret-hosts-auto-debug.log
AUTOHOSTLIST_DEBUGLOG=0 AUTOHOSTLIST_DEBUGLOG=0
@@ -63,47 +69,31 @@ DESYNC_MARK_POSTNAT=0x20000000
FILTER_MARK="" FILTER_MARK=""
TPWS_SOCKS_ENABLE=0 NFQWS2_ENABLE=1
# tpws socks listens on this port on localhost and LAN interfaces
TPPORT_SOCKS=987
# use <HOSTLIST> and <HOSTLIST_NOAUTO> placeholders to engage standard hostlists and autohostlist in ipset dir
# hostlist markers are replaced to empty string if MODE_FILTER does not satisfy
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
TPWS_SOCKS_OPT="--filter-tcp=80 --methodeol <HOSTLIST> --new --filter-tcp=443 --split-tls=sni --disorder <HOSTLIST>"
TPWS_ENABLE=0
TPWS_PORTS="80,443"
# use <HOSTLIST> and <HOSTLIST_NOAUTO> placeholders to engage standard hostlists and autohostlist in ipset dir
# hostlist markers are replaced to empty string if MODE_FILTER does not satisfy
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
TPWS_OPT="--filter-tcp=80 --methodeol <HOSTLIST> --new --filter-tcp=443 --split-tls=sni --disorder <HOSTLIST>"
NFQWS_ENABLE=1
# redirect outgoing traffic with connbytes limiter applied in both directions. # redirect outgoing traffic with connbytes limiter applied in both directions.
NFQWS_PORTS_TCP="80,443" NFQWS2_PORTS_TCP="80,443"
NFQWS_PORTS_UDP="443" NFQWS2_PORTS_UDP="443"
# PKT_OUT means connbytes dir original # PKT_OUT means connbytes dir original
# PKT_IN means connbytes dir reply # PKT_IN means connbytes dir reply
# this is --dpi-desync-cutoff=nX kernel mode implementation for linux. it saves a lot of CPU. # this is --dpi-desync-cutoff=nX kernel mode implementation for linux. it saves a lot of CPU.
NFQWS_TCP_PKT_OUT="9" NFQWS2_TCP_PKT_OUT="9"
NFQWS_TCP_PKT_IN="3" NFQWS2_TCP_PKT_IN="3"
NFQWS_UDP_PKT_OUT="9" NFQWS2_UDP_PKT_OUT="9"
NFQWS_UDP_PKT_IN="0" NFQWS2_UDP_PKT_IN="0"
# redirect outgoing traffic without connbytes limiter and incoming with connbytes limiter # redirect outgoing traffic without connbytes limiter and incoming with connbytes limiter
# normally it's needed only for stateless DPI that matches every packet in a single TCP session # normally it's needed only for stateless DPI that matches every packet in a single TCP session
# typical example are plain HTTP keep alives # typical example are plain HTTP keep alives
# this mode can be very CPU consuming. enable with care ! # this mode can be very CPU consuming. enable with care !
NFQWS_PORTS_TCP_KEEPALIVE="" NFQWS2_PORTS_TCP_KEEPALIVE=""
NFQWS_PORTS_UDP_KEEPALIVE="" NFQWS2_PORTS_UDP_KEEPALIVE=""
# use <HOSTLIST> and <HOSTLIST_NOAUTO> placeholders to engage standard hostlists and autohostlist in ipset dir # use <HOSTLIST> and <HOSTLIST_NOAUTO> placeholders to engage standard hostlists and autohostlist in ipset dir
# hostlist markers are replaced to empty string if MODE_FILTER does not satisfy # hostlist markers are replaced to empty string if MODE_FILTER does not satisfy
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list # <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
NFQWS_OPT="--filter-tcp=80 <HOSTLIST> --dpi-desync=fake,fakedsplit --dpi-desync-autottl=2 --dpi-desync-fooling=badsum --new --filter-tcp=443 --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --dpi-desync=fake,multidisorder --dpi-desync-split-pos=1,midsld --dpi-desync-repeats=11 --dpi-desync-fooling=badsum --dpi-desync-fake-tls-mod=rnd,dupsid,sni=www.google.com --new --filter-udp=443 --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin --new --filter-udp=443 <HOSTLIST_NOAUTO> --dpi-desync=fake --dpi-desync-repeats=11 --new --filter-tcp=443 <HOSTLIST> --dpi-desync=multidisorder --dpi-desync-split-pos=1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1" NFQWS2_OPT="--filter-tcp=80 --filter-l7=http <HOSTLIST> --payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5 --lua-desync=multisplit:pos=method+2 --new --filter-tcp=443 --filter-l7=tls <HOSTLIST> --payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tcp_seq=-10000 --lua-desync=multidisorder:pos=1,midsld --new --filter-udp=443 --filter-l7=quic <HOSTLIST_NOAUTO> --payload=quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=6"
DISABLE_CUSTOM=1 DISABLE_CUSTOM=1
@@ -121,9 +111,8 @@ FLOWOFFLOAD=none
# for routers based on desktop linux and macos. has no effect in openwrt. # for routers based on desktop linux and macos. has no effect in openwrt.
# CHOOSE LAN and optinally WAN/WAN6 NETWORK INTERFACES # CHOOSE LAN and optinally WAN/WAN6 NETWORK INTERFACES
# or leave them commented if its not router # or leave them commented if its not router
# it's possible to specify multiple interfaces like this : IFACE_LAN="eth0 eth1 eth2" # it's possible to specify multiple interfaces like this : IFACE_WAN="eth0 eth1 eth2"
# if IFACE_WAN6 is not defined it take the value of IFACE_WAN # if IFACE_WAN6 is not defined it take the value of IFACE_WAN
#IFACE_LAN=eth0
#IFACE_WAN=eth1 #IFACE_WAN=eth1
#IFACE_WAN6="ipsec0 wireguard0 he_net" #IFACE_WAN6="ipsec0 wireguard0 he_net"
@@ -132,10 +121,10 @@ FLOWOFFLOAD=none
INIT_APPLY_FW=1 INIT_APPLY_FW=1
# firewall apply hooks # firewall apply hooks
#INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret.hook.pre_up" #INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret2.hook.pre_up"
#INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up" #INIT_FW_POST_UP_HOOK="/etc/firewall.zapret2.hook.post_up"
#INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down" #INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret2.hook.pre_down"
#INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret.hook.post_down" #INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret2.hook.post_down"
# do not work with ipv4 # do not work with ipv4
DISABLE_IPV4=0 DISABLE_IPV4=0
@@ -155,5 +144,5 @@ FILTER_TTL_EXPIRED_ICMP=1
DAEMON_LOG_ENABLE=0 DAEMON_LOG_ENABLE=0
DAEMON_LOG_SIZE_MAX=2000
DAEMON_LOG_FILE="/tmp/zapret+<DAEMON_NAME>+<DAEMON_IDNUM>+<DAEMON_CFGNAME>.log" DAEMON_LOG_FILE="/tmp/zapret2+<DAEMON_NAME>+<DAEMON_IDNUM>+<DAEMON_CFGNAME>.log"

View File

@@ -3,7 +3,7 @@
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22) # NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config : # can override in config :
NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---dpi-desync=fake --dpi-desync-repeats=2}" NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---payload stun --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
alloc_dnum DNUM_STUN4ALL alloc_dnum DNUM_STUN4ALL
alloc_qnum QNUM_STUN4ALL alloc_qnum QNUM_STUN4ALL
@@ -17,14 +17,14 @@ zapret_custom_daemons()
} }
zapret_custom_firewall() zapret_custom_firewall()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local f='-p udp -m u32 --u32' local f='-p udp -m u32 --u32'
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=28:65535&&0>>22&0x3C@12=0x2112A442&&0>>22&0x3C@8&0xC0000003=0" "$f 44>>16=28:65535&&52=0x2112A442&&48&0xC0000003=0" $QNUM_STUN4ALL fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=28:65535&&0>>22&0x3C@12=0x2112A442&&0>>22&0x3C@8&0xC0000003=0" "$f 44>>16=28:65535&&52=0x2112A442&&48&0xC0000003=0" $QNUM_STUN4ALL
} }
zapret_custom_firewall_nft() zapret_custom_firewall_nft()
{ {
# stop logic is not required # stop logic is not required
local f="udp length >= 28 @ih,32,32 0x2112A442 @ih,0,2 0 @ih,30,2 0" local f="udp length >= 28 @ih,32,32 0x2112A442 @ih,0,2 0 @ih,30,2 0"
nft_fw_nfqws_post "$f" "$f" $QNUM_STUN4ALL nft_fw_nfqws_post "$f" "$f" $QNUM_STUN4ALL

View File

@@ -1,10 +1,10 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2024 remittor # Copyright (c) 2025 remittor
function set_cfg_reset_values function set_cfg_reset_values
{ {
local cfgname=${1:-$ZAPRET_CFG_NAME} local cfgname=${1:-$ZAPRET_CFG_NAME}
local TAB="$( printf '\t' )" local TAB="$( echo -n -e '\t' )"
uci batch <<-EOF uci batch <<-EOF
set $cfgname.config.run_on_boot='0' set $cfgname.config.run_on_boot='0'
# settings for zapret service # settings for zapret service
@@ -19,26 +19,29 @@ function set_cfg_reset_values
set $cfgname.config.DISABLE_CUSTOM='1' set $cfgname.config.DISABLE_CUSTOM='1'
set $cfgname.config.WS_USER='daemon' set $cfgname.config.WS_USER='daemon'
set $cfgname.config.DAEMON_LOG_ENABLE='0' set $cfgname.config.DAEMON_LOG_ENABLE='0'
set $cfgname.config.DAEMON_LOG_SIZE_MAX='2000' set $cfgname.config.DAEMON_LOG_FILE='/tmp/zapret2+<DAEMON_NAME>+<DAEMON_IDNUM>+<DAEMON_CFGNAME>.log'
set $cfgname.config.DAEMON_LOG_FILE='/tmp/zapret+<DAEMON_NAME>+<DAEMON_IDNUM>+<DAEMON_CFGNAME>.log'
# autohostlist options # autohostlist options
set $cfgname.config.AUTOHOSTLIST_INCOMING_MAXSEQ='4096'
set $cfgname.config.AUTOHOSTLIST_RETRANS_MAXSEQ='32768'
set $cfgname.config.AUTOHOSTLIST_RETRANS_THRESHOLD='3' set $cfgname.config.AUTOHOSTLIST_RETRANS_THRESHOLD='3'
set $cfgname.config.AUTOHOSTLIST_FAIL_THRESHOLD='3' set $cfgname.config.AUTOHOSTLIST_FAIL_THRESHOLD='3'
set $cfgname.config.AUTOHOSTLIST_FAIL_TIME='60' set $cfgname.config.AUTOHOSTLIST_FAIL_TIME='60'
set $cfgname.config.AUTOHOSTLIST_UDP_IN='1'
set $cfgname.config.AUTOHOSTLIST_UDP_OUT='4'
set $cfgname.config.AUTOHOSTLIST_DEBUGLOG='0' set $cfgname.config.AUTOHOSTLIST_DEBUGLOG='0'
# nfqws options # nfqws options
set $cfgname.config.NFQWS_ENABLE='1' set $cfgname.config.NFQWS2_ENABLE='1'
set $cfgname.config.DESYNC_MARK='0x40000000' set $cfgname.config.DESYNC_MARK='0x40000000'
set $cfgname.config.DESYNC_MARK_POSTNAT='0x20000000' set $cfgname.config.DESYNC_MARK_POSTNAT='0x20000000'
set $cfgname.config.FILTER_MARK='$TAB' set $cfgname.config.FILTER_MARK='$TAB'
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS2_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS2_PORTS_UDP='443'
set $cfgname.config.NFQWS_TCP_PKT_OUT='9' set $cfgname.config.NFQWS2_TCP_PKT_OUT='9'
set $cfgname.config.NFQWS_TCP_PKT_IN='3' set $cfgname.config.NFQWS2_TCP_PKT_IN='3'
set $cfgname.config.NFQWS_UDP_PKT_OUT='9' set $cfgname.config.NFQWS2_UDP_PKT_OUT='9'
set $cfgname.config.NFQWS_UDP_PKT_IN='0' set $cfgname.config.NFQWS2_UDP_PKT_IN='0'
set $cfgname.config.NFQWS_PORTS_TCP_KEEPALIVE='0' set $cfgname.config.NFQWS2_PORTS_TCP_KEEPALIVE='0'
set $cfgname.config.NFQWS_PORTS_UDP_KEEPALIVE='0' set $cfgname.config.NFQWS2_PORTS_UDP_KEEPALIVE='0'
# save changes # save changes
commit $cfgname commit $cfgname
EOF EOF
@@ -48,12 +51,12 @@ function set_cfg_reset_values
function clear_nfqws_strat function clear_nfqws_strat
{ {
local cfgname=${1:-$ZAPRET_CFG_NAME} local cfgname=${1:-$ZAPRET_CFG_NAME}
local TAB="$( printf '\t' )" local TAB="$( echo -n -e '\t' )"
uci batch <<-EOF uci batch <<-EOF
set $cfgname.config.MODE_FILTER='hostlist' set $cfgname.config.MODE_FILTER='hostlist'
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS2_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS2_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT='$TAB' set $cfgname.config.NFQWS2_OPT='$TAB'
commit $cfgname commit $cfgname
EOF EOF
} }
@@ -62,7 +65,7 @@ function set_cfg_nfqws_strat
{ {
local strat=${1:--} local strat=${1:--}
local cfgname=${2:-$ZAPRET_CFG_NAME} local cfgname=${2:-$ZAPRET_CFG_NAME}
local TAB="$( printf '\t' )" local TAB="$( echo -n -e '\t' )"
uci batch <<-EOF uci batch <<-EOF
set $cfgname.config.MODE_FILTER='hostlist' set $cfgname.config.MODE_FILTER='hostlist'
@@ -71,353 +74,31 @@ function set_cfg_nfqws_strat
if [ "$strat" = "empty" ]; then if [ "$strat" = "empty" ]; then
clear_nfqws_strat $cfgname clear_nfqws_strat $cfgname
fi fi
if [ "$strat" = "v1_by_StressOzz" ]; then if [ "$strat" = "default" ]; then
uci batch <<-EOF uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS2_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS2_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS2_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 <HOSTLIST> --filter-tcp=80
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --filter-l7=http <HOSTLIST>
--dpi-desync=fake,multidisorder --payload=http_req
--dpi-desync-split-seqovl=681 --lua-desync=fake:blob=fake_default_http:tcp_md5
--dpi-desync-split-pos=1 --lua-desync=multisplit:pos=method+2
--dpi-desync-fooling=badseq
--dpi-desync-badseq-increment=10000000
--dpi-desync-repeats=2
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--dpi-desync-fake-tls-mod=rnd,dupsid,sni=fonts.google.com
--new --new
--filter-udp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--dpi-desync=fake
--dpi-desync-repeats=6
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
"
commit $cfgname
EOF
fi
if [ "$strat" = "v2_by_StressOzz" ]; then
uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat
--filter-tcp=443 <HOSTLIST>
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude-domains=openwrt.org
--dpi-desync=fake,fakeddisorder
--dpi-desync-split-pos=10,midsld
--dpi-desync-fake-tls=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--dpi-desync-fake-tls-mod=rnd,dupsid,sni=fonts.google.com
--dpi-desync-fake-tls=0x0F0F0F0F
--dpi-desync-fake-tls-mod=none
--dpi-desync-fakedsplit-pattern=/opt/zapret/files/fake/tls_clienthello_vk_com.bin
--dpi-desync-split-seqovl=336
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_gosuslugi_ru.bin
--dpi-desync-fooling=badseq,badsum
--dpi-desync-badseq-increment=0
--new
--filter-udp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--dpi-desync=fake
--dpi-desync-repeats=6
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
"
commit $cfgname
EOF
fi
if [ "$strat" = "v3_by_StressOzz" ]; then
uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat
--filter-tcp=443 <HOSTLIST>
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude-domains=openwrt.org
--dpi-desync=fake,fakeddisorder
--dpi-desync-split-pos=10,midsld
--dpi-desync-fake-tls=/opt/zapret/files/fake/t2.bin
--dpi-desync-fake-tls-mod=rnd,dupsid,sni=m.ok.ru
--dpi-desync-fake-tls=0x0F0F0F0F
--dpi-desync-fake-tls-mod=none
--dpi-desync-fakedsplit-pattern=/opt/zapret/files/fake/tls_clienthello_vk_com.bin
--dpi-desync-split-seqovl=336
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_gosuslugi_ru.bin
--dpi-desync-fooling=badseq,badsum
--dpi-desync-badseq-increment=0
--new
--filter-udp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--dpi-desync=fake
--dpi-desync-repeats=6
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
"
commit $cfgname
EOF
fi
if [ "$strat" = "v4_by_StressOzz" ]; then
uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat
--filter-tcp=443 --filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --filter-l7=tls <HOSTLIST>
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt --payload=tls_client_hello
--hostlist-exclude-domains=openwrt.org --lua-desync=fake:blob=fake_default_tls:tcp_md5:tcp_seq=-10000
--dpi-desync=fake,multisplit --lua-desync=multidisorder:pos=1,midsld
--dpi-desync-split-pos=2,sld
--dpi-desync-fake-tls=0x0F0F0F0F
--dpi-desync-fake-tls=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--dpi-desync-fake-tls-mod=rnd,dupsid,sni=google.com
--dpi-desync-split-seqovl=2108
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--dpi-desync-fooling=badseq
--new
--filter-tcp=443 <HOSTLIST>
--hostlist-exclude-domains=openwrt.org
--dpi-desync-any-protocol=1
--dpi-desync-cutoff=n5
--dpi-desync=multisplit
--dpi-desync-split-seqovl=582
--dpi-desync-split-pos=1
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/4pda.bin
--new --new
--filter-udp=443 --filter-udp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --filter-l7=quic <HOSTLIST_NOAUTO>
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt --payload=quic_initial
--dpi-desync=fake --lua-desync=fake:blob=fake_default_quic:repeats=6
--dpi-desync-repeats=6
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
"
commit $cfgname
EOF
fi
if [ "$strat" = "v5_by_StressOzz" ]; then
uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat
--filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--hostlist-exclude-domains=openwrt.org
--ip-id=zero
--dpi-desync=multisplit
--dpi-desync-split-seqovl=681
--dpi-desync-split-pos=1
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--new
--filter-tcp=443 <HOSTLIST>
--hostlist-exclude-domains=openwrt.org
--dpi-desync=fake,fakeddisorder
--dpi-desync-split-pos=10,midsld
--dpi-desync-fake-tls=/opt/zapret/files/fake/max.bin
--dpi-desync-fake-tls-mod=rnd,dupsid
--dpi-desync-fake-tls=0x0F0F0F0F
--dpi-desync-fake-tls-mod=none
--dpi-desync-fakedsplit-pattern=/opt/zapret/files/fake/tls_clienthello_vk_com.bin
--dpi-desync-fooling=badseq,badsum
--dpi-desync-badseq-increment=0
--new
--filter-udp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--dpi-desync=fake
--dpi-desync-repeats=6
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
"
commit $cfgname
EOF
fi
if [ "$strat" = "v6_by_StressOzz" ]; then
uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443,2053,2083,2087,2096,8443'
set $cfgname.config.NFQWS_PORTS_UDP='443,19294-19344,50000-50100'
set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat
--filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--dpi-desync=multisplit
--dpi-desync-split-pos=1,sniext+1
--dpi-desync-split-seqovl=1
--new
--filter-tcp=443 <HOSTLIST>
--dpi-desync=hostfakesplit
--dpi-desync-hostfakesplit-mod=host=rzd.ru
--dpi-desync-hostfakesplit-midhost=host-2
--dpi-desync-split-seqovl=726
--dpi-desync-fooling=badsum,badseq
--dpi-desync-badseq-increment=0
--new
--filter-udp=443 <HOSTLIST_NOAUTO>
--dpi-desync=fake
--dpi-desync-repeats=6
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
--new
--filter-udp=19294-19344,50000-50100
--filter-l7=discord,stun
--dpi-desync=fake
--dpi-desync-repeats=6
--new
--filter-tcp=2053,2083,2087,2096,8443
--hostlist-domains=discord.media
--dpi-desync=multisplit
--dpi-desync-split-seqovl=652
--dpi-desync-split-pos=2
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
"
commit $cfgname
EOF
fi
if [ "$strat" = "v7_by_StressOzz" ]; then
uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443,2053,2083,2087,2096,8443'
set $cfgname.config.NFQWS_PORTS_UDP='443,19294-19344,50000-50100'
set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat
--filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--dpi-desync=fake,multisplit
--dpi-desync-split-pos=2,sld
--dpi-desync-fake-tls=0x0F0F0F0F
--dpi-desync-fake-tls=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--dpi-desync-fake-tls-mod=rnd,dupsid,sni=ggpht.com
--dpi-desync-split-seqovl=620
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--dpi-desync-fooling=badsum,badseq
--new
--filter-tcp=443 <HOSTLIST>
--dpi-desync=fake,multisplit
--dpi-desync-split-seqovl=654
--dpi-desync-split-pos=1
--dpi-desync-fooling=ts
--dpi-desync-repeats=8
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/max.bin
--dpi-desync-fake-tls=/opt/zapret/files/fake/max.bin
--new
--filter-udp=443 <HOSTLIST_NOAUTO>
--dpi-desync=fake
--dpi-desync-repeats=6
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
--new
--filter-udp=19294-19344,50000-50100
--filter-l7=discord,stun
--dpi-desync=fake
--dpi-desync-repeats=6
--new
--filter-tcp=2053,2083,2087,2096,8443
--hostlist-domains=discord.media
--dpi-desync=multisplit
--dpi-desync-split-seqovl=652
--dpi-desync-split-pos=2
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
"
commit $cfgname
EOF
fi
if [ "$strat" = "ALT7_by_Flowseal" ]; then
uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat
--filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--hostlist-exclude-domains=openwrt.org
--ip-id=zero
--dpi-desync=multisplit
--dpi-desync-split-pos=2,sniext+1
--dpi-desync-split-seqovl=679
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--new
--filter-tcp=80,443 <HOSTLIST>
--hostlist-exclude-domains=openwrt.org
--dpi-desync=multisplit
--dpi-desync-split-pos=2,sniext+1
--dpi-desync-split-seqovl=679
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--new
--filter-udp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--dpi-desync=fake
--dpi-desync-repeats=6
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
"
commit $cfgname
EOF
fi
if [ "$strat" = "TLS_AUTO_ALT3_by_Flowseal" ]; then
uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat
--filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--hostlist-exclude-domains=openwrt.org
--ip-id=zero
--dpi-desync=fake,multisplit
--dpi-desync-split-seqovl=681
--dpi-desync-split-pos=1
--dpi-desync-fooling=ts
--dpi-desync-repeats=8
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--dpi-desync-fake-tls-mod=rnd,dupsid,sni=www.google.com
--new
--filter-tcp=80,443 <HOSTLIST>
--hostlist-exclude-domains=openwrt.org
--dpi-desync=fake,multisplit
--dpi-desync-split-seqovl=681
--dpi-desync-split-pos=1
--dpi-desync-fooling=ts
--dpi-desync-repeats=8
--dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin
--dpi-desync-fake-tls-mod=rnd,dupsid,sni=www.google.com
--new
--filter-udp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
--hostlist-exclude=/opt/zapret/ipset/zapret-hosts-user-exclude.txt
--dpi-desync=fake
--dpi-desync-repeats=11
--dpi-desync-fake-quic=/opt/zapret/files/fake/quic_initial_www_google_com.bin
" "
commit $cfgname commit $cfgname
EOF EOF
@@ -428,7 +109,7 @@ function set_cfg_nfqws_strat
function set_cfg_default_values function set_cfg_default_values
{ {
local opt_flags=${1:--} local opt_flags=${1:--}
local opt_strat=${2:-v6_by_StressOzz} local opt_strat=${2:-default}
local cfgname=${3:-$ZAPRET_CFG_NAME} local cfgname=${3:-$ZAPRET_CFG_NAME}
if ! echo "$opt_flags" | grep -q "(skip_base)"; then if ! echo "$opt_flags" | grep -q "(skip_base)"; then
@@ -443,17 +124,5 @@ function set_cfg_default_values
commit $cfgname commit $cfgname
EOF EOF
fi fi
if echo "$opt_flags" | grep -q "(enable_custom_d)"; then
uci batch <<-EOF
set $cfgname.config.DISABLE_CUSTOM='0'
commit $cfgname
EOF
fi
if echo "$opt_flags" | grep -q "(disable_custom_d)"; then
uci batch <<-EOF
set $cfgname.config.DISABLE_CUSTOM='1'
commit $cfgname
EOF
fi
return 0 return 0
} }

View File

@@ -1,308 +0,0 @@
#!/bin/sh
# Copyright (c) 2026 remittor
ZAP_TMP_DIR=/tmp/zapret_dwc
opt_sites=
opt_dig=
opt_recom=
opt_tmp_dir=
opt_test=
while getopts "sd:RT:t" opt; do
case $opt in
s) opt_sites="true";;
d) opt_dig="$OPTARG";;
R) opt_recom="true";; # Recommendations
T) opt_tmp_dir="$OPTARG";;
t) opt_test="true";;
esac
done
[ "$opt_tmp_dir" != "" ] && ZAP_TMP_DIR="$opt_tmp_dir"
TARGET_LIST_FILE="$ZAP_TMP_DIR/targets"
[ -f "$TARGET_LIST_FILE" ] && rm -rf "$ZAP_TMP_DIR"
[ -f "$TARGET_LIST_FILE" ] && exit 3
CURL_TIMEOUT=5
CURL_MAXBODY=65536
CURL_NOCACHE='cache-control: no-cache'
CURL_NOCACHE2='pragma: no-cache'
CURL_USERAGENT='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36'
if ! command -v curl >/dev/null 2>&1; then
echo "ERROR: package \"curl\" not installed!"
return 10
fi
CURL_INFO=$( curl -V )
if ! echo "$CURL_INFO" | grep -q 'https'; then
echo "------- package curl"
echo "$CURL_INFO"
echo "-------"
echo "ERROR: package \"curl\" not supported HTTPS protocol!"
echo "NOTE: Please install package \"curl-ssl\""
return 11
fi
if [ "$opt_dig" != "" ]; then
if ! command -v dig >/dev/null 2>&1; then
echo "ERROR: package \"bind-dig\" not installed!"
return 12
fi
OPT_DIG_DNS="@$opt_dig"
[ "$opt_dig" = "@" ] && OPT_DIG_DNS=''
[ "$opt_dig" = "8" ] && OPT_DIG_DNS='@8.8.8.8'
[ "$opt_dig" = "1" ] && OPT_DIG_DNS='@1.1.1.1'
[ "$opt_dig" = "9" ] && OPT_DIG_DNS='@9.9.9.9'
fi
if [ -f /etc/openwrt_release ]; then
CA_CERTS=/etc/ssl/certs/ca-certificates.crt
if [ ! -f $CA_CERTS ]; then
echo "ERROR: package \"ca-bundle\" not installed!"
return 15
fi
fi
#echo 'Original sources: https://github.com/hyperion-cs/dpi-checkers'
#echo 'WEB-version: https://hyperion-cs.github.io/dpi-checkers/ru/tcp-16-20/'
TEST_SUITE='
{ id: "US.CF-01", provider: "🇺🇸 Cloudflare", times: 1, url: "https://img.wzstats.gg/cleaver/gunFullDisplay" },
{ id: "US.CF-02", provider: "🇺🇸 Cloudflare", times: 1, url: "https://genshin.jmp.blue/characters/all#" },
{ id: "US.CF-03", provider: "🇺🇸 Cloudflare", times: 1, url: "https://api.frankfurter.dev/v1/2000-01-01..2002-12-31" },
{ id: "US.CF-04", provider: "🇨🇦 Cloudflare", times: 1, url: "https://www.bigcartel.com/" },
{ id: "US.DO-01", provider: "🇺🇸 DigitalOcean", times: 2, url: "https://genderize.io/" },
{ id: "DE.HE-01", provider: "🇩🇪 Hetzner", times: 1, url: "https://j.dejure.org/jcg/doctrine/doctrine_banner.webp" },
{ id: "DE.HE-02", provider: "🇩🇪 Hetzner", times: 1, url: "https://maps.gnosis.earth/ogcapi/api/swagger-ui/swagger-ui-standalone-preset.js#" },
{ id: "FI.HE-01", provider: "🇫🇮 Hetzner", times: 1, url: "https://251b5cd9.nip.io/1MB.bin" },
{ id: "FI.HE-02", provider: "🇫🇮 Hetzner", times: 1, url: "https://nioges.com/libs/fontawesome/webfonts/fa-solid-900.woff2" },
{ id: "FI.HE-03", provider: "🇫🇮 Hetzner", times: 1, url: "https://5fd8bdae.nip.io/1MB.bin" },
{ id: "FI.HE-04", provider: "🇫🇮 Hetzner", times: 1, url: "https://5fd8bca5.nip.io/1MB.bin" },
{ id: "FR.OVH-01", provider: "🇫🇷 OVH", times: 1, url: "https://eu.api.ovh.com/console/rapidoc-min.js" },
{ id: "FR.OVH-02", provider: "🇫🇷 OVH", times: 1, url: "https://ovh.sfx.ovh/10M.bin" },
{ id: "SE.OR-01", provider: "🇸🇪 Oracle", times: 1, url: "https://oracle.sfx.ovh/10M.bin" },
{ id: "DE.AWS-01", provider: "🇩🇪 AWS", times: 1, url: "https://www.getscope.com/assets/fonts/fa-solid-900.woff2" },
{ id: "US.AWS-01", provider: "🇺🇸 AWS", times: 1, url: "https://corp.kaltura.com/wp-content/cache/min/1/wp-content/themes/airfleet/dist/styles/theme.css" },
{ id: "US.GC-01", provider: "🇺🇸 Google Cloud", times: 1, url: "https://api.usercentrics.eu/gvl/v3/en.json" },
{ id: "US.FST-01", provider: "🇺🇸 Fastly", times: 1, url: "https://www.jetblue.com/footer/footer-element-es2015.js" },
{ id: "CA.FST-01", provider: "🇨🇦 Fastly", times: 1, url: "https://www.cnn10.com/" },
{ id: "US.AKM-01", provider: "🇺🇸 Akamai", times: 1, url: "https://www.roxio.com/static/roxio/images/products/creator/nxt9/call-action-footer-bg.jpg" },
{ id: "PL.AKM-01", provider: "🇵🇱 Akamai", times: 1, url: "https://media-assets.stryker.com/is/image/stryker/gateway_1?$max_width_1410$" },
{ id: "US.CDN77-01", provider: "🇺🇸 CDN77", times: 1, url: "https://cdn.eso.org/images/banner1920/eso2520a.jpg" },
{ id: "FR.CNTB-01", provider: "🇫🇷 Contabo", times: 1, url: "https://airsea.no/images/main_logo.png" },
{ id: "NL.SW-01", provider: "🇳🇱 Scaleway", times: 1, url: "https://www.velivole.fr/img/header.jpg" },
{ id: "US.CNST-01", provider: "🇺🇸 Constant", times: 1, url: "https://cdn.xuansiwei.com/common/lib/font-awesome/4.7.0/fontawesome-webfont.woff2?v=4.7.0" }
'
if [ "$opt_sites" = true ]; then
TEST_SUITE='
gosuslugi.ru | @ | 40000 | https://gosuslugi.ru/__jsch/static/script.js
esia.gosuslugi.ru | @ | 40000 | https://esia.gosuslugi.ru/__jsch/static/script.js
gu-st.ru | | | https://gu-st.ru/portal-st/lib-assets/fonts/Lato-Regular-v3.woff2
nalog.ru | | | https://data.nalog.ru/images/new/buttons/TSET-button.png
lkfl2.nalog.ru | | | https://lkfl2.nalog.ru/lkfl/static/assets/main-desktop-1920-CvJsHANg.jpg
rutube.ru | @ | 40000 | https://static.rutube.ru/static/wdp/fonts/Semibold/OpenSans-Semibold.woff2?20231026
youtube.com | @# | 300000 | https://youtube.com
instagram.com | @# | 300000 | https://instagram.com
rutracker.org | @# | 80000 | https://rutracker.org
nnmclub.to | @# | 120000 | https://nnmclub.to
rutor.info | @# | 110000 | https://rutor.info
epidemz.net.co | @# | 40000 | https://epidemz.net.co
filmix.my | @ | 23000 | https://filmix.my/templates/Filmix/media/fonts/Roboto/roboto-v20-latin_cyrillic-italic.woff2
openwrt.org | + | 60000 | https://openwrt.org/lib/tpl/bootstrap3/assets/bootstrap/default/bootstrap.min.css
ntc.party | @# | 200000 | https://ntc.party
sxyprn.net | @# | 310000 | https://sxyprn.net
pornhub.com | @# | 700000 | https://pornhub.com
spankbang.com | @# | 80000 | https://spankbang.com
discord.com | @# | 120000 | https://discord.com
x.com | @ | 39000 | https://abs.twimg.com/fonts/v1/chirp-extended-heavy-web.woff2
flightradar24.com | @ | 100000 | https://www.flightradar24.com/mobile/airlines?format=2&version=0
cdn77.com | @ | 24000 | https://cdn77.com/fonts/Eina01-Regular.woff2
play.google.com | @# | 100000 | https://gstatic.com/feedback/js/help/prod/service/lazy.min.js
genderize.io | @# | 210000 | https://genderize.io
ottai.com | @ | 70000 | https://seas.static.ottai.com/ottai-website/public/images/new/home/banner/uk/banner.webp
'
CURL_TIMEOUT=7
fi
function trim
{
echo "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
}
mkdir -p "$ZAP_TMP_DIR"
: > "$TARGET_LIST_FILE"
IDX=0
while IFS= read -r line; do
if [ "$opt_sites" = true ]; then
echo -n "$line" | grep -q ' | http' || continue
IDX=$((IDX + 1))
TAG=$( printf '%s\n' "$line" | cut -d'|' -f1 | awk '{$1=$1;print}' )
FLAGS=$( printf '%s\n' "$line" | cut -d'|' -f2 | awk '{$1=$1;print}' )
TSIZE=$( printf '%s\n' "$line" | cut -d'|' -f3 | awk '{$1=$1;print}' )
URL=$( printf '%s\n' "$line" | cut -d'|' -f4 | awk '{$1=$1;print}' )
COUNTRY="XX"
echo "${IDX}|${TAG}|${COUNTRY}|${FLAGS}|${TSIZE}|${URL}" >> "$TARGET_LIST_FILE"
continue
fi
case "$line" in
*id:*provider:*url:*)
IDX=$((IDX + 1))
TAG=$( printf '%s\n' "$line" | cut -d'"' -f2 )
COUNTRY="${TAG%%.*}"
PROVIDER_RAW=$( printf '%s\n' "$line" | cut -d'"' -f4 )
PROVIDER="${PROVIDER_RAW#* }"
TIMES=$( printf '%s\n' "$line" | cut -d':' -f4 | cut -d',' -f1 | tr -d ' ')
URL=$( printf '%s\n' "$line" | cut -d'"' -f6 )
echo "${IDX}|${TAG}|${COUNTRY}|${PROVIDER}|${TIMES}|${URL}" >> "$TARGET_LIST_FILE"
;;
esac
done <<EOF
$TEST_SUITE
EOF
CURL_CON_TIMEOUT=$((CURL_TIMEOUT-2))
CURL_SPEED_TIME=$((CURL_TIMEOUT-2))
CURL_SPEED_LIMIT=1
while IFS='|' read -r ID TAG COUNTRY PROVIDER TIMES URL; do
[ -z "$TAG" ] && continue
ID3=$( printf '%03d' "$ID" )
RANGETO=""
REDIRECT=""
USERAGENT="$CURL_USERAGENT"
if [ "$opt_sites" = true ]; then
FLAGS="$PROVIDER"
TSIZE="$TIMES"
[ "$TSIZE" = "" ] && TSIZE=$CURL_MAXBODY
if echo "$FLAGS" | grep -q '@'; then
RANGETO=""
else
RANGETO="--range 0-$((TSIZE - 1))"
fi
PROVIDER="$TSIZE"
if echo "$FLAGS" | grep -q '#'; then
REDIRECT="-L"
fi
if echo "$FLAGS" | grep -q '+'; then
USERAGENT="curl/8.12"
fi
else
RANGETO="--range 0-$((CURL_MAXBODY - 1))"
COUNTRY=$( echo "$TAG" | cut -d. -f1 )
CNTFLAG=$( echo "$PROVIDER" | awk '{print $1}' )
fi
URL_NO_PROTO="${URL#*://}"
DOMAIN="${URL_NO_PROTO%%/*}"
URLPATH="/${URL_NO_PROTO#*/}"
[ "$URLPATH" = "/$URL_NO_PROTO" ] && URLPATH="/"
#echo "TAG=$TAG , COUNTRY=$COUNTRY , PROVIDER=$PROVIDER , DOMAIN=$DOMAIN , URL=$URL"
FNAME="$ZAP_TMP_DIR/$ID3=$TAG=$PROVIDER"
(
DST_IP=
RESOLVE_OPT=
if [ "$opt_dig" != "" ]; then
DST_IP=$( dig +time=2 +retry=1 $OPT_DIG_DNS +short "$DOMAIN" 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -n1 )
else
CURL_TIMEOUTS="--connect-timeout 2 --max-time 3 --speed-time 3 --speed-limit 1"
DST_IP=$( curl -4 -I -s $CURL_TIMEOUTS -o /dev/null -w '%{remote_ip}\n' "$URL" )
if [ -z "$DST_IP" ]; then
DST_IP=$( curl -4 -s $CURL_TIMEOUTS -o /dev/null -r 0-0 -w '%{remote_ip}\n' "$URL" )
fi
fi
if [ "$DST_IP" = "" ]; then
DST_IP=$( ping -c1 "$DOMAIN" 2>/dev/null | sed -n '1s/.*(\([0-9.]*\)).*/\1/p' )
fi
[ "$DST_IP" != "" ] && RESOLVE_OPT="--resolve $DOMAIN:443:$DST_IP"
echo "$DST_IP" > "$FNAME.ip"
echo "$URL" > "$FNAME.url"
curl "$URL" \
$RESOLVE_OPT \
$REDIRECT \
--connect-timeout $CURL_CON_TIMEOUT \
--max-time $CURL_TIMEOUT \
--speed-time $CURL_SPEED_TIME \
--speed-limit $CURL_SPEED_LIMIT \
$RANGETO \
-A "$USERAGENT" \
-D "$FNAME.hdr" \
-o "$FNAME.body"
) > "$FNAME.log" 2>&1 &
done < "$TARGET_LIST_FILE"
wait
FAIL_URL_LIST="$ZAP_TMP_DIR/FAIL_URL_LIST.txt"
rm -f "$FAIL_URL_LIST"
printf '%s\n' "$ZAP_TMP_DIR"/*.log | sort | while IFS= read -r file; do
[ -f "$file" ] || continue
FILENAME="${file##*/}"
FILENAME="${FILENAME%.log}"
ID=$( echo "$FILENAME" | cut -d= -f1)
TAG=$( echo "$FILENAME" | cut -d= -f2)
PROVIDER=$(echo "$FILENAME" | cut -d= -f3 )
FNAME="$ZAP_TMP_DIR/$FILENAME"
REQ_SIZE=$CURL_MAXBODY
[ "$opt_sites" = true ] && REQ_SIZE="$PROVIDER"
BODY_SIZE=0
[ -f "$FNAME.body" ] && BODY_SIZE=$( wc -c < "$FNAME.body" )
IPADDR="x.x.x.x"
[ -s "$FNAME.ip" ] && IPADDR=$( cat "$FNAME.ip" )
res=0
status=
if [ ! -f "$FNAME.hdr" ]; then
status="ERROR: cannot Get Headers"
elif [ ! -s "$FNAME.hdr" ]; then
status="ERROR: cannot get headers"
elif [ ! -f "$FNAME.body" ]; then
status="Possibly detected*"
elif [ ! -s "$FNAME.body" ]; then
status="Possibly detected"
else
if [ $BODY_SIZE -lt $REQ_SIZE ]; then
status="Failed (recv $BODY_SIZE bytes)"
res=5
else
status="[ OK ]"
res=100
fi
fi
if [ "$opt_sites" = true ]; then
printf '%18s / %-15s : %s \n' "$TAG" "$IPADDR" "$status"
else
printf '%12s / %-15s / %-13s: %s \n' "$TAG" "$IPADDR" "$PROVIDER" "$status"
fi
echo "$BODY_SIZE" > "$FNAME.size"
if [ $res != 100 ]; then
URL=$( cat "$FNAME.url" )
echo "$FILENAME : $URL" >> "$FAIL_URL_LIST"
fi
done
if [ "$opt_test" != true ]; then
rm -f "$ZAP_TMP_DIR"/*.body >/dev/null 2>&1
fi
[ "$opt_recom" != "true" ] && return 0
[ ! -f "$FAIL_URL_LIST" ] && return 0
echo "==================================================="
echo "Recommendations:"
echo "Try adding the specified domains to the \"zapret-hosts-user.txt\" file:"
while IFS=' : ' read -r FILENAME URL; do
[ -z "$FILENAME" ] && continue
URL_NO_PROTO="${URL#*://}"
DOMAIN="${URL_NO_PROTO%%/*}"
URLPATH="/${URL_NO_PROTO#*/}"
[ "$URLPATH" = "/$URL_NO_PROTO" ] && URLPATH="/"
echo "$DOMAIN"
done < "$FAIL_URL_LIST"
return 0

View File

@@ -7,17 +7,17 @@ START=21
SCRIPT_FILENAME=$1 SCRIPT_FILENAME=$1
. /opt/zapret/comfunc.sh . /opt/zapret2/comfunc.sh
if ! is_valid_config ; then if ! is_valid_config ; then
logger -p err -t $ZAP_LOG_TAG "Wrong main config: $ZAPRET_CONFIG" logger -p err -t ZAPRET2 "Wrong main config: $ZAPRET_CONFIG"
exit 91 exit 91
fi fi
. $ZAPRET_ORIG_INITD . $ZAPRET_ORIG_INITD
EXEDIR=/opt/$ZAPRET_CFG_NAME EXEDIR=/opt/zapret2
ZAPRET_BASE=/opt/$ZAPRET_CFG_NAME ZAPRET_BASE=/opt/zapret2
is_run_on_boot && IS_RUN_ON_BOOT=1 || IS_RUN_ON_BOOT=0 is_run_on_boot && IS_RUN_ON_BOOT=1 || IS_RUN_ON_BOOT=0
@@ -30,13 +30,13 @@ function enable
if [ -n "$ZAPRET_CFG_SEC_NAME" ]; then if [ -n "$ZAPRET_CFG_SEC_NAME" ]; then
run_on_boot=$( get_run_on_boot_option ) run_on_boot=$( get_run_on_boot_option )
if [ $run_on_boot != 1 ]; then if [ $run_on_boot != 1 ]; then
logger -p notice -t $ZAP_LOG_TAG "Attempt to enable service, but service blocked!" logger -p notice -t ZAPRET2 "Attempt to enable service, but service blocked!"
return 61 return 61
fi fi
fi fi
fi fi
if [ -n "$ZAPRET_CFG_SEC_NAME" ]; then if [ -n "$ZAPRET_CFG_SEC_NAME" ]; then
uci set $ZAPRET_CFG_SEC.run_on_boot=1 uci set $ZAPRET_CFG_NAME.config.run_on_boot=1
uci commit uci commit
fi fi
/bin/sh /etc/rc.common $ZAPRET_ORIG_INITD enable /bin/sh /etc/rc.common $ZAPRET_ORIG_INITD enable
@@ -49,7 +49,7 @@ function enabled
run_on_boot=$( get_run_on_boot_option ) run_on_boot=$( get_run_on_boot_option )
if [ $run_on_boot != 1 ]; then if [ $run_on_boot != 1 ]; then
if [ "$IS_RUN_ON_BOOT" = "1" ]; then if [ "$IS_RUN_ON_BOOT" = "1" ]; then
logger -p notice -t $ZAP_LOG_TAG "Service is blocked!" logger -p notice -t ZAPRET2 "Service is blocked!"
fi fi
return 61 return 61
fi fi
@@ -65,23 +65,23 @@ function boot
if [ -n "$ZAPRET_CFG_SEC_NAME" ]; then if [ -n "$ZAPRET_CFG_SEC_NAME" ]; then
run_on_boot=$( get_run_on_boot_option ) run_on_boot=$( get_run_on_boot_option )
if [ $run_on_boot != 1 ]; then if [ $run_on_boot != 1 ]; then
logger -p notice -t $ZAP_LOG_TAG "Attempt to run service on boot! Service is blocked!" logger -p notice -t ZAPRET2 "Attempt to run service on boot! Service is blocked!"
return 61 return 61
fi fi
fi fi
fi fi
init_before_start "$DAEMON_LOG_ENABLE" "$DAEMON_LOG_SIZE_MAX" init_before_start "$DAEMON_LOG_ENABLE"
/bin/sh /etc/rc.common $ZAPRET_ORIG_INITD start "$@" /bin/sh /etc/rc.common $ZAPRET_ORIG_INITD start "$@"
} }
function start function start
{ {
init_before_start "$DAEMON_LOG_ENABLE" "$DAEMON_LOG_SIZE_MAX" init_before_start "$DAEMON_LOG_ENABLE"
/bin/sh /etc/rc.common $ZAPRET_ORIG_INITD start "$@" /bin/sh /etc/rc.common $ZAPRET_ORIG_INITD start "$@"
} }
function restart function restart
{ {
init_before_start "$DAEMON_LOG_ENABLE" "$DAEMON_LOG_SIZE_MAX" init_before_start "$DAEMON_LOG_ENABLE"
/bin/sh /etc/rc.common $ZAPRET_ORIG_INITD restart "$@" /bin/sh /etc/rc.common $ZAPRET_ORIG_INITD restart "$@"
} }

View File

@@ -11,14 +11,10 @@ fe80::/10
nalog.ru nalog.ru
gstatic.com gstatic.com
gosuslugi.ru gosuslugi.ru
mos.ru
mos-gorsud.ru mos-gorsud.ru
gov.ru gov.ru
sudrf.ru sudrf.ru
ottai.com
ipstream.one ipstream.one
vkusvill.ru
kinopoisk.ru
#################################### Epicgames #################################### Epicgames
easy.ac easy.ac
fab.com fab.com
@@ -40,14 +36,45 @@ cubicmotion.com
playparagon.com playparagon.com
realityscan.com realityscan.com
epicgamescdn.com epicgamescdn.com
et.epicgames.com
ol.epicgames.com
radgametools.com radgametools.com
unrealengine.com unrealengine.com
api.epicgames.dev
easyanticheat.net easyanticheat.net
shadowcomplex.com shadowcomplex.com
battlebreakers.com battlebreakers.com
store.epicgames.com
capturingreality.com capturingreality.com
unrealtournament.com unrealtournament.com
cdn1.unrealengine.com
cdn2.unrealengine.com
accounts.epicgames.com
download.epicgames.com
tracking.epicgames.com
download2.epicgames.com
download3.epicgames.com
download4.epicgames.com
metrics.ol.epicgames.com
datarouter.ol.epicgames.com
fastly-download.epicgames.com
store-content.ak.epicgames.com
static-assets-prod.epicgames.com
epicgames-download1.akamaized.net epicgames-download1.akamaized.net
launcher-website-prod07.ol.epicgames.com
ut-public-service-prod10.ol.epicgames.com
store-site-backend-static.ak.epicgames.com
library-service.live.use1a.on.epicgames.com
accountportal-website-prod07.ol.epicgames.com
account-public-service-prod03.ol.epicgames.com
catalog-public-service-prod06.ol.epicgames.com
friends-public-service-prod06.ol.epicgames.com
launcher-public-service-prod06.ol.epicgames.com
entitlement-public-service-prod08.ol.epicgames.com
lightswitch-public-service-prod06.ol.epicgames.com
orderprocessor-public-service-ecomprod01.ol.epicgames.com
launcherwaitingroom-public-service-prod06.ol.epicgames.com
datastorage-public-service-liveegs.live.use1a.on.epicgames.com
#################################### Steam #################################### Steam
s.team s.team
steam.tv steam.tv
@@ -75,49 +102,99 @@ valvesoftware.net
steam.cdn.webra.ru steam.cdn.webra.ru
steambroadcast.com steambroadcast.com
steamcommunity.com steamcommunity.com
cdn.steamstatic.com
cs.steampowered.com
dl.steam.clngaa.com dl.steam.clngaa.com
steam.ru.qtlglb.com steam.ru.qtlglb.com
api.steampowered.com
steam.eca.qtlglb.com steam.eca.qtlglb.com
steamusercontent.com steamusercontent.com
help.steampowered.com
steam.apac.qtlglb.com steam.apac.qtlglb.com
steam.naeu.qtlglb.com steam.naeu.qtlglb.com
cdn.steamcommunity.com cdn.steamcommunity.com
gstore.val.manlaxy.com gstore.val.manlaxy.com
login.steampowered.com
media.steampowered.com
partner.steamgames.com partner.steamgames.com
shared.steamstatic.com
steam.cdn.orcon.net.nz steam.cdn.orcon.net.nz
store.steampowered.com
steamcdn-a.akamaihd.net steamcdn-a.akamaihd.net
steampipe.akamaized.net steampipe.akamaized.net
partner.steampowered.com
steamcdn-a.akamaized.net steamcdn-a.akamaized.net
steamdeckusercontent.com steamdeckusercontent.com
support.steampowered.com
checkout.steampowered.com
community.steamstatic.com
steam.cdn.slingshot.co.nz steam.cdn.slingshot.co.nz
steammobile.akamaized.net steammobile.akamaized.net
steamstatic.akamaized.net steamstatic.akamaized.net
steamstore-a.akamaihd.net steamstore-a.akamaihd.net
steamvideo-a.akamaihd.net steamvideo-a.akamaihd.net
workshop.steampowered.com
cdn.akamai.steamstatic.com
cdn.fastly.steamstatic.com
client-update.queniuqe.com client-update.queniuqe.com
community.steampowered.com
steamdeckcdn.akamaized.net steamdeckcdn.akamaized.net
steampipe-kr.akamaized.net steampipe-kr.akamaized.net
clan.fastly.steamstatic.com
steamcontent-a.akamaihd.net steamcontent-a.akamaihd.net
steambroadcast.akamaized.net steambroadcast.akamaized.net
steamcommunity.akamaized.net steamcommunity.akamaized.net
store.akamai.steamstatic.com
store.fastly.steamstatic.com
scontent.steamusercontent.com scontent.steamusercontent.com
shared.fastly.steamstatic.com
steamcommunity-a.akamaihd.net steamcommunity-a.akamaihd.net
avatars.fastly.steamstatic.com
cdn.cloudflare.steamstatic.com
edge.steam-dns.top.comcast.net edge.steam-dns.top.comcast.net
steamcommunity-a.akamaized.net steamcommunity-a.akamaized.net
steamuserimages-a.akamaihd.net steamuserimages-a.akamaihd.net
steampipe-partner.akamaized.net steampipe-partner.akamaized.net
steamusercontent-a.akamaihd.net steamusercontent-a.akamaihd.net
client-download.steampowered.com
community.fastly.steamstatic.com
store.cloudflare.steamstatic.com
community.cloudflare.steamstatic.com
steamcdn-a.akamaihd.net.edgesuite.net steamcdn-a.akamaihd.net.edgesuite.net
steamcloudsweden.blob.core.windows.net steamcloudsweden.blob.core.windows.net
steamcommunity.cloudflare.steamstatic.com
steamcommunity-a.akamaihd.net.edgesuite.net steamcommunity-a.akamaihd.net.edgesuite.net
#################################### OpenWRT #################################### OpenWRT
github.com
openwrt.org openwrt.org
gh.openwrt.org
cdn.openwrt.org
dev.openwrt.org
git.openwrt.org
lede-project.org lede-project.org
wiki.openwrt.org
forum.openwrt.org
lists.openwrt.org
openwrt.gitlab.io
archive.openwrt.org
downloads.openwrt.org
fwdownloads.openwrt.org
mirror-01.infra.openwrt.org
mirror-02.infra.openwrt.org
mirror-03.infra.openwrt.org
mirror-04.infra.openwrt.org
#################################### UbisoftConnect #################################### UbisoftConnect
ubi.com ubi.com
ubisoft.com ubisoft.com
store.ubi.com
ubisoftconnect.com ubisoftconnect.com
connect.ubisoft.comubisoft-orbit-savegames.s3.amazonaws.com connect.ubisoft.com
drops-register.ubi.com
public-ubiservices.ubi.com
ubisoftconnect.cdn.ubi.com
uplaypc-s-ubisoft.cdn.ubi.com
uplaypc-s-ubisoft-ww.cdn.ubi.com
ubisoft-orbit-savegames.s3.amazonaws.com
ubisoft-uplay-savegames.s3.amazonaws.com ubisoft-uplay-savegames.s3.amazonaws.com
#################################### Aliexpress #################################### Aliexpress
ae.com ae.com
@@ -137,190 +214,43 @@ playstation.net
playstation.com playstation.com
account.sony.com account.sony.com
psremoteplay.com psremoteplay.com
ps4.playstation.com
ps5.playstation.com
playstationcloud.com playstationcloud.com
psapi.playstation.net
store.playstation.com
media.playstation.com
auth.np.ac.playstation.net
sonyentertainmentnetwork.com sonyentertainmentnetwork.com
np.community.playstation.net
id.sonyentertainmentnetwork.com
#################################### Twitch #################################### Twitch
twitch.tv twitch.tv
ttvnw.net ttvnw.net
jtvnw.net jtvnw.net
twimg.com
m.twitch.tv
id.twitch.tv
www.twitch.tv
twitchcdn.net twitchcdn.net
ext-twitch.tv ext-twitch.tv
twitchsvc.net twitchsvc.net
api.twitch.tv
gql.twitch.tv
dev.twitch.tv
live-video.net live-video.net
twitch.a2z.com twitch.a2z.com
chat.twitch.tv
help.twitch.tv
assets.twitch.tv
twitch-shadow.net twitch-shadow.net
passport.twitch.tv
irc.chat.twitch.tv
vod-metro.twitch.tv
twitchcdn-shadow.net twitchcdn-shadow.net
#################################### Valorant static.twitchcdn.net
qq.com vod-secure.twitch.tv
pvp.net irc-ws.chat.twitch.tv
vivox.com pubsub-edge.twitch.tv
sd-rtn.com vod-pop-secure.twitch.tv
adjust.com
riotcdn.net
adobess.com
valorant.com
akamaihd.net
myqcloud.com
riotgames.com
playvalorant.com
wildrift-na.akamaized.net
#################################### TikTok
musical.ly
tiktok.com
tiktokv.eu
tiktokv.us
tiktokw.eu
tiktokw.us
muscdn.com
tiktokd.net
tiktokd.org
tiktokv.com
tiktokcdn.com
ibytedtos.com
ttwstatic.com
tik-tokapi.com
tiktok-row.net
tiktokminis.us
byteoversea.com
tiktok-minis.com
tiktokcdn-eu.com
tiktokcdn-us.com
tiktokeu-cdn.com
tiktokrow-cdn.com
tiktokglobalshopv.com
tiktokcdn.com.akamaized.net
tiktokcdn.com.edgesuite.net
tiktokcdn-us.com.edgesuite.net
#################################### Hoyoverse
hoyo.link
hoyolab.com
yuanshen.com
hoyoverse.com
genshinimpact.com
zenlesszonezero.com
#################################### Xiaomi
mi.com
miui.com
wali.com
c.mi.com
mgslb.com
mifile.cn
xiaomi.cn
mipay.com
youpin.cn
zmifi.com
mi-idc.com
mi-img.com
mijia.tech
mitvos.com
miwifi.com
xiaomi.com
xiaomi.net
duokan.com
saxyit.com
mi-fan.com
mihome.com
xiaomisa.cn
migames.com
miaibox.com
mi-home.com
xiaomicp.com
xiaomidns.cn
xiaomiev.com
xiaomiinc.cn
xiaominr.com
xiaomisa.com
xiaomisa.net
xiaomisa.org
roborock.com
mi-robot.com
yeelight.com
miot-spec.cn
xiaomidns.com
xiaomidns.net
xiaomiinc.com
xiaomiinc.net
duokanbox.com
youpin.com.cn
miot-spec.org
miot-spec.com
xiaomiwear.com
xiaomimimo.com
dreamehome.com
xiaomiprint.com
xiaomidns.com.cn
xiaomiinc.com.cn
xiaomimobile.com
xiaomixiaoai.com
xiaomiyoupin.com
xiaoaiassist.com
xiaomi-mijia.com
xiaomifactory.com
airstarfinance.net
dreame-technology.cn
dreame-technology.com
#################################### Picooc
picoocru.com
picooc-g.com
picooc-int.com
#################################### Huawei
hc-cdn.cn
huawei.ru
huawei.com
hc-cdn.com
huawei.net
dbankcdn.ru
hicloud.com
dbankcdn.com
dbankcloud.ru
dbankcloud.cn
dbankcloud.com
huaweicloud.com
huaweistatic.com
hwclouds-dns.com
hwclouds-dns.net
myhuaweicloud.cn
myhuaweicloud.com
huaweicloud-dns.cn
huaweicloud-dns.ru
huaweicloud-dns.com
huaweicloud-dns.org
#################################### Okko
okko.tv
playfamily.ru
#################################### Beeline
beeline.ru
beeline.tv
#################################### Delta Force
volces.com
wetest.net
intlgame.com
fleetlogd.com
dgameglobal.com
tdatamaster.com
playdeltaforce.com
quovadisglobal.com
jupiterlauncher.com
anticheatexpert.com
#################################### Microsoft
live.com
lync.com
skype.com
microsoft
msauth.net
office.net
office.com
msocdn.com
mojang.com
windows.net
msftauth.net
xboxlive.com
microsoft.com
office365.com
azureedge.net
skypeassets.com
windowsupdate.com
microsoftonline.com
microsoftonline-p.com
minecraftservices.com
#################################### ####################################

View File

@@ -25,10 +25,10 @@ index 0af19c0..41c0967 100644
done done
} }
} }
diff --git a/init.d/openwrt/zapret b/init.d/openwrt/zapret diff --git a/init.d/openwrt/zapret b/init.d/openwrt/zapret2
index 8d6d3a9..fcb1e91 100755 index 8d6d3a9..fcb1e91 100755
--- a/init.d/openwrt/zapret --- a/init.d/openwrt/zapret2
+++ b/init.d/openwrt/zapret +++ b/init.d/openwrt/zapret2
@@ -58,12 +58,29 @@ run_daemon() @@ -58,12 +58,29 @@ run_daemon()
# use $PIDDIR/$DAEMONBASE$1.pid as pidfile # use $PIDDIR/$DAEMONBASE$1.pid as pidfile
local DAEMONBASE="$(basename "$2")" local DAEMONBASE="$(basename "$2")"
@@ -51,15 +51,15 @@ index 8d6d3a9..fcb1e91 100755
procd_open_instance procd_open_instance
- procd_set_param command $2 $3 - procd_set_param command $2 $3
+ procd_set_param command $DAEMON_PATH $DAEMON_ARGS + procd_set_param command $DAEMON_PATH $DAEMON_ARGS
procd_set_param pidfile $PIDDIR/$DAEMONBASE$1.pid procd_set_param pidfile $PIDDIR/${DAEMONBASE}_$1.pid
procd_close_instance procd_close_instance
} }
+DAEMON_CFGNAME="main" +DAEMON_CFGNAME="main"
+ +
run_tpws() run_nfqws()
{ {
[ "$DISABLE_IPV4" = "1" ] && [ "$DISABLE_IPV6" = "1" ] && return 0 run_daemon $1 "$NFQWS2" "$NFQWS2_OPT_BASE $2"
-- --
2.41.0.windows.3 2.41.0.windows.3

View File

@@ -1,9 +1,7 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2024 remittor # Copyright (c) 2024 remittor
EXE_DIR=$(cd "$(dirname "$0")" 2>/dev/null || exit 1; pwd) . /opt/zapret2/comfunc.sh
. $EXE_DIR/comfunc.sh
merge_cfg_with_def_values merge_cfg_with_def_values
@@ -14,5 +12,5 @@ CONFIGS_SYNC=0
if [ "$CONFIGS_SYNC" = "1" ]; then if [ "$CONFIGS_SYNC" = "1" ]; then
# renew main config # renew main config
$ZAPRET_BASE/sync_config.sh /opt/zapret2/sync_config.sh
fi fi

View File

@@ -1,11 +1,9 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2024 remittor # Copyright (c) 2024 remittor
EXE_DIR=$(cd "$(dirname "$0")" 2>/dev/null || exit 1; pwd) . /opt/zapret2/comfunc.sh
. $EXE_DIR/comfunc.sh cfg_run_on_boot="$( uci -q get $ZAPRET_CFG_NAME.config.run_on_boot )"
cfg_run_on_boot="$( uci -q get $ZAPRET_CFG_SEC.run_on_boot )"
opt_flags=${1:--} opt_flags=${1:--}
opt_strat=$2 opt_strat=$2
@@ -13,16 +11,11 @@ opt_strat=$2
if echo "$opt_flags" | grep -q "(reset_ipset)"; then if echo "$opt_flags" | grep -q "(reset_ipset)"; then
restore_all_ipset_cfg restore_all_ipset_cfg
fi fi
if echo "$opt_flags" | grep -q "(erase_autohostlist)"; then
: > $ZAPRET_BASE/ipset/zapret-hosts-auto.txt
: > $ZAPRET_BASE/ipset/zapret-hosts-auto-debug.log
fi
create_default_cfg "$opt_flags" "$opt_strat" create_default_cfg "$opt_flags" "$opt_strat"
if [ "$cfg_run_on_boot" = "1" ]; then if [ "$cfg_run_on_boot" = "1" ]; then
uci set $ZAPRET_CFG_SEC.run_on_boot=1 uci set $ZAPRET_CFG_NAME.config.run_on_boot=1
uci commit uci commit
fi fi
@@ -36,5 +29,5 @@ fi
if [ "$ZAPRET_SYNC_CONFIG" = "1" ]; then if [ "$ZAPRET_SYNC_CONFIG" = "1" ]; then
# renew main config # renew main config
$ZAPRET_BASE/sync_config.sh /opt/zapret2/sync_config.sh
fi fi

View File

@@ -1,9 +1,7 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2024 remittor # Copyright (c) 2024 remittor
EXE_DIR=$(cd "$(dirname "$0")" 2>/dev/null || exit 1; pwd) . /opt/zapret2/comfunc.sh
. $EXE_DIR/comfunc.sh
function uncomment_param function uncomment_param
{ {
@@ -43,22 +41,16 @@ function sync_param
{ {
local param=$1 local param=$1
local vtype=$2 local vtype=$2
local value="$( uci -q get $ZAPRET_CFG_SEC.$param )" local value="$( uci -q get zapret2.config.$param )"
uncomment_param $param uncomment_param $param
append_param $param append_param $param
local TAB="$( printf '\t' )" local TAB="$( echo -n -e '\t' )"
if [ "$value" = "$TAB" ]; then if [ "$value" = "$TAB" ]; then
value="" value=""
fi fi
if [ "$param" = "NFQWS_PORTS_TCP_KEEPALIVE" -o "$param" = "NFQWS_PORTS_UDP_KEEPALIVE" ]; then
[ "$value" = "0" ] && value=""
fi
if [ "$param" = "NFQWS2_PORTS_TCP_KEEPALIVE" -o "$param" = "NFQWS2_PORTS_UDP_KEEPALIVE" ]; then if [ "$param" = "NFQWS2_PORTS_TCP_KEEPALIVE" -o "$param" = "NFQWS2_PORTS_UDP_KEEPALIVE" ]; then
[ "$value" = "0" ] && value="" [ "$value" = "0" ] && value=""
fi fi
if [ "$param" = "NFQWS_OPT" -a "$value" != "" ]; then
value=$( echo -n "$value" | sed '/^#/d' )
fi
if [ "$param" = "NFQWS2_OPT" -a "$value" != "" ]; then if [ "$param" = "NFQWS2_OPT" -a "$value" != "" ]; then
value=$( echo -n "$value" | sed '/^#/d' ) value=$( echo -n "$value" | sed '/^#/d' )
fi fi
@@ -93,49 +85,26 @@ sync_param MODE_FILTER
sync_param DISABLE_CUSTOM sync_param DISABLE_CUSTOM
sync_param WS_USER str sync_param WS_USER str
sync_param DAEMON_LOG_ENABLE sync_param DAEMON_LOG_ENABLE
sync_param DAEMON_LOG_SIZE_MAX
sync_param DAEMON_LOG_FILE str sync_param DAEMON_LOG_FILE str
sync_param AUTOHOSTLIST_RETRANS_THRESHOLD sync_param AUTOHOSTLIST_RETRANS_THRESHOLD
sync_param AUTOHOSTLIST_FAIL_THRESHOLD sync_param AUTOHOSTLIST_FAIL_THRESHOLD
sync_param AUTOHOSTLIST_FAIL_TIME sync_param AUTOHOSTLIST_FAIL_TIME
if [ $ZAPRET_CFG_NAME = "zapret2" ]; then
sync_param AUTOHOSTLIST_INCOMING_MAXSEQ
sync_param AUTOHOSTLIST_RETRANS_MAXSEQ
sync_param AUTOHOSTLIST_RETRANS_RESET
sync_param AUTOHOSTLIST_UDP_IN
sync_param AUTOHOSTLIST_UDP_OUT
fi
sync_param AUTOHOSTLIST_DEBUGLOG sync_param AUTOHOSTLIST_DEBUGLOG
sync_param NFQWS2_ENABLE
sync_param DESYNC_MARK sync_param DESYNC_MARK
sync_param DESYNC_MARK_POSTNAT sync_param DESYNC_MARK_POSTNAT
sync_param FILTER_MARK str sync_param FILTER_MARK str
sync_param NFQWS2_PORTS_TCP str
if [ $ZAPRET_CFG_NAME = "zapret" ]; then sync_param NFQWS2_PORTS_UDP str
sync_param NFQWS_ENABLE sync_param NFQWS2_TCP_PKT_OUT str
sync_param NFQWS_PORTS_TCP str sync_param NFQWS2_TCP_PKT_IN str
sync_param NFQWS_PORTS_UDP str sync_param NFQWS2_UDP_PKT_OUT str
sync_param NFQWS_TCP_PKT_OUT str sync_param NFQWS2_UDP_PKT_IN str
sync_param NFQWS_TCP_PKT_IN str sync_param NFQWS2_PORTS_TCP_KEEPALIVE str
sync_param NFQWS_UDP_PKT_OUT str sync_param NFQWS2_PORTS_UDP_KEEPALIVE str
sync_param NFQWS_UDP_PKT_IN str sync_param NFQWS2_OPT str
sync_param NFQWS_PORTS_TCP_KEEPALIVE str
sync_param NFQWS_PORTS_UDP_KEEPALIVE str
sync_param NFQWS_OPT str
fi
if [ $ZAPRET_CFG_NAME = "zapret2" ]; then
sync_param NFQWS2_ENABLE
sync_param NFQWS2_PORTS_TCP str
sync_param NFQWS2_PORTS_UDP str
sync_param NFQWS2_TCP_PKT_OUT str
sync_param NFQWS2_TCP_PKT_IN str
sync_param NFQWS2_UDP_PKT_OUT str
sync_param NFQWS2_UDP_PKT_IN str
sync_param NFQWS2_PORTS_TCP_KEEPALIVE str
sync_param NFQWS2_PORTS_UDP_KEEPALIVE str
sync_param NFQWS2_OPT str
fi
ZAPRET_CONFIG="$ZAPRET_CONFIG__SAVED" ZAPRET_CONFIG="$ZAPRET_CONFIG__SAVED"

View File

@@ -1,23 +1,18 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2024 remittor # Copyright (c) 2024 remittor
[ ! -f /opt/zapret/comfunc.sh ] && exit 0 . /opt/zapret2/comfunc.sh
. /opt/zapret/comfunc.sh
mkdir -p $ZAPRET_BASE/ipset
# create empty txt files into ipset directory # create empty txt files into ipset directory
[ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-google.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-google.txt" [ ! -f "/opt/zapret2/ipset/zapret-hosts-google.txt" ] && touch "/opt/zapret2/ipset/zapret-hosts-google.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-auto.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-auto.txt" #[ ! -f "/opt/zapret2/ipset/zapret-hosts-auto.txt" ] && touch "/opt/zapret2/ipset/zapret-hosts-auto.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-user.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-user.txt" [ ! -f "/opt/zapret2/ipset/zapret-hosts-user.txt" ] && touch "/opt/zapret2/ipset/zapret-hosts-user.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-user-ipban.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-user-ipban.txt" [ ! -f "/opt/zapret2/ipset/zapret-hosts-user-ipban.txt" ] && touch "/opt/zapret2/ipset/zapret-hosts-user-ipban.txt"
#[ ! -f "$ZAPRET_BASE/ipset/zapret-ip.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-ip.txt" #[ ! -f "/opt/zapret2/ipset/zapret-ip.txt" ] && touch "/opt/zapret2/ipset/zapret-ip.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-ip-user.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-ip-user.txt" [ ! -f "/opt/zapret2/ipset/zapret-ip-user.txt" ] && touch "/opt/zapret2/ipset/zapret-ip-user.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-ip-user-exclude.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-ip-user-exclude.txt" [ ! -f "/opt/zapret2/ipset/zapret-ip-user-exclude.txt" ] && touch "/opt/zapret2/ipset/zapret-ip-user-exclude.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-ip-user-ipban.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-ip-user-ipban.txt" [ ! -f "/opt/zapret2/ipset/zapret-ip-user-ipban.txt" ] && touch "/opt/zapret2/ipset/zapret-ip-user-ipban.txt"
# create or merge uci-config # create or merge uci-config
[ ! -f "$ZAPRET_BASE/renew-cfg.sh" ] && exit 0
$ZAPRET_BASE/renew-cfg.sh $ZAPRET_BASE/renew-cfg.sh

View File

@@ -1,7 +1,9 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2025 remittor # Copyright (c) 2025 remittor
EXE_DIR=$(cd "$(dirname "$0")" 2>/dev/null || exit 1; pwd) . /opt/zapret2/comfunc.sh
. /usr/share/libubox/jshn.sh
. /etc/openwrt_release
opt_check= opt_check=
opt_prerelease= opt_prerelease=
@@ -12,34 +14,14 @@ opt_test=
while getopts "cu:pft:" opt; do while getopts "cu:pft:" opt; do
case $opt in case $opt in
c) opt_check=true;; c) opt_check=true;;
p) opt_prerelease="true";; p) opt_prerelease=true;;
u) opt_update="$OPTARG";; u) opt_update="$OPTARG";;
f) opt_forced="true";; f) opt_forced=true;;
t) opt_test="$OPTARG";; t) opt_test="$OPTARG";;
esac esac
done done
if [ "$EXE_DIR" = "/tmp" ]; then ZAP_PKG_DIR=/tmp/zapret2_pkg
ZAPRET_CFG_NAME="zapret"
if [ "$opt_update" = "1" ]; then
ZAPRET_CFG_NAME="zapret"
opt_update="@"
opt_forced="true"
fi
if [ "$opt_update" = "2" ]; then
ZAPRET_CFG_NAME="zapret2"
opt_update="@"
opt_forced="true"
fi
else
[ -f "$EXE_DIR/comfunc.sh" ] || { echo "ERROR: file $EXE_DIR/comfunc.sh not found!"; exit 1; }
. $EXE_DIR/comfunc.sh
fi
. /usr/share/libubox/jshn.sh
. /etc/openwrt_release
ZAP_PKG_DIR=/tmp/$ZAPRET_CFG_NAME-pkg
if [ "$opt_test" != "" ]; then if [ "$opt_test" != "" ]; then
echo 1; sleep 2; echo 1; sleep 2;
@@ -51,14 +33,9 @@ if [ "$opt_test" != "" ]; then
return "$opt_test" return "$opt_test"
fi fi
ZAP_CPU_ARCH="$DISTRIB_ARCH" ZAP_CPU_ARCH=$(get_cpu_arch)
ZAP_REL_URL="https://raw.githubusercontent.com/remittor/zapret-openwrt/gh-pages/releases/releases_zap2_$ZAP_CPU_ARCH.json"
if [ $ZAPRET_CFG_NAME = "zapret" ]; then
ZAP_REL_URL="https://raw.githubusercontent.com/remittor/zapret-openwrt/gh-pages/releases/releases_zap1_$ZAP_CPU_ARCH.json"
fi
if [ $ZAPRET_CFG_NAME = "zapret2" ]; then
ZAP_REL_URL="https://raw.githubusercontent.com/remittor/zapret-openwrt/gh-pages/releases/releases_zap2_$ZAP_CPU_ARCH.json"
fi
CURL_TIMEOUT=5 CURL_TIMEOUT=5
CURL_HEADER1="Accept: application/json" CURL_HEADER1="Accept: application/json"
CURL_HEADER2="Cache-Control: no-cache" CURL_HEADER2="Cache-Control: no-cache"
@@ -75,13 +52,9 @@ ZAP_PKG_URL=
if command -v apk >/dev/null; then if command -v apk >/dev/null; then
PKG_MGR=apk PKG_MGR=apk
ZAP_PKG_EXT=apk ZAP_PKG_EXT=apk
PKG_CHECK="apk info -e "
PKG_REMOVE="apk del --force "
elif command -v opkg >/dev/null; then elif command -v opkg >/dev/null; then
PKG_MGR=opkg PKG_MGR=opkg
ZAP_PKG_EXT=ipk ZAP_PKG_EXT=ipk
PKG_CHECK="opkg status "
PKG_REMOVE="opkg remove --force-remove "
else else
echo "ERROR: No package manager found" echo "ERROR: No package manager found"
return 1 return 1
@@ -89,73 +62,11 @@ fi
# ------------------------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------------------------
function get_distrib_param function download_json
{ {
local parname=$1 local url="$1"
local value="__unknown__" curl -s -L --max-time $CURL_TIMEOUT -H "$CURL_HEADER1" -H "$CURL_HEADER2" "$url" 2>/dev/null
if [ -f /etc/openwrt_release ]; then return $?
while IFS='=' read -r key val; do
val="${val#\'}"
val="${val%\'}"
val="${val#\"}"
val="${val%\"}"
if [ "$key" = "$parname" ]; then
value="$val"
break
fi
done < /etc/openwrt_release
fi
printf '%s' "$value"
}
function pkg_mgr_update
{
local forced=$1
if [ "$PKG_MGR" = "opkg" ]; then
PKG_TOTAL=$( opkg list | wc -l )
PKG_INSTALLED=$( opkg list-installed | wc -l )
if [ "$PKG_TOTAL" -le "$PKG_INSTALLED" ] || [[ "$PKG_TOTAL" -le $((PKG_INSTALLED + 100)) ]]; then
echo ">>> OPKG update..."
opkg update
return $?
fi
else
PKG_AVAIL=$( apk list --available 2>/dev/null | wc -l )
if [ "$PKG_AVAIL" -lt 100 ]; then
echo ">>> APK update..."
apk update
return $?
fi
fi
return 0
}
function curl_install
{
if command -v curl >/dev/null 2>&1; then
return 0
fi
pkg_mgr_update || { echo "ERROR: cannot update packages list"; return 1; }
echo ">>> Package curl not found, installing..."
if [ "$PKG_MGR" = "opkg" ]; then
opkg install curl
else
apk add curl
fi
}
function unzip_install
{
if command -v unzip >/dev/null 2>&1; then
return 0
fi
pkg_mgr_update || { echo "ERROR: cannot update packages list"; return 1; }
echo ">>> Package unzip not found, installing..."
if [ "$PKG_MGR" = "opkg" ]; then
opkg install unzip
else
apk add unzip
fi
} }
function get_pkg_version function get_pkg_version
@@ -170,7 +81,7 @@ function get_pkg_version
fi fi
fi fi
if [ "$PKG_MGR" = apk ]; then if [ "$PKG_MGR" = apk ]; then
line=$( apk info -s "$pkg_name" 2>/dev/null | head -n 1 | awk '{print $1}' || true ) line=$( apk info -e "$pkg_name" 2>/dev/null || true )
if [ -n "$line" ]; then if [ -n "$line" ]; then
base=${line%-r[0-9]*} base=${line%-r[0-9]*}
ver=${base##*-} ver=${base##*-}
@@ -206,16 +117,11 @@ function normalize_version
;; ;;
esac esac
old_ifs="$IFS" ; IFS='.' ; set -- $base ; IFS="$old_ifs" old_ifs="$IFS" ; IFS='.' ; set -- $base ; IFS="$old_ifs"
rel=${rel:-1}
major=${1:-0} major=${1:-0}
minor=${2:-0} minor=${2:-0}
if [ $ZAPRET_CFG_NAME = "zapret" ]; then build=${3:-0}
echo "$major.$minor.$rel" rel=${rel:-1}
fi echo "$major.$minor.$build.$rel"
if [ $ZAPRET_CFG_NAME = "zapret2" ]; then
build=${3:-0}
echo "$major.$minor.$build.$rel"
fi
} }
function pkg_version_cmp function pkg_version_cmp
@@ -233,22 +139,14 @@ function pkg_version_cmp
x2=$( echo "$ver2" | cut -d. -f2 ) x2=$( echo "$ver2" | cut -d. -f2 )
[ "$x1" -gt "$x2" ] && { echo -n "G"; return 0; } [ "$x1" -gt "$x2" ] && { echo -n "G"; return 0; }
[ "$x1" -lt "$x2" ] && { echo -n "L"; return 0; } [ "$x1" -lt "$x2" ] && { echo -n "L"; return 0; }
if [ $ZAPRET_CFG_NAME = "zapret2" ]; then # build
# build x1=$( echo "$ver1" | cut -d. -f3 )
x1=$( echo "$ver1" | cut -d. -f3 ) x2=$( echo "$ver2" | cut -d. -f3 )
x2=$( echo "$ver2" | cut -d. -f3 ) [ "$x1" -gt "$x2" ] && { echo -n "G"; return 0; }
[ "$x1" -gt "$x2" ] && { echo -n "G"; return 0; } [ "$x1" -lt "$x2" ] && { echo -n "L"; return 0; }
[ "$x1" -lt "$x2" ] && { echo -n "L"; return 0; }
fi
# release # release
if [ $ZAPRET_CFG_NAME = "zapret" ]; then x1=$( echo "$ver1" | cut -d. -f4 )
x1=$( echo "$ver1" | cut -d. -f3 ) x2=$( echo "$ver2" | cut -d. -f4 )
x2=$( echo "$ver2" | cut -d. -f3 )
fi
if [ $ZAPRET_CFG_NAME = "zapret2" ]; then
x1=$( echo "$ver1" | cut -d. -f4 )
x2=$( echo "$ver2" | cut -d. -f4 )
fi
[ "$x1" -gt "$x2" ] && { echo -n "G"; return 0; } [ "$x1" -gt "$x2" ] && { echo -n "G"; return 0; }
[ "$x1" -lt "$x2" ] && { echo -n "L"; return 0; } [ "$x1" -lt "$x2" ] && { echo -n "L"; return 0; }
echo -n "E" echo -n "E"
@@ -256,28 +154,18 @@ function pkg_version_cmp
function download_releases_info function download_releases_info
{ {
local fname resp hdr txt txtlen txtlines generated_at local txt txtlen txtlines generated_at
REL_JSON= REL_JSON=
echo "Download releases info..." echo "Download releases info..."
fname="${ZAP_REL_URL##*/}" txt=$(download_json $ZAP_REL_URL)
resp=$( curl -s -D - --max-time $CURL_TIMEOUT -H "$CURL_HEADER1" -H "$CURL_HEADER2" "$ZAP_REL_URL" 2>/dev/null )
hdr="${resp%%$'\r\n\r\n'*}"
status=$( printf '%s\n' "$hdr" | head -n 1 | awk '{print $2}' )
if [ "$status" != 200 ]; then
echo "ERROR: Cannot download file \"$ZAP_REL_URL\" (status = $status)"
return 103
fi
txtlen=$( printf '%s\n' "$hdr" | awk -F': ' 'BEGIN{IGNORECASE=1} $1=="Content-Length"{print $2}' | tr -d '\r' )
echo "Content-Length: $txtlen bytes"
txt="${resp#*$'\r\n\r\n'}"
txtlen=${#txt} txtlen=${#txt}
txtlines=$(printf '%s\n' "$txt" | wc -l) txtlines=$(printf '%s\n' "$txt" | wc -l)
if [[ $txtlen -lt 64 ]]; then if [[ $txtlen -lt 64 ]]; then
echo "ERROR: Cannot download releases info! (size = $txtlen)" echo "ERROR: Cannot download releases info!"
return 104 return 104
fi fi
echo "Releases info downloaded! Size = $txtlen, Lines = $txtlines" echo "Releases info downloaded! Size = $txtlen, Lines = $txtlines"
generated_at=$( printf '%s\n' "$txt" | grep -m1 -o '"generated_at"[[:space:]]*:[[:space:]]*".*"' | cut -d'"' -f4 ) generated_at=$(printf '%s\n' "$txt" | grep -m1 -o '"generated_at"[[:space:]]*:[[:space:]]*".*"' | cut -d'"' -f4)
if [[ "$generated_at" = "" ]]; then if [[ "$generated_at" = "" ]]; then
echo "ERROR: Cannot download releases info! (incorrect generated_at)" echo "ERROR: Cannot download releases info! (incorrect generated_at)"
return 105 return 105
@@ -340,8 +228,8 @@ function get_actual_release
return 0 return 0
done done
json_cleanup json_cleanup
echo "ERROR: latest release for arch \"$ZAP_CPU_ARCH\" not found!" echo "ERROR: latest release for arch \"$ZAP_CPU_ARCH\" not founded!"
return 150 # release not found return 1 # release not founded
} }
# ------------------------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------------------------
@@ -357,16 +245,11 @@ fi
#echo "DISTRIB_ID: $DISTRIB_ID" #echo "DISTRIB_ID: $DISTRIB_ID"
echo "DISTRIB_RELEASE: $DISTRIB_RELEASE" echo "DISTRIB_RELEASE: $DISTRIB_RELEASE"
echo "DISTRIB_DESCRIPTION:" $( get_distrib_param DISTRIB_DESCRIPTION ) echo "DISTRIB_DESCRIPTION:" $(get_distrib_param DISTRIB_DESCRIPTION)
echo "DISTRIB_ARCH:" $( get_distrib_param DISTRIB_ARCH ) echo "DISTRIB_ARCH:" $(get_distrib_param DISTRIB_ARCH)
if ! command -v curl >/dev/null 2>&1; then if ! command -v curl >/dev/null 2>&1; then
if [ "$opt_forced" = true ]; then echo "ERROR: package \"curl\" not installed!"
curl_install
fi
fi
if ! command -v curl >/dev/null 2>&1; then
echo "ERROR: Required package \"curl\" not installed!"
return 10 return 10
fi fi
CURL_INFO=$( curl -V ) CURL_INFO=$( curl -V )
@@ -388,11 +271,6 @@ if [ "$opt_check" = "true" ]; then
fi fi
get_actual_release get_actual_release
ZAP_ERR=$? ZAP_ERR=$?
if [ $ZAP_ERR = 150 ] && [ "$opt_prerelease" != true ] && [ "$opt_forced" = true ]; then
opt_prerelease="true"
get_actual_release
ZAP_ERR=$?
fi
if [ $ZAP_ERR -ne 0 ]; then if [ $ZAP_ERR -ne 0 ]; then
echo "ERROR: Func get_actual_release return error code: $ZAP_ERR" echo "ERROR: Func get_actual_release return error code: $ZAP_ERR"
return $ZAP_ERR return $ZAP_ERR
@@ -408,13 +286,13 @@ ZAP_PKG_FN=
ZAP_PKG_BASE_FN= ZAP_PKG_BASE_FN=
ZAP_PKG_LUCI_FN= ZAP_PKG_LUCI_FN=
ZAP_CUR_PKG_VER=$( get_pkg_version $ZAPRET_CFG_NAME ) ZAP_CUR_PKG_VER=$( get_pkg_version zapret2 )
echo "Current installed version: $ZAP_CUR_PKG_VER" echo "Current installed version: $ZAP_CUR_PKG_VER"
if [ "$opt_update" = "" ]; then if [ "$opt_update" = "" ]; then
ZAP_PKG_URL="$REL_ACTUAL_URL" ZAP_PKG_URL="$REL_ACTUAL_URL"
if [ "$ZAP_PKG_URL" = "" ]; then if [ "$ZAP_PKG_URL" = "" ]; then
echo "ERROR: actual release not found!" echo "ERROR: actual release not founded!"
return 199 return 199
fi fi
else else
@@ -423,7 +301,7 @@ else
ZAP_PKG_URL="$REL_ACTUAL_URL" ZAP_PKG_URL="$REL_ACTUAL_URL"
fi fi
if [ "$opt_update" = "@" -a "$ZAP_PKG_URL" = "" ]; then if [ "$opt_update" = "@" -a "$ZAP_PKG_URL" = "" ]; then
echo "ERROR: actual release not found!" echo "ERROR: actual release not founded!"
return 199 return 199
fi fi
fi fi
@@ -463,8 +341,8 @@ if [ "$opt_update" != "" ]; then
return 0 return 0
fi fi
fi fi
ZAP_PKG_DIR=/tmp/$ZAPRET_CFG_NAME-pkg ZAP_PKG_DIR=/tmp/zapret2_pkg
rm -rf $ZAP_PKG_DIR 2>/dev/null rm -rf $ZAP_PKG_DIR
ZAP_PKG_HDRS=$( curl -s -I -L --max-time $CURL_TIMEOUT -H "$CURL_HEADER2" "$ZAP_PKG_URL" ) ZAP_PKG_HDRS=$( curl -s -I -L --max-time $CURL_TIMEOUT -H "$CURL_HEADER2" "$ZAP_PKG_URL" )
ZAP_PKG_SIZE=$( echo "$ZAP_PKG_HDRS" | grep -i 'content-length: ' | tail -n1 | awk '{print $2}' | tr -d '\r' ) ZAP_PKG_SIZE=$( echo "$ZAP_PKG_HDRS" | grep -i 'content-length: ' | tail -n1 | awk '{print $2}' | tr -d '\r' )
echo "Downloded ZIP-file size = $ZAP_PKG_SIZE bytes" echo "Downloded ZIP-file size = $ZAP_PKG_SIZE bytes"
@@ -486,57 +364,37 @@ if [ "$opt_update" != "" ]; then
return 216 return 216
fi fi
if ! command -v unzip >/dev/null 2>&1; then if ! command -v unzip >/dev/null 2>&1; then
if [ "$opt_forced" = true ]; then echo "ERROR: package \"upzip\" not installed!"
unzip_install
fi
fi
if ! command -v unzip >/dev/null 2>&1; then
echo "ERROR: package \"unzip\" not installed!"
return 218 return 218
fi fi
unzip -q "$ZAP_PKG_FN" -d $ZAP_PKG_DIR unzip -q "$ZAP_PKG_FN" -d $ZAP_PKG_DIR
rm -f "$ZAP_PKG_FN" 2>/dev/null rm -f "$ZAP_PKG_FN"
if [ "$PKG_MGR" = "apk" ]; then if [ "$PKG_MGR" = "apk" ]; then
if [ ! -d "$ZAP_PKG_DIR/apk" ]; then if [ ! -d "$ZAP_PKG_DIR/apk" ]; then
echo "ERROR: APK-files not found" echo "ERROR: APK-files not founded"
return 221 return 221
fi fi
rm -f $ZAP_PKG_DIR/*.ipk 2>/dev/null rm -f "$ZAP_PKG_DIR/*.ipk"
mv $ZAP_PKG_DIR/apk/* $ZAP_PKG_DIR/ mv "$ZAP_PKG_DIR/apk/*" "$ZAP_PKG_DIR/"
else else
rm -rf $ZAP_PKG_DIR/apk 2>/dev/null rm -rf "$ZAP_PKG_DIR/apk"
fi fi
ZAP_PKG_LIST=$( ls -1 "$ZAP_PKG_DIR" ) ZAP_PKG_LIST=$( ls -1 "$ZAP_PKG_DIR" )
echo "------ Downloaded packages:" echo "------ Downloaded packages:"
echo "$ZAP_PKG_LIST" echo "$ZAP_PKG_LIST"
echo "------" echo "------"
if [ "$PKG_MGR" != "apk" ]; then ZAP_PKG_BASE_FN=$( find "$ZAP_PKG_DIR" -maxdepth 1 -type f -name "zapret2_*.${ZAP_PKG_EXT}" | head -n 1 )
ZAP_PKG_BASE_FN=$( find "$ZAP_PKG_DIR" -maxdepth 1 -type f -name "${ZAPRET_CFG_NAME}_*.${ZAP_PKG_EXT}" | head -n 1 ) ZAP_PKG_LUCI_FN=$( find "$ZAP_PKG_DIR" -maxdepth 1 -type f -name "luci-app-*.${ZAP_PKG_EXT}" | head -n 1 )
else
ZAP_PKG_BASE_FN=$( find "$ZAP_PKG_DIR" -maxdepth 1 -type f -name "${ZAPRET_CFG_NAME}-[0-9]*.?*.${ZAP_PKG_EXT}" | head -n 1 )
fi
ZAP_PKG_LUCI_FN=$( find "$ZAP_PKG_DIR" -maxdepth 1 -type f -name "luci-app-${ZAPRET_CFG_NAME}*.${ZAP_PKG_EXT}" | head -n 1 )
if [ ! -f "$ZAP_PKG_BASE_FN" ]; then if [ ! -f "$ZAP_PKG_BASE_FN" ]; then
echo "ERROR: File \"${ZAPRET_CFG_NAME}*.${ZAP_PKG_EXT}\" not found!" echo "ERROR: File \"zapret2_*.${ZAP_PKG_EXT}\" not found!"
return 231 return 231
fi fi
echo "ZAP_PKG_BASE_FN = $ZAP_PKG_BASE_FN" echo "ZAP_PKG_BASE_FN = $ZAP_PKG_BASE_FN"
if [ ! -f "$ZAP_PKG_LUCI_FN" ]; then if [ ! -f "$ZAP_PKG_LUCI_FN" ]; then
echo "ERROR: File \"luci-app-${ZAPRET_CFG_NAME}*.${ZAP_PKG_EXT}\" not found!" echo "ERROR: File \"luci-app-*.${ZAP_PKG_EXT}\" not found!"
return 232 return 232
fi fi
echo "ZAP_PKG_LUCI_FN = $ZAP_PKG_LUCI_FN" echo "ZAP_PKG_LUCI_FN = $ZAP_PKG_LUCI_FN"
if [ "$opt_forced" = true ]; then
pkg_mgr_update
fi
if ${PKG_CHECK} ${ZAPRET_CFG_NAME}-mdig >/dev/null 2>&1; then
echo "Uninstall mdig..."
${PKG_REMOVE} ${ZAPRET_CFG_NAME}-mdig
fi
if ${PKG_CHECK} ${ZAPRET_CFG_NAME}-ip2net >/dev/null 2>&1; then
echo "Uninstall ip2net..."
${PKG_REMOVE} ${ZAPRET_CFG_NAME}-ip2net
fi
echo "Install downloaded packages..." echo "Install downloaded packages..."
if [ "$PKG_MGR" != "apk" ]; then if [ "$PKG_MGR" != "apk" ]; then
opkg install --force-reinstall "$ZAP_PKG_BASE_FN" opkg install --force-reinstall "$ZAP_PKG_BASE_FN"