Compare commits

..

3 Commits

Author SHA1 Message Date
remittor
7a7784878f Bump version to v72.20260111 2026-01-11 13:39:18 +03:00
remittor
fc3e0ec213 build: Fix matrix for riscv64 arch 2026-01-11 13:39:01 +03:00
remittor
9e3dbf8ef3 Add diagnostic button (DPI checker) 2026-01-11 11:56:22 +03:00
22 changed files with 728 additions and 1717 deletions

View File

@@ -276,8 +276,6 @@ jobs:
run: | run: |
make defconfig make defconfig
sed -i 's/CONFIG_LUCI_JSMIN=y/CONFIG_LUCI_JSMIN=n/g' .config 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 echo "status=success" >> $GITHUB_OUTPUT
- name: Show config - name: Show config

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

@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-zapret PKG_NAME:=luci-app-zapret
PKG_VERSION:=72.20260128 PKG_VERSION:=72.20260111
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>

View File

@@ -5,7 +5,7 @@
'require uci'; 'require uci';
'require ui'; 'require ui';
'require view'; 'require view';
'require view.zapret.tools as tools'; 'require view.zapret2.tools as tools';
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';
@@ -23,106 +23,44 @@ return baseclass.extend({
this.logArea.scrollTop = this.logArea.scrollHeight; 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() dpiCheck: async function()
{ {
this._action = 'dpiCheck'; this._action = 'dpiCheck';
this.setBtnMode(0, 0, 0);
this.appendLog('DPI check [tcp 16-20]...'); this.appendLog('DPI check [tcp 16-20]...');
this.appendLog('Original sources: https://github.com/hyperion-cs/dpi-checkers'); 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/'); this.appendLog('WEB-version: https://hyperion-cs.github.io/dpi-checkers/ru/tcp-16-20/');
let cmd = [ fn_dwc_sh ]; let cmd = [ fn_dwc_sh ];
let resolve_dns = document.getElementById('cfg_resolve_dns'); let log = '/tmp/'+tools.appName+'_dwc.log';
let dns_ip = resolve_dns.options[resolve_dns.selectedIndex].text; let callback = this.execAndReadCallback;
if (dns_ip && dns_ip != 'default') { let wnd = this;
cmd.push(...[ '-d', dns_ip.trim() ]); return tools.execAndRead({ cmd: cmd, log: log, logArea: this.logArea, callback: callback, cbarg: wnd });
}
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() execAndReadCallback: function(wnd, rc, txt = '')
{ {
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) { if (rc == 0 && txt) {
this.appendLog('========================================================='); if (wnd._action == 'dpiCheck') {
return; wnd.appendLog('=========================================================');
return;
}
} }
if (rc >= 500) { if (rc >= 500) {
if (txt) { if (txt) {
this.appendLog(txt.startsWith('ERROR') ? txt : 'ERROR: ' + txt); wnd.appendLog(txt.startsWith('ERROR') ? txt : 'ERROR: ' + txt);
} else { } else {
this.appendLog('ERROR: ' + this._action + ': Terminated with error code = ' + rc); wnd.appendLog('ERROR: ' + wnd._action + ': Terminated with error code = ' + rc);
} }
} else { } else {
this.appendLog('ERROR: Process finished with retcode = ' + rc); wnd.appendLog('ERROR: Process finished with retcode = ' + rc);
} }
this.appendLog('========================================================='); wnd.setStage(999);
wnd.appendLog('=========================================================');
}, },
openDiagnostDialog: function(pkg_arch) openDiagnostDialog: function(pkg_arch)
{ {
this.pkg_arch = 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', { this.logArea = E('textarea', {
'id': 'widget.modal_content', 'id': 'widget.modal_content',
'readonly': true, 'readonly': true,
@@ -142,25 +80,14 @@ return baseclass.extend({
'id': 'btn_dpicheck', 'id': 'btn_dpicheck',
'name': 'btn_dpicheck', 'name': 'btn_dpicheck',
'class': btn_style_action, 'class': btn_style_action,
}, _('DPI check')); }, _('DPI check [tcp 16-20]'));
this.btn_dpicheck.onclick = ui.createHandlerFn(this, this.dpiCheck); 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'), [ ui.showModal(_('Diagnostics'), [
E('div', { 'class': 'cbi-section' }, [ E('div', { 'class': 'cbi-section' }, [
resolve_dns,
E('br'), E('br'),
this.logArea, this.logArea,
]), ]),
E('div', { 'class': 'right' }, [ E('div', { 'class': 'right' }, [
this.btn_sitescheck,
' ',
this.btn_dpicheck, this.btn_dpicheck,
' ', ' ',
this.btn_cancel, 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', tools.appName+'+*.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;
} }
@@ -70,20 +68,17 @@ return view.extend({
))); )));
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.'+tools.appName
))); )));
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++) {
@@ -116,28 +111,26 @@ return view.extend({
} }
}, },
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'}, [ tools.AppName + ' - ' + _('Log Viewer') ]),
]); ]);
var tabs = E('div', {}, E('div')); var tabs = E('div', {}, E('div'));
@@ -200,11 +193,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

@@ -32,39 +32,22 @@ return baseclass.extend({
autoHostListFN : '/opt/zapret/ipset/zapret-hosts-auto.txt', autoHostListFN : '/opt/zapret/ipset/zapret-hosts-auto.txt',
autoHostListDbgFN : '/opt/zapret/ipset/zapret-hosts-auto-debug.log', autoHostListDbgFN : '/opt/zapret/ipset/zapret-hosts-auto-debug.log',
load_env: function(ctx) load_env: function(dst_obj) {
{
let env_proto = Object.getPrototypeOf(this); let env_proto = Object.getPrototypeOf(this);
Object.getOwnPropertyNames(env_proto).forEach(function(key) { Object.getOwnPropertyNames(env_proto).forEach(function(key) {
if (key === 'constructor' || key.startsWith('__')) { if (key === 'constructor' || key === 'load_env' || key.startsWith('__'))
return; return;
} dst_obj[key] = env_proto[key];
if (key === 'load_env' || key === 'load_feat_env') {
return;
}
ctx[key] = env_proto[key];
}); });
ctx.skey_pkg_dict = this.appName + '-pkg-dict'; dst_obj.packager = { };
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')) { if (L.hasSystemFeature('apk')) {
ctx.packager.name = 'apk'; dst_obj.packager.name = 'apk';
ctx.packager.path = '/usr/bin/apk'; dst_obj.packager.path = '/usr/bin/apk';
ctx.packager.args = [ 'list', '-I', '*'+this.appName+'*' ]; dst_obj.packager.args = [ 'list', '-I', '*'+this.appName+'*' ];
} else { } else {
ctx.packager.name = 'opkg'; dst_obj.packager.name = 'opkg';
ctx.packager.path = '/bin/opkg'; dst_obj.packager.path = '/bin/opkg';
ctx.packager.args = [ 'list-installed', '*'+this.appName+'*' ]; dst_obj.packager.args = [ 'list-installed', '*'+this.appName+'*' ];
} }
}, }
}); });

View File

@@ -16,18 +16,16 @@ 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'), 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,18 +44,17 @@ 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.'+tools.appName
@@ -65,35 +62,41 @@ return view.extend({
}); });
}, },
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 +104,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 +129,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,18 +244,8 @@ 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 ] ) );
@@ -231,11 +262,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 +276,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)';
};
if (document.getElementById('cfg_enable_custom_d').checked) {
opt_flags += '(enable_custom_d)';
};
let sel_strat = document.getElementById('cfg_nfqws_strat'); 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 +293,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 +304,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,17 +367,17 @@ 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'));
@@ -368,7 +386,7 @@ return view.extend({
let btn_diag = create_btn('btn_diag', btn_style_action, _('Diagnostics')); let btn_diag = create_btn('btn_diag', btn_style_action, _('Diagnostics'));
btn_diag.onclick = ui.createHandlerFn(this, () => { diagnost.openDiagnostDialog(this.pkg_arch) }); btn_diag.onclick = ui.createHandlerFn(this, () => { diagnost.openDiagnostDialog(this.pkg_arch) });
layout_append('Diagnostic tools', null, [ btn_diag ] ); layout_append('', 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) });
@@ -385,19 +403,17 @@ return view.extend({
"btn_diag": btn_diag, "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 = tools.AppName;
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[tools.appName] === undefined || pkgdict[tools.appName] == '') {
page_title += 'unknown version'; page_title += 'unknown version';
} else { } else {
page_title += 'v' + pkgdict[tools.appName]; page_title += 'v' + pkgdict[tools.appName];
page_title = page_title.replace(/-r1$/, '');
} }
let aux1 = E('em'); let aux1 = E('em');
let aux2 = E('em'); let aux2 = E('em');

View File

@@ -7,30 +7,44 @@
'require view'; 'require view';
'require view.zapret.tools as tools'; 'require view.zapret.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;
@@ -90,43 +104,6 @@ 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 = 'nfqws_params';
@@ -151,10 +128,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,23 +141,21 @@ 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') { if (tools.appName == 'zapret2') {
@@ -306,10 +279,6 @@ return view.extend({
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'));
@@ -338,12 +307,13 @@ return view.extend({
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 +323,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 +340,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 +378,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 +419,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 +461,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 +469,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

@@ -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

@@ -40,12 +40,7 @@ return baseclass.extend({
env_tools.load_env(this); env_tools.load_env(this);
//console.log('appName: ' + this.appName); //console.log('appName: ' + this.appName);
//console.log('PACKAGER: ' + this.packager.name); //console.log('PACKAGER: ' + this.packager.name);
}, },
load_feat_env: function()
{
env_tools.load_feat_env(this);
},
infoLabelRunning : '<span class="label-status running">' + _('Running') + '</span>', infoLabelRunning : '<span class="label-status running">' + _('Running') + '</span>',
infoLabelStarting : '<span class="label-status starting">' + _('Starting') + '</span>', infoLabelStarting : '<span class="label-status starting">' + _('Starting') + '</span>',
@@ -106,29 +101,6 @@ return baseclass.extend({
}); });
}, },
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() { getStratList: function() {
let exec_cmd = '/bin/busybox'; let exec_cmd = '/bin/busybox';
let exec_arg = [ 'awk', '-F', '"', '/if \\[ "\\$strat" = "/ {print $4}', this.defCfgPath ]; let exec_arg = [ 'awk', '-F', '"', '/if \\[ "\\$strat" = "/ {print $4}', this.defCfgPath ];
@@ -142,9 +114,7 @@ return baseclass.extend({
}); });
}, },
handleServiceAction: function(name, action, throwed = false) handleServiceAction: function(name, action) {
{
console.log('handleServiceAction: '+name+' '+action);
return this.callInitAction(name, action).then(success => { return this.callInitAction(name, action).then(success => {
if (!success) { if (!success) {
throw _('Command failed'); throw _('Command failed');
@@ -152,139 +122,9 @@ return baseclass.extend({
return true; return true;
}).catch(e => { }).catch(e => {
ui.addNotification(null, E('p', _('Service action failed "%s %s": %s').format(name, action, 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) { normalizeValue: function(v) {
return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v; return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
}, },
@@ -301,7 +141,7 @@ return baseclass.extend({
return m ? m[2] : defval; return m ? m[2] : defval;
}, },
decode_pkg_list: function(pkg_list) { decode_pkg_list: function(pkg_list, with_suffix_r1 = true) {
let pkg_dict = { }; let pkg_dict = { };
if (!pkg_list) { if (!pkg_list) {
return pkg_dict; return pkg_dict;
@@ -340,7 +180,11 @@ return baseclass.extend({
} }
} }
if (rev >= 0) { if (rev >= 0) {
ver += '-r' + rev; if (rev == 1 && !with_suffix_r1) {
// nothing
} else {
ver += '-r' + rev;
}
} }
pkg_dict[name] = ver; pkg_dict[name] = ver;
} }
@@ -364,8 +208,7 @@ return baseclass.extend({
return plist; return plist;
}, },
decode_svc_info: function(svc_autorun, svc_info, proc_list, cfg = null) decode_svc_info: function(svc_autorun, svc_info, proc_list, cfg) {
{
let result = { let result = {
"autorun": svc_autorun, "autorun": svc_autorun,
"dmn": { "dmn": {
@@ -376,18 +219,13 @@ return baseclass.extend({
}, },
"status": this.statusDict.error, "status": this.statusDict.error,
}; };
let plist = proc_list; if (proc_list.code != 0) {
if (proc_list?.code !== undefined) { return -2;
if (proc_list.code != 0) { }
return -2; let plist = this.get_pid_list(proc_list.stdout);
}
plist = this.get_pid_list(proc_list.stdout); if (plist.length < 4) {
if (plist.length < 4) { return -3;
return -3;
}
}
if (svc_info == null) {
return null;
} }
if (typeof(svc_info) !== 'object') { if (typeof(svc_info) !== 'object') {
return -4; return -4;
@@ -423,7 +261,7 @@ return baseclass.extend({
let svc_autorun = _('Unknown'); let svc_autorun = _('Unknown');
let svc_daemons = _('Unknown'); let svc_daemons = _('Unknown');
if (typeof(svcinfo) == 'object' && svcinfo?.autorun !== undefined) { if (typeof(svcinfo) == 'object') {
svc_autorun = (svcinfo.autorun) ? _('Enabled') : _('Disabled'); svc_autorun = (svcinfo.autorun) ? _('Enabled') : _('Disabled');
if (!svcinfo.dmn.inited) { if (!svcinfo.dmn.inited) {
svc_daemons = _('Stopped'); svc_daemons = _('Stopped');
@@ -482,18 +320,14 @@ return baseclass.extend({
}, },
fileEditDialog: baseclass.extend({ fileEditDialog: baseclass.extend({
__init__: function(opts = {}) __init__: function(file, title, desc, aux = null, rows = 10, callback, file_exists = false) {
{ this.file = file;
Object.assign(this, { this.title = title;
file: '', this.desc = desc;
title: '', this.aux = aux;
desc: '', this.rows = rows,
aux: '', this.callback = callback;
rows: 10, this.file_exists = file_exists;
callback: null,
file_exists: false,
setperm: 644,
}, opts);
}, },
load: function() { load: function() {
@@ -536,52 +370,11 @@ return baseclass.extend({
]); ]);
}, },
writeAdv: async function(fileName, data, chunkSize = 8000) handleSaveAdv: function(ev) {
{
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 txt = document.getElementById('widget.modal_content');
let value = txt.value.trim().replace(/\r\n/g, '\n'); let value = txt.value.trim().replace(/\r\n/g, '\n') + '\n';
if (value.length > 0) {
value += '\n'; return fs.write(this.file, value).then(async rc => {
}
return this.writeAdv(this.file, value).then(async rc => {
txt.value = value; txt.value = value;
ui.addNotification(null, E('p', _('Contents have been saved.')), 'info'); ui.addNotification(null, E('p', _('Contents have been saved.')), 'info');
if (this.callback) { if (this.callback) {
@@ -627,16 +420,13 @@ return baseclass.extend({
}), }),
longstrEditDialog: baseclass.extend({ longstrEditDialog: baseclass.extend({
__init__: function(opts = {}) __init__: function(cfgsec, cfgparam, title, desc, rows = 10, multiline = false) {
{ this.cfgsec = cfgsec;
Object.assign(this, { this.cfgparam = cfgparam;
cfgsec: '', this.title = title;
cfgparam: '', this.desc = desc;
title: '', this.rows = rows;
desc: '', this.multiline = multiline;
rows: 10,
multiline: false // may be 2
}, opts);
env_tools.load_env(this); env_tools.load_env(this);
}, },
@@ -700,11 +490,8 @@ return baseclass.extend({
if (value != "" && value != "\t") { if (value != "" && value != "\t") {
value = '\n' + value + '\n'; value = '\n' + value + '\n';
if (this.multiline == 2) { if (this.multiline == 2) {
if (value.includes('"')) {
alert(_('Unable to save the contents') + ':\n' + _('text cannot contain quotes!'));
return false;
}
value = value.replace(/"/g, ''); value = value.replace(/"/g, '');
value = value.replace(/'/g, '');
} }
} }
} else { } else {
@@ -719,10 +506,24 @@ return baseclass.extend({
value = value.replace(/˂/g, '<'); value = value.replace(/˂/g, '<');
value = value.replace(/˃/g, '>'); value = value.replace(/˃/g, '>');
try { try {
let elem = document.getElementById("widget.cbid." + this.appName + ".config._" + this.cfgparam); let elem = document.getElementById("cbi-" + this.appName + "-" + this.cfgsec + "-_" + this.cfgparam);
if (elem) {
if (elem.querySelector('div')) {
elem = elem.querySelector('div');
} else {
elem = elem.querySelector('output');
}
}
if (elem) { if (elem) {
let val = value.trim(); let val = value.trim();
elem.textContent = val; if (this.multiline) {
val = val.replace(/</g, '˂');
val = val.replace(/>/g, '˃');
val = val.replace(/\n/g, '<br/>');
elem.innerHTML = val;
} else {
elem.textContent = val;
}
} }
} catch(e) { } catch(e) {
console.error('ERROR: cannot found elem for ' + this.cfgsec + '.' + this.cfgparam); console.error('ERROR: cannot found elem for ' + this.cfgsec + '.' + this.cfgparam);
@@ -761,7 +562,7 @@ return baseclass.extend({
}, },
}), }),
execAndRead: async function({ cmd = [ ], log = '', logArea = null, callback = null, ctx = null, hiderow = [ ], rpc_timeout = 5, rpc_root = false } = {}) execAndRead: async function({ cmd = [ ], log = '', logArea = null, callback = null, cbarg = null, hiderow = [ ], rpc_timeout = 5, rpc_root = false } = {})
{ {
function appendLog(msg, end = '\n') function appendLog(msg, end = '\n')
{ {
@@ -785,211 +586,69 @@ return baseclass.extend({
await fs.exec('/bin/busybox', [ 'rm', '-f', logFile + '*' ], null, rpc_opt); await fs.exec('/bin/busybox', [ 'rm', '-f', logFile + '*' ], null, rpc_opt);
appendLog('Output file cleared!'); appendLog('Output file cleared!');
} catch (e) { } catch (e) {
return callback.call(ctx, 500, 'ERROR: Failed to clear output file'); return callback(cbarg, 500, 'ERROR: Failed to clear output file');
} }
try { try {
let opt_list = [ logFile ]; let opt_list = [ logFile ];
opt_list.push(...cmd); opt_list.push(...cmd);
let res = await fs.exec(this.appDir+'/script-exec.sh', opt_list, null, rpc_opt); let res = await fs.exec(this.appDir+'/script-exec.sh', opt_list, null, rpc_opt);
if (res.code != 0) { if (res.code != 0) {
return callback.call(ctx, 525, 'ERROR: cannot run "' + cmd[0] + '" script! (error = ' + res.code + ')'); return callback(cbarg, 525, 'ERROR: cannot run "' + cmd[0] + '" script! (error = ' + res.code + ')');
} }
appendLog('Process started...'); appendLog('Process started...');
} catch (e) { } catch (e) {
return callback.call(ctx, 520, 'ERROR: Failed on execute process: ' + e.message); return callback(cbarg, 520, 'ERROR: Failed on execute process: ' + e.message);
} }
let lastLen = 0; let lastLen = 0;
let retCode = -1; let retCode = -1;
return await new Promise(async (resolve, reject) => { let timerBusy = false;
async function epoll() let timer = setInterval(async () => {
{ if (timerBusy)
try { return; // skip iteration
let res = await fs.exec('/bin/cat', [ logFile ], null, rpc_opt); timerBusy = true;
if (res.stdout && res.stdout.length > lastLen) { try {
let log = res.stdout.slice(lastLen); let res = await fs.exec('/bin/cat', [ logFile ], null, rpc_opt);
hide_rows.forEach(re => { if (res.stdout && res.stdout.length > lastLen) {
log = log.replace(re, ''); let log = res.stdout.slice(lastLen);
}); hide_rows.forEach(re => {
appendLog(log, ''); log = log.replace(re, '');
lastLen = res.stdout.length; });
} appendLog(log, '');
if (retCode < 0) { lastLen = res.stdout.length;
let rc = await fs.exec('/bin/cat', [ rcFile ], null, rpc_opt); }
if (rc.code != 0) { if (retCode < 0) {
fixLogEnd(); let rc = await fs.exec('/bin/cat', [ rcFile ], null, rpc_opt);
resolve(callback.call(ctx, 545, 'ERROR: cannot read file "' + rcFile + '"')); if (rc.code != 0) {
return; clearInterval(timer);
}
if (rc.stdout) {
retCode = parseInt(rc.stdout.trim(), 10);
}
}
if (retCode >= 0) {
fixLogEnd(); fixLogEnd();
if (retCode == 0 && res.stdout) { return callback(cbarg, 545, 'ERROR: cannot read file "' + rcFile + '"');
resolve(callback.call(ctx, 0, res.stdout));
return;
}
resolve(callback.call(ctx, retCode, 'ERROR: Process failed with error ' + retCode));
return;
} }
setTimeout(epoll, 500); if (rc.stdout) {
} catch (e) { retCode = parseInt(rc.stdout.trim(), 10);
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
} }
}
if (retCode >= 0) {
clearInterval(timer);
fixLogEnd(); fixLogEnd();
let errtxt = 'ERROR: execAndRead: ' + e.message; if (retCode == 0 && res.stdout) {
errtxt += 'ERROR: execAndRead: ' + e.stack?.trim().split('\n')[0]; return callback(cbarg, 0, res.stdout);
callback.call(ctx, 540, errtxt); }
reject(e); return callback(cbarg, retCode, 'ERROR: Process failed with error ' + retCode);
} }
} catch (e) {
if (e.message?.includes('RPC call to file/exec failed with error -32000: Object not found')) {
console.warn('WARN: execAndRead: ' + e.message);
return; // goto next timer iteration
}
clearInterval(timer);
fixLogEnd();
let errtxt = 'ERROR: execAndRead: ' + e.message;
errtxt += 'ERROR: execAndRead: ' + e.stack?.trim().split('\n')[0];
return callback(cbarg, 540, errtxt);
} finally {
timerBusy = false;
} }
epoll(); }, 500);
});
}, },
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

@@ -25,28 +25,35 @@ return baseclass.extend({
this.logArea.scrollTop = this.logArea.scrollHeight; this.logArea.scrollTop = this.logArea.scrollHeight;
}, },
setBtnMode: function(check, install, cancel) setBtnMode: function(enable)
{ {
this.btn_check.disabled = check ? false : true; this.btn_cancel.disabled = enable ? false : true;
this.btn_install.disabled = install ? false : true; this.btn_action.disabled = (enable == 2) ? false : true;
this.btn_cancel.disabled = cancel ? false : true;
}, },
setStage: function(stage, btn_flag = true) setStage: function(stage, btn_flag = true)
{ {
if (stage == 0) this.setBtnMode(1, 0, 1); if (stage == 0) {
if (stage == 1) this.setBtnMode(0, 0, 1); this.btn_action.textContent = _('Check for updates');
if (stage == 2) this.setBtnMode(1, 1, 1); this.btn_action.classList.remove('hidden');
if (stage == 3) this.setBtnMode(0, 0, 0); } else
if (stage == 8) this.setBtnMode(0, 0, 1); if (stage == 1) {
if (stage >= 9) this.setBtnMode(0, 0, 0); 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; this.stage = stage;
}, },
checkUpdates: async function(ev) checkUpdates: async function()
{ {
this._action = 'checkUpdates'; this._action = 'checkUpdates';
this.setStage(1); this.setStage(0);
this.setBtnMode(0);
this.pkg_url = null; this.pkg_url = null;
this.appendLog(_('Checking for updates...')); this.appendLog(_('Checking for updates...'));
let cmd = [ fn_update_pkg_sh, '-c' ]; // check for updates let cmd = [ fn_update_pkg_sh, '-c' ]; // check for updates
@@ -54,92 +61,82 @@ return baseclass.extend({
cmd.push('-p'); // include prereleases ZIP-files cmd.push('-p'); // include prereleases ZIP-files
} }
this.forced_reinstall = document.getElementById('cfg_forced_reinstall').checked; this.forced_reinstall = document.getElementById('cfg_forced_reinstall').checked;
return tools.execAndRead({ let log = '/tmp/'+tools.appName+'_pkg_check.log';
cmd: cmd, let callback = this.execAndReadCallback;
log: '/tmp/'+tools.appName+'_pkg_check.log', let wnd = this;
logArea: this.logArea, return tools.execAndRead({ cmd: cmd, log: log, logArea: this.logArea, callback: callback, cbarg: wnd });
callback: this.execAndReadCallback,
ctx: this,
});
}, },
installUpdates: async function(ev) installUpdates: async function()
{ {
this._action = 'installUpdates';
this.setStage(1);
this.setBtnMode(0);
if (!this.pkg_url || this.pkg_url.length < 10) { if (!this.pkg_url || this.pkg_url.length < 10) {
this.appendLog('ERROR: pkg_url = null'); this.appendLog('ERROR: pkg_url = null');
this.setStage(9); this.setStage(999);
return; return;
} }
this._action = 'installUpdates';
this.setStage(3);
this.appendLog(_('Install updates...')); this.appendLog(_('Install updates...'));
let cmd = [ fn_update_pkg_sh, '-u', this.pkg_url ]; // update packages let cmd = [ fn_update_pkg_sh, '-u', this.pkg_url ]; // update packages
if (document.getElementById('cfg_forced_reinstall').checked == true) { if (document.getElementById('cfg_forced_reinstall').checked == true) {
cmd.push('-f'); // forced reinstall if same version cmd.push('-f'); // forced reinstall if same version
} }
//this._test = 1; cmd.push('-t'); cmd.push('45'); // only for testing //this._test = 1; cmd.push('-t'); cmd.push('45'); // only for testing
return tools.execAndRead({ let log = '/tmp/'+tools.appName+'_pkg_install.log';
cmd: cmd, let hiderow = /^ \* resolve_conffiles.*(?:\r?\n|$)/gm;
log: '/tmp/'+tools.appName+'_pkg_install.log', let callback = this.execAndReadCallback;
logArea: this.logArea, let wnd = this;
hiderow: /^ \* resolve_conffiles.*(?:\r?\n|$)/gm, return tools.execAndRead({ cmd: cmd, log: log, logArea: this.logArea, hiderow: hiderow, callback: callback, cbarg: wnd });
callback: this.execAndReadCallback,
ctx: this,
});
}, },
execAndReadCallback: function(rc, txt = '') execAndReadCallback: function(wnd, rc, txt = '')
{ {
//console.log('execAndReadCallback = ' + rc + '; _action = ' + this._action); //console.log('execAndReadCallback = ' + rc + '; _action = ' + wnd._action);
if (rc == 0 && txt) { if (rc == 0 && txt) {
let code = txt.match(/^RESULT:\s*\(([^)]+)\)\s+.+$/m); let code = txt.match(/^RESULT:\s*\(([^)]+)\)\s+.+$/m);
if (this._action == 'checkUpdates') { if (wnd._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); let pkg_url = txt.match(/^ZAP_PKG_URL\s*=\s*(.+)$/m);
if (code && pkg_url) { if (code && pkg_url) {
if (!this.forced_reinstall) { wnd.appendLog('=========================================================');
if (code[1] == 'E' || code[1] == 'G') { wnd.pkg_url = pkg_url[1];
this.setStage(0); // install not needed code = code[1];
return; if (code == 'E' && !wnd.forced_reinstall) {
} wnd.setStage(999); // install not needed
return;
} }
this.pkg_url = pkg_url[1]; wnd.setStage(1);
this.setStage(2); // enable all buttons wnd.setBtnMode(2); // enable all buttons
return; // install allowed return; // install allowed
} }
} }
if (this._action == 'installUpdates') { if (wnd._action == 'installUpdates') {
if (this._test || (code && code[1] == '+')) { if (wnd._test || (code && code[1] == '+')) {
this.setStage(9); wnd.stage = 999;
this.appendLog('Please update WEB-page (press F5)'); wnd.btn_action.textContent = _('OK');
wnd.btn_action.disabled = false;
wnd.btn_cancel.disabled = true;
return; return;
} }
} }
} }
this.setStage(0);
if (rc >= 500) { if (rc >= 500) {
if (txt) { if (txt) {
this.appendLog(txt.startsWith('ERROR') ? txt : 'ERROR: ' + txt); wnd.appendLog(txt.startsWith('ERROR') ? txt : 'ERROR: ' + txt);
} else { } else {
this.appendLog('ERROR: ' + this._action + ': Terminated with error code = ' + rc); wnd.appendLog('ERROR: ' + wnd._action + ': Terminated with error code = ' + rc);
} }
} else { } else {
this.appendLog('ERROR: Process finished with retcode = ' + rc); wnd.appendLog('ERROR: Process finished with retcode = ' + rc);
}
wnd.setStage(999);
if (wnd._action == 'checkUpdates') {
wnd.appendLog('=========================================================');
} }
this.appendLog('=========================================================');
}, },
openUpdateDialog: function(pkg_arch) openUpdateDialog: function(pkg_arch)
{ {
if (tools.checkUnsavedChanges()) {
ui.addNotification(null, E('p', _('You have unapplied changes')));
return;
}
this.stage = 0; this.stage = 0;
this.pkg_arch = pkg_arch; this.pkg_arch = pkg_arch;
this.pkg_url = null; this.pkg_url = null;
@@ -169,30 +166,25 @@ return baseclass.extend({
}, _('Cancel')); }, _('Cancel'));
this.btn_cancel.onclick = ui.hideModal; this.btn_cancel.onclick = ui.hideModal;
this.btn_check = E('button', { this.btn_action = E('button', {
'id': 'btn_check', 'id': 'btn_action',
'name': 'btn_check', 'name': 'btn_action',
'class': btn_style_action, 'class': btn_style_action,
}, _('Check')); }, 'BUTTON_ACTION');
this.btn_check.onclick = ui.createHandlerFn(this, this.checkUpdates); this.btn_action.onclick = ui.createHandlerFn(this, () => {
if (this.stage == 0) {
this.btn_install = E('button', { return this.checkUpdates();
'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);
} }
if (this.stage == 1) {
return this.installUpdates();
}
return ui.hideModal();
}); });
this.setStage(0); this.setStage(0);
this.setBtnMode(2);
ui.showModal(_('Check for updates and install'), [ ui.showModal(_('Package update'), [
E('div', { 'class': 'cbi-section' }, [ E('div', { 'class': 'cbi-section' }, [
exclude_prereleases, exclude_prereleases,
E('br'), E('br'), E('br'), E('br'),
@@ -202,11 +194,9 @@ return baseclass.extend({
this.logArea, this.logArea,
]), ]),
E('div', { 'class': 'right' }, [ E('div', { 'class': 'right' }, [
this.btn_check,
' ',
this.btn_install,
' ',
this.btn_cancel, this.btn_cancel,
' ',
this.btn_action,
]) ])
]); ]);
} }

View File

@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=zapret PKG_NAME:=zapret
PKG_VERSION:=72.20260128 PKG_VERSION:=72.20260111
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=bol-van PKG_MAINTAINER:=bol-van
@@ -14,8 +14,8 @@ PKG_LICENSE_FILES:=docs/LICENSE.txt
PKG_SOURCE_URL:=https://github.com/bol-van/zapret.git PKG_SOURCE_URL:=https://github.com/bol-van/zapret.git
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=119e243b3664d6a512ed8b6ab61dcba00987105c PKG_SOURCE_VERSION:=a775aa7aaa4903a8c0870f9c16918e9d19d83772
PKG_SOURCE_DATE:=2026-01-28 PKG_SOURCE_DATE:=2026-01-11
#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/zapret/archive/refs/tags/v$(PKG_VERSION).tar.gz?
@@ -56,165 +56,91 @@ define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR)/mdig $(TARGET_CONFIGURE_OPTS) $(MAKE) -C $(PKG_BUILD_DIR)/mdig $(TARGET_CONFIGURE_OPTS)
endef 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/zapret
/opt/zapret/config
/opt/zapret/ipset/
/opt/zapret/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/zapret
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/$(MAKE_PATH) $(INSTALL_DIR) $(1)/opt/zapret/$(MAKE_PATH)
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(MAKE_PATH)/nfqws $(1)$(ZAPRET_DIR)/$(MAKE_PATH)/ $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(MAKE_PATH)/nfqws $(1)/opt/zapret/$(MAKE_PATH)/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/ip2net $(INSTALL_DIR) $(1)/opt/zapret/ip2net
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ip2net/ip2net $(1)$(ZAPRET_DIR)/ip2net/ $(INSTALL_BIN) $(PKG_BUILD_DIR)/ip2net/ip2net $(1)/opt/zapret/ip2net/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/mdig $(INSTALL_DIR) $(1)/opt/zapret/mdig
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mdig/mdig $(1)$(ZAPRET_DIR)/mdig/ $(INSTALL_BIN) $(PKG_BUILD_DIR)/mdig/mdig $(1)/opt/zapret/mdig/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/common $(INSTALL_DIR) $(1)/opt/zapret/common
$(CP) $(PKG_BUILD_DIR)/common/* $(1)$(ZAPRET_DIR)/common/ $(CP) $(PKG_BUILD_DIR)/common/* $(1)/opt/zapret/common/
#$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/docs #$(INSTALL_DIR) $(1)/opt/zapret/docs
#$(CP) $(PKG_BUILD_DIR)/docs/* $(1)$(ZAPRET_DIR)/docs/ #$(CP) $(PKG_BUILD_DIR)/docs/* $(1)/opt/zapret/docs/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/files $(INSTALL_DIR) $(1)/opt/zapret/files
$(CP) $(PKG_BUILD_DIR)/files/* $(1)$(ZAPRET_DIR)/files/ $(CP) $(PKG_BUILD_DIR)/files/* $(1)/opt/zapret/files/
$(CP) ./files/* $(1)$(ZAPRET_DIR)/files/ $(CP) ./files/* $(1)/opt/zapret/files/
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/ipset $(INSTALL_DIR) $(1)/opt/zapret/ipset
$(CP) $(PKG_BUILD_DIR)/ipset/* $(1)$(ZAPRET_DIR)/ipset/ $(CP) $(PKG_BUILD_DIR)/ipset/* $(1)/opt/zapret/ipset/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/blockcheck.sh $(1)$(ZAPRET_DIR)/blockcheck.sh $(INSTALL_BIN) $(PKG_BUILD_DIR)/blockcheck.sh $(1)/opt/zapret/blockcheck.sh
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/tmp #$(INSTALL_DATA) $(PKG_BUILD_DIR)/config.default $(1)/opt/zapret/config.default
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/init.d/openwrt $(INSTALL_DIR) $(1)/opt/zapret/tmp
$(CP) $(PKG_BUILD_DIR)/init.d/openwrt/* $(1)$(ZAPRET_DIR)/init.d/openwrt/ $(INSTALL_DIR) $(1)/opt/zapret/init.d/openwrt
$(CP) $(PKG_BUILD_DIR)/init.d/openwrt/* $(1)/opt/zapret/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-zapret $(1)/etc/hotplug.d/iface/90-zapret
$(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/zapret
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/init.d $(INSTALL_DATA) ./config.default $(1)/opt/zapret/config.default
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/init.d/openwrt $(INSTALL_DATA) ./ipset/zapret-hosts-google.txt $(1)/opt/zapret/ipset/zapret-hosts-google.txt
$(INSTALL_DIR) $(1)$(ZAPRET_DIR)/init.d/openwrt/custom.d $(INSTALL_DATA) ./ipset/zapret-hosts-user.txt $(1)/opt/zapret/ipset/zapret-hosts-user.txt
$(INSTALL_DATA) ./ipset/zapret-hosts-user-exclude.txt $(1)/opt/zapret/ipset/zapret-hosts-user-exclude.txt
$(INSTALL_DATA) ./ipset/zapret-ip-exclude.txt $(1)/opt/zapret/ipset/zapret-ip-exclude.txt
$(INSTALL_DIR) $(1)/opt/zapret/ipset_def
$(INSTALL_DATA) ./ipset/zapret-hosts-google.txt $(1)/opt/zapret/ipset_def/zapret-hosts-google.txt
$(INSTALL_DATA) ./ipset/zapret-hosts-user.txt $(1)/opt/zapret/ipset_def/zapret-hosts-user.txt
$(INSTALL_DATA) ./ipset/zapret-hosts-user-exclude.txt $(1)/opt/zapret/ipset_def/zapret-hosts-user-exclude.txt
$(INSTALL_DATA) ./ipset/zapret-ip-exclude.txt $(1)/opt/zapret/ipset_def/zapret-ip-exclude.txt
$(INSTALL_DIR) $(1)/opt/zapret/init.d
$(INSTALL_DIR) $(1)/opt/zapret/init.d/openwrt
$(INSTALL_DIR) $(1)/opt/zapret/init.d/openwrt/custom.d
$(CP) ./custom.d/* $(1)/opt/zapret/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/zapret-uci-def-cfg.sh
# install all sh-scripts $(INSTALL_BIN) ./uci-def-cfg.sh $(1)/opt/zapret/uci-def-cfg.sh
$(CP) ./*.sh $(1)$(ZAPRET_DIR)/ $(INSTALL_BIN) ./comfunc.sh $(1)/opt/zapret/comfunc.sh
rm -f $(1)$(ZAPRET_DIR)/init.d.sh $(INSTALL_BIN) ./def-cfg.sh $(1)/opt/zapret/def-cfg.sh
# Install conf files $(INSTALL_BIN) ./renew-cfg.sh $(1)/opt/zapret/renew-cfg.sh
$(foreach cfg,$(ZAPRET_CONFFILES), \ $(INSTALL_BIN) ./restore-def-cfg.sh $(1)/opt/zapret/restore-def-cfg.sh
rel="$(cfg:$(ZAPRET_DIR)/%=%)"; \ $(INSTALL_BIN) ./sync_config.sh $(1)/opt/zapret/sync_config.sh
src="./$$$$rel"; \ $(INSTALL_BIN) ./script-exec.sh $(1)/opt/zapret/script-exec.sh
if echo "$$$$rel" | grep -q "/custom.d/"; then \ $(INSTALL_BIN) ./update-pkg.sh $(1)/opt/zapret/update-pkg.sh
src="./custom.d/$$$$(basename $$$$rel)"; \ # Fix permisions
fi; \ chmod 644 $(1)/opt/zapret/ipset/*.txt
dst="$(1)$(cfg)"; \ chmod 644 $(1)/opt/zapret/ipset_def/*.txt
mkdir -p "$(1)$(dir $(cfg))"; \ chmod 644 $(1)/opt/zapret/init.d/openwrt/custom.d/*.sh
rm -f "$$$${dst}"; \ chmod 644 $(1)/opt/zapret/config.default
if [ -f "$$$${src}" ]; then \ chmod 755 $(1)/opt/zapret/*.sh
$(INSTALL_DATA) "$$$${src}" "$$$${dst}"; \ chmod 755 $(1)/opt/zapret/$(MAKE_PATH)/*
else \ chmod 755 $(1)/opt/zapret/ip2net/*
$(INSTALL_DATA) /dev/null "$$$${dst}"; \ chmod 755 $(1)/opt/zapret/mdig/*
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/zapret" ]; then
ZAPRET_INITD=/etc/init.d/zapret SCRIPT=$$( readlink /etc/init.d/zapret )
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 zapret 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/zapret" ]; then
$${ZAPRET_INITD} running && $${ZAPRET_INITD} stop >/dev/null 2>&1 /etc/init.d/zapret running && /etc/init.d/zapret stop >/dev/null 2>&1
fi fi
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-google.txt" ]; then
if [ -f "/opt/zapret/ipset/zapret-hosts-user.txt" ]; then if [ -f "/opt/zapret/ipset/zapret-hosts-user.txt" ]; then
CFGLISTHASH=$$( md5sum "/opt/zapret/ipset/zapret-hosts-user.txt" | awk '{print $$1;}' ) CFGLISTHASH=$$( md5sum "/opt/zapret/ipset/zapret-hosts-user.txt" | awk '{print $$1;}' )
@@ -231,21 +157,8 @@ 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_INITD=/etc/init.d/zapret
ZAPRET_CFG=/etc/config/zapret
ZAPRET_CONFIG=/opt/zapret/config ZAPRET_CONFIG=/opt/zapret/config
ZAPRET_CONFIG_DEF="/opt/zapret/config.default" 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}"
@@ -258,10 +171,8 @@ if [ -z "$${IPKG_INSTROOT}" ]; then
echo "Current file $${ZAPRET_CONFIG} backuped to $${ZAPRET_CONFIG_BACKUP}" echo "Current file $${ZAPRET_CONFIG} backuped to $${ZAPRET_CONFIG_BACKUP}"
cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}" cp -f "$${ZAPRET_CONFIG_DEF}" "$${ZAPRET_CONFIG}"
fi 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/zapret" ] && 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/zapret/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/zapret merged with default uci-config"
@@ -273,13 +184,13 @@ if [ -z "$${IPKG_INSTROOT}" ]; then
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/zapret enable
# stop all # stop all
$${ZAPRET_INITD} stop_fw >/dev/null 2>&1 /etc/init.d/zapret stop_fw
$${ZAPRET_INITD} stop_daemons >/dev/null 2>&1 /etc/init.d/zapret stop_daemons
ps w | grep '/opt/zapret/nfq/nfqws' | grep -v grep | awk '{print $$1}' | xargs -r kill -9 ps w | grep '/opt/zapret/nfq/nfqws' | grep -v grep | awk '{print $$1}' | xargs -r kill -9
# start main service # start main service
$${ZAPRET_INITD} start /etc/init.d/zapret 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,10 +201,8 @@ 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/zapret
ZAPRET_BASE=/opt/zapret ZAPRET_BASE=/opt/zapret
ZAPRET_INITD=/etc/init.d/zapret
ZAPRET_CFG=/etc/config/zapret
ZAPRET_CONFIG=/opt/zapret/config ZAPRET_CONFIG=/opt/zapret/config
ZAPRET_CONFIG_DEF="/opt/zapret/config.default" ZAPRET_CONFIG_DEF="/opt/zapret/config.default"
OPENWRT_FW_INCLUDE=/etc/firewall.zapret OPENWRT_FW_INCLUDE=/etc/firewall.zapret
@@ -308,8 +217,8 @@ 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/zapret running && /etc/init.d/zapret stop
$${ZAPRET_INITD} disable >/dev/null 2>&1 /etc/init.d/zapret disable
ps w | grep '/opt/zapret/nfq/nfqws' | grep -v grep | awk '{print $$1}' | xargs -r kill -9 ps w | grep '/opt/zapret/nfq/nfqws' | grep -v grep | awk '{print $$1}' | xargs -r kill -9
remove_openwrt_firewall remove_openwrt_firewall
nft_del_table nft_del_table
@@ -322,9 +231,7 @@ 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/zapret-opkg" ] && rm -f "/etc/config/zapret-opkg"
rm -f /etc/config/zapret.opkg*
rm -f /etc/config/zapret.apk*
[ -f "/opt/zapret/config" ] && cp -f /opt/zapret/config "/opt/zapret/config.backup" [ -f "/opt/zapret/config" ] && cp -f /opt/zapret/config "/opt/zapret/config.backup"
#rm -rf /opt/zapret #rm -rf /opt/zapret
#echo "Directory /opt/zapret removed!" #echo "Directory /opt/zapret removed!"

View File

@@ -130,7 +130,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
@@ -170,25 +170,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 '$ZAPRET_CFG_NAME+\*.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 '$ZAPRET_CFG_NAME\*\.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 '$ZAPRET_CFG_NAME+*.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 +188,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 $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 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

@@ -155,5 +155,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/zapret+<DAEMON_NAME>+<DAEMON_IDNUM>+<DAEMON_CFGNAME>.log"

View File

@@ -4,7 +4,7 @@
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,7 +19,6 @@ 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/zapret+<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_RETRANS_THRESHOLD='3' set $cfgname.config.AUTOHOSTLIST_RETRANS_THRESHOLD='3'
@@ -48,7 +47,7 @@ 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.NFQWS_PORTS_TCP='80,443'
@@ -62,7 +61,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'
@@ -76,7 +75,7 @@ function set_cfg_nfqws_strat
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 <HOSTLIST> --filter-tcp=443 <HOSTLIST>
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
@@ -105,7 +104,7 @@ function set_cfg_nfqws_strat
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 <HOSTLIST> --filter-tcp=443 <HOSTLIST>
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
@@ -138,7 +137,7 @@ function set_cfg_nfqws_strat
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 <HOSTLIST> --filter-tcp=443 <HOSTLIST>
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
@@ -171,7 +170,7 @@ function set_cfg_nfqws_strat
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 --filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
@@ -212,7 +211,7 @@ function set_cfg_nfqws_strat
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 --filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
@@ -253,7 +252,7 @@ function set_cfg_nfqws_strat
set $cfgname.config.NFQWS_PORTS_TCP='80,443,2053,2083,2087,2096,8443' 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_PORTS_UDP='443,19294-19344,50000-50100'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 --filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
@@ -293,63 +292,12 @@ function set_cfg_nfqws_strat
commit $cfgname commit $cfgname
EOF EOF
fi 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 if [ "$strat" = "ALT7_by_Flowseal" ]; then
uci batch <<-EOF uci batch <<-EOF
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 --filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
@@ -385,7 +333,7 @@ function set_cfg_nfqws_strat
set $cfgname.config.NFQWS_PORTS_TCP='80,443' set $cfgname.config.NFQWS_PORTS_TCP='80,443'
set $cfgname.config.NFQWS_PORTS_UDP='443' set $cfgname.config.NFQWS_PORTS_UDP='443'
set $cfgname.config.NFQWS_OPT=" set $cfgname.config.NFQWS_OPT="
--comment=Strategy__$strat # Strategy $strat
--filter-tcp=443 --filter-tcp=443
--hostlist=/opt/zapret/ipset/zapret-hosts-google.txt --hostlist=/opt/zapret/ipset/zapret-hosts-google.txt
@@ -443,17 +391,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,36 +1,14 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2026 remittor # Copyright (c) 2026 remittor
. /opt/zapret/comfunc.sh
ZAP_TMP_DIR=/tmp/zapret_dwc ZAP_TMP_DIR=/tmp/zapret_dwc
opt_sites= rm -rf $ZAP_TMP_DIR
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_TIMEOUT=5
CURL_MAXBODY=65536 CURL_RANGETO=65535
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 if ! command -v curl >/dev/null 2>&1; then
echo "ERROR: package \"curl\" not installed!" echo "ERROR: package \"curl\" not installed!"
@@ -46,30 +24,10 @@ if ! echo "$CURL_INFO" | grep -q 'https'; then
return 11 return 11
fi 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 'Original sources: https://github.com/hyperion-cs/dpi-checkers'
#echo 'WEB-version: https://hyperion-cs.github.io/dpi-checkers/ru/tcp-16-20/' #echo 'WEB-version: https://hyperion-cs.github.io/dpi-checkers/ru/tcp-16-20/'
TEST_SUITE=' TEST_SUITE='[
{ id: "US.CF-01", provider: "🇺🇸 Cloudflare", times: 1, url: "https://img.wzstats.gg/cleaver/gunFullDisplay" }, { 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-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-03", provider: "🇺🇸 Cloudflare", times: 1, url: "https://api.frankfurter.dev/v1/2000-01-01..2002-12-31" },
@@ -78,7 +36,7 @@ TEST_SUITE='
{ id: "DE.HE-01", provider: "🇩🇪 Hetzner", times: 1, url: "https://j.dejure.org/jcg/doctrine/doctrine_banner.webp" }, { 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: "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-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-02", provider: "🇫🇮 Hetzner", times: 1, url: "https://5fd8c176.nip.io/1MB.bin" },
{ id: "FI.HE-03", provider: "🇫🇮 Hetzner", times: 1, url: "https://5fd8bdae.nip.io/1MB.bin" }, { 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: "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-01", provider: "🇫🇷 OVH", times: 1, url: "https://eu.api.ovh.com/console/rapidoc-min.js" },
@@ -87,7 +45,7 @@ TEST_SUITE='
{ id: "DE.AWS-01", provider: "🇩🇪 AWS", times: 1, url: "https://www.getscope.com/assets/fonts/fa-solid-900.woff2" }, { 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.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.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: "US.FST-01", provider: "🇺🇸 Fastly", times: 1, url: "https://www.jetblue.com/main.c7b61d59416f714f.js" },
{ id: "CA.FST-01", provider: "🇨🇦 Fastly", times: 1, url: "https://www.cnn10.com/" }, { 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: "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: "PL.AKM-01", provider: "🇵🇱 Akamai", times: 1, url: "https://media-assets.stryker.com/is/image/stryker/gateway_1?$max_width_1410$" },
@@ -95,214 +53,66 @@ TEST_SUITE='
{ id: "FR.CNTB-01", provider: "🇫🇷 Contabo", times: 1, url: "https://airsea.no/images/main_logo.png" }, { 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: "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" } { 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 function trim
{ {
echo "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' echo "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
} }
mkdir -p "$ZAP_TMP_DIR" mkdir -p $ZAP_TMP_DIR
: > "$TARGET_LIST_FILE" ID=0
IDX=0 while IFS='|' read -r TAG PROVIDER TIMES URL; do
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 [ -z "$TAG" ] && continue
ID3=$( printf '%03d' "$ID" ) ID=$((ID+1))
RANGETO="" ID3=$(printf '%03d' "$ID")
REDIRECT="" COUNTRY="$(echo "$TAG" | cut -d. -f1)"
USERAGENT="$CURL_USERAGENT" CNTFLAG="$(echo "$PROVIDER" | awk '{print $1}')"
if [ "$opt_sites" = true ]; then PROVIDER="$(echo "$PROVIDER" | cut -d' ' -f2-)"
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#*://}" URL_NO_PROTO="${URL#*://}"
DOMAIN="${URL_NO_PROTO%%/*}" DOMAIN="${URL_NO_PROTO%%/*}"
URLPATH="/${URL_NO_PROTO#*/}" URLPATH="/${URL_NO_PROTO#*/}"
[ "$URLPATH" = "/$URL_NO_PROTO" ] && URLPATH="/" [ "$URLPATH" = "/$URL_NO_PROTO" ] && URLPATH="/"
#echo "TAG=$TAG , COUNTRY=$COUNTRY , PROVIDER=$PROVIDER , DOMAIN=$DOMAIN , URL=$URL" #echo "TAG=$TAG , COUNTRY=$COUNTRY , PROVIDER=$PROVIDER , TIMES=$TIMES , URL=$URL"
FNAME="$ZAP_TMP_DIR/$ID3=$TAG=$PROVIDER"
( (
DST_IP= DST_IP=$( curl -4 -s -o /dev/null -w '%{remote_ip}\n' $DOMAIN )
RESOLVE_OPT= if [ -z "$DST_IP" ]; then
if [ "$opt_dig" != "" ]; then DST_IP="$( ping -c1 "$DOMAIN" 2>/dev/null | sed -n '1s/.*(\([0-9.]*\)).*/\1/p')"
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 fi
if [ "$DST_IP" = "" ]; then curl -k $URL --resolve $DOMAIN:443:$DST_IP -o /dev/null -s -w '%{size_download}\n' --max-time $CURL_TIMEOUT --range 0-$CURL_RANGETO
DST_IP=$( ping -c1 "$DOMAIN" 2>/dev/null | sed -n '1s/.*(\([0-9.]*\)).*/\1/p' ) ) >"$ZAP_TMP_DIR/$ID3.$TAG.txt" 2>&1 &
fi done <<EOF
[ "$DST_IP" != "" ] && RESOLVE_OPT="--resolve $DOMAIN:443:$DST_IP" $(printf '%s\n' "$TEST_SUITE" | sed -n '
echo "$DST_IP" > "$FNAME.ip" s/.*id:[[:space:]]*"\([^"]*\)".*provider:[[:space:]]*"\([^"]*\)".*times:[[:space:]]*\([0-9]\+\).*url:[[:space:]]*"\([^"]*\)".*/\1|\2|\3|\4/p
echo "$URL" > "$FNAME.url" ')
curl "$URL" \ EOF
$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 wait
FAIL_URL_LIST="$ZAP_TMP_DIR/FAIL_URL_LIST.txt" for file in $(ls "$ZAP_TMP_DIR"/*.txt | sort); do
rm -f "$FAIL_URL_LIST"
printf '%s\n' "$ZAP_TMP_DIR"/*.log | sort | while IFS= read -r file; do
[ -f "$file" ] || continue [ -f "$file" ] || continue
FILENAME="${file##*/}" tag="${file##*/}"
FILENAME="${FILENAME%.log}" tag="${tag%.txt}"
ID=$( echo "$FILENAME" | cut -d= -f1) tag="${tag#*.}"
TAG=$( echo "$FILENAME" | cut -d= -f2) res=$( cat "$file" )
PROVIDER=$(echo "$FILENAME" | cut -d= -f3 ) res=$( trim "$res" )
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= status=
if [ ! -f "$FNAME.hdr" ]; then case "$res" in
status="ERROR: cannot Get Headers" ''|*[!0-9]*)
elif [ ! -s "$FNAME.hdr" ]; then status="Error (incorrect value)"
status="ERROR: cannot get headers" ;;
elif [ ! -f "$FNAME.body" ]; then esac
status="Possibly detected*" if [ -z "$status" ]; then
elif [ ! -s "$FNAME.body" ]; then if [ "$res" = 0 ]; then
status="Possibly detected" status="Possibly detected"
else elif [ "$res" -lt $CURL_RANGETO ]; then
if [ $BODY_SIZE -lt $REQ_SIZE ]; then status="Failed to complete detection"
status="Failed (recv $BODY_SIZE bytes)"
res=5
else else
status="[ OK ]" status="[ OK ]"
res=100
fi fi
fi fi
if [ "$opt_sites" = true ]; then printf '%12s: %s \n' "$tag" "$status"
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 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 return 0

View File

@@ -70,18 +70,18 @@ function boot
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

@@ -13,11 +13,6 @@ 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"

View File

@@ -46,7 +46,7 @@ function sync_param
local value="$( uci -q get $ZAPRET_CFG_SEC.$param )" local value="$( uci -q get $ZAPRET_CFG_SEC.$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
@@ -93,7 +93,6 @@ 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
@@ -102,7 +101,6 @@ sync_param AUTOHOSTLIST_FAIL_TIME
if [ $ZAPRET_CFG_NAME = "zapret2" ]; then if [ $ZAPRET_CFG_NAME = "zapret2" ]; then
sync_param AUTOHOSTLIST_INCOMING_MAXSEQ sync_param AUTOHOSTLIST_INCOMING_MAXSEQ
sync_param AUTOHOSTLIST_RETRANS_MAXSEQ sync_param AUTOHOSTLIST_RETRANS_MAXSEQ
sync_param AUTOHOSTLIST_RETRANS_RESET
sync_param AUTOHOSTLIST_UDP_IN sync_param AUTOHOSTLIST_UDP_IN
sync_param AUTOHOSTLIST_UDP_OUT sync_param AUTOHOSTLIST_UDP_OUT
fi fi

View File

@@ -1,15 +1,11 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2024 remittor # Copyright (c) 2024 remittor
[ ! -f /opt/zapret/comfunc.sh ] && exit 0
. /opt/zapret/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 "$ZAPRET_BASE/ipset/zapret-hosts-google.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-google.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-auto.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-auto.txt" #[ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-auto.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-auto.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-user.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-user.txt" [ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-user.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-user.txt"
[ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-user-ipban.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-user-ipban.txt" [ ! -f "$ZAPRET_BASE/ipset/zapret-hosts-user-ipban.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-hosts-user-ipban.txt"
#[ ! -f "$ZAPRET_BASE/ipset/zapret-ip.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-ip.txt" #[ ! -f "$ZAPRET_BASE/ipset/zapret-ip.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-ip.txt"
@@ -18,6 +14,5 @@ mkdir -p $ZAPRET_BASE/ipset
[ ! -f "$ZAPRET_BASE/ipset/zapret-ip-user-ipban.txt" ] && touch "$ZAPRET_BASE/ipset/zapret-ip-user-ipban.txt" [ ! -f "$ZAPRET_BASE/ipset/zapret-ip-user-ipban.txt" ] && touch "$ZAPRET_BASE/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

@@ -75,13 +75,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
@@ -491,7 +487,7 @@ if [ "$opt_update" != "" ]; then
fi fi
fi fi
if ! command -v unzip >/dev/null 2>&1; then if ! command -v unzip >/dev/null 2>&1; then
echo "ERROR: package \"unzip\" not installed!" echo "ERROR: package \"upzip\" 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
@@ -529,14 +525,6 @@ if [ "$opt_update" != "" ]; then
if [ "$opt_forced" = true ]; then if [ "$opt_forced" = true ]; then
pkg_mgr_update pkg_mgr_update
fi 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"