diff --git a/autoinstall/autoinstall.sh b/autoinstall/2.x/autoinstall.sh similarity index 81% rename from autoinstall/autoinstall.sh rename to autoinstall/2.x/autoinstall.sh index 04cc3bc..78812df 100755 --- a/autoinstall/autoinstall.sh +++ b/autoinstall/2.x/autoinstall.sh @@ -7,11 +7,12 @@ PROXY_MODE=1 BLACKLIST=0 LUA_MODULE=0 LUCI_APP=1 +HTTPS_DNS_PROXY=1 -OWRT_VERSION="22.03" -RUAB_VERSION="0.9.7-1" -RUAB_MOD_LUA_VERSION="0.9.7-1" -RUAB_LUCI_APP_VERSION="0.9.7-0" +OWRT_VERSION="current" +RUAB_VERSION="2.0.0-r1" +RUAB_MOD_LUA_VERSION="2.0.0-r1" +RUAB_LUCI_APP_VERSION="2.0.0-1" BASE_URL="https://raw.githubusercontent.com/gSpotx2f/packages-openwrt/master" PKG_DIR="/tmp" @@ -27,33 +28,36 @@ URL_MOD_LUA_PKG="${BASE_URL}/${OWRT_VERSION}/ruantiblock-mod-lua_${RUAB_MOD_LUA_ URL_LUCI_APP_PKG="${BASE_URL}/${OWRT_VERSION}/luci-app-ruantiblock_${RUAB_LUCI_APP_VERSION}_all.ipk" URL_LUCI_APP_RU_PKG="${BASE_URL}/${OWRT_VERSION}/luci-i18n-ruantiblock-ru_${RUAB_LUCI_APP_VERSION}_all.ipk" ### tor -URL_TORRC="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/0.9/tor/etc/tor/torrc" +URL_TORRC="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master/tor/etc/tor/torrc" ### ruantiblock-mod-lua -URL_LUA_IPTOOL="https://raw.githubusercontent.com/gSpotx2f/iptool-lua/master/5.1/iptool.lua" URL_LUA_IDN="https://raw.githubusercontent.com/haste/lua-idn/master/idn.lua" ### Local files -RUAB_CFG_DIR="${PREFIX}/etc/ruantiblock" +CONFIG_DIR="${PREFIX}/etc/ruantiblock" +USER_LISTS_DIR="${CONFIG_DIR}/user_lists" EXEC_DIR="${PREFIX}/usr/bin" -BACKUP_DIR="${RUAB_CFG_DIR}/autoinstall.bak.`date +%s`" +BACKUP_DIR="${CONFIG_DIR}/autoinstall.bak.`date +%s`" ### packages FILE_RUAB_PKG="${PKG_DIR}/ruantiblock_${RUAB_VERSION}_all.ipk" FILE_MOD_LUA_PKG="${PKG_DIR}/ruantiblock-mod-lua_${RUAB_MOD_LUA_VERSION}_all.ipk" FILE_LUCI_APP_PKG="${PKG_DIR}/luci-app-ruantiblock_${RUAB_LUCI_APP_VERSION}_all.ipk" FILE_LUCI_APP_RU_PKG="${PKG_DIR}/luci-i18n-ruantiblock-ru_${RUAB_LUCI_APP_VERSION}_all.ipk" ### ruantiblock -FILE_CONFIG="${RUAB_CFG_DIR}/ruantiblock.conf" -FILE_FQDN_FILTER="${RUAB_CFG_DIR}/fqdn_filter" -FILE_IP_FILTER="${RUAB_CFG_DIR}/ip_filter" -FILE_USER_ENTRIES="${RUAB_CFG_DIR}/user_entries" +FILE_CONFIG="${CONFIG_DIR}/ruantiblock.conf" +FILE_FQDN_FILTER="${CONFIG_DIR}/fqdn_filter" +FILE_IP_FILTER="${CONFIG_DIR}/ip_filter" +FILE_USER_ENTRIES="${CONFIG_DIR}/user_entries" +FILE_BYPASS_ENTRIES="${CONFIG_DIR}/bypass_entries" +FILE_GR_EXCLUDED_SLD="${CONFIG_DIR}/gr_excluded_sld" +FILE_GR_EXCLUDED_NETS="${CONFIG_DIR}/gr_excluded_nets" FILE_UCI_CONFIG="${PREFIX}/etc/config/ruantiblock" FILE_INIT_SCRIPT="${PREFIX}/etc/init.d/ruantiblock" FILE_MAIN_SCRIPT="${EXEC_DIR}/ruantiblock" ### tor FILE_TORRC="${PREFIX}/etc/tor/torrc" ### ruantiblock-mod-lua -FILE_LUA_IPTOOL="${PREFIX}/usr/lib/lua/iptool.lua" +#FILE_LUA_IPTOOL="${PREFIX}/usr/lib/lua/iptool.lua" FILE_LUA_IDN="${PREFIX}/usr/lib/lua/idn.lua" AWK_CMD="awk" @@ -121,9 +125,13 @@ BackupFile() { BackupCurrentConfig() { local _file MakeDir "$BACKUP_DIR" - for _file in "$FILE_CONFIG" "$FILE_FQDN_FILTER" "$FILE_IP_FILTER" "$FILE_USER_ENTRIES" "$FILE_UCI_CONFIG" "$FILE_TORRC" + for _file in `ls -1 "$CONFIG_DIR" | grep -v "$(basename $BACKUP_DIR)"` do - [ -e "$_file" ] && cp -f "$_file" "${BACKUP_DIR}/`basename ${_file}`" + cp -af "${CONFIG_DIR}/${_file}" "${BACKUP_DIR}/${_file}" + done + for _file in "$FILE_UCI_CONFIG" "$FILE_TORRC" + do + [ -e "$_file" ] && cp -af "$_file" "${BACKUP_DIR}/`basename ${_file}`" done } @@ -136,11 +144,6 @@ AppStop() { } AppStart() { - modprobe ip_set > /dev/null - modprobe ip_set_hash_ip > /dev/null - modprobe ip_set_hash_net > /dev/null - modprobe ip_set_list_set > /dev/null - modprobe xt_set > /dev/null $FILE_INIT_SCRIPT start } @@ -174,10 +177,11 @@ InstallPackages() { InstallBaseConfig() { _return_code=1 - InstallPackages "ipset" "kmod-ipt-ipset" "dnsmasq-full" + InstallPackages "dnsmasq-full" "kmod-nft-tproxy" RemoveFile "$FILE_RUAB_PKG" > /dev/null DlFile "$URL_RUAB_PKG" "$FILE_RUAB_PKG" && $OPKG_CMD install "$FILE_RUAB_PKG" > /dev/null _return_code=$? + # костыль для остановки сервиса, который запускается автоматически после установки пакета! AppStop return $_return_code } @@ -219,6 +223,7 @@ InstallTorConfig() { TorrcSettings $UCI_CMD set ruantiblock.config.proxy_mode="1" $UCI_CMD commit ruantiblock + # dnsmasq rebind protection $UCI_CMD set dhcp.@dnsmasq[0].rebind_domain='onion' $UCI_CMD commit dhcp } @@ -227,7 +232,6 @@ InstallLuaModule() { InstallPackages "lua" "luasocket" "luasec" "luabitop" RemoveFile "$FILE_MOD_LUA_PKG" > /dev/null DlFile "$URL_MOD_LUA_PKG" "$FILE_MOD_LUA_PKG" && $OPKG_CMD install "$FILE_MOD_LUA_PKG" - FileExists "$FILE_LUA_IPTOOL" || DlFile "$URL_LUA_IPTOOL" "$FILE_LUA_IPTOOL" FileExists "$FILE_LUA_IDN" || DlFile "$URL_LUA_IDN" "$FILE_LUA_IDN" $UCI_CMD set ruantiblock.config.bllist_module="/usr/libexec/ruantiblock/ruab_parser.lua" $UCI_CMD commit ruantiblock @@ -243,6 +247,10 @@ InstallLuciApp() { /etc/init.d/uhttpd restart } +InstallHttpsDnsProxy() { + InstallPackages "https-dns-proxy" "luci-app-https-dns-proxy" "luci-i18n-https-dns-proxy-ru" +} + PrintBold() { printf "\033[1m - ${1}\033[0m\n" } @@ -279,7 +287,7 @@ ConfirmProxyMode() { ConfirmBlacklist() { local _reply - printf " Select blacklist [ 1: User entries only | 2: RKN blacklist ] (default: 1, quit: q) > " + printf " Select blacklist [ 1: User entries only | 2: Full blacklist ] (default: 1, quit: q) > " read _reply case $_reply in 1|"") @@ -343,6 +351,28 @@ ConfirmLuciApp() { esac } +ConfirmHttpsDnsProxy() { + local _reply + printf " Would you like to install the https-dns-proxy? [ y | n ] (default: y, quit: q) > " + read _reply + case $_reply in + y|Y|"") + HTTPS_DNS_PROXY=1 + break + ;; + n|N) + HTTPS_DNS_PROXY=0 + break + ;; + q|Q) + printf "Bye...\n"; exit 0 + ;; + *) + InputError ConfirmHttpsDnsProxy + ;; + esac +} + ConfirmProcessing() { local _reply printf " Next, the installation will begin... Continue? [ y | n ] (default: y, quit: q) > " @@ -364,11 +394,13 @@ ConfirmProxyMode ConfirmBlacklist #ConfirmLuaModule ConfirmLuciApp +ConfirmHttpsDnsProxy ConfirmProcessing AppStop PrintBold "Updating packages list..." UpdatePackagesList PrintBold "Saving current configuration..." +#BackupCurrentConfig PrintBold "Installing basic configuration..." InstallBaseConfig if [ $? -eq 0 ]; then @@ -388,7 +420,7 @@ if [ $? -eq 0 ]; then fi if [ $BLACKLIST = 2 ]; then - PrintBold "Set RKN blacklist..." + PrintBold "Set full blacklist..." EnableBlacklist fi @@ -402,6 +434,11 @@ if [ $? -eq 0 ]; then InstallLuciApp fi + if [ $HTTPS_DNS_PROXY = 1 ]; then + PrintBold "Installing https-dns-proxy..." + InstallHttpsDnsProxy + fi + RunAtStartup SetCronTask else diff --git a/autoinstall/uninstall.sh b/autoinstall/2.x/uninstall.sh similarity index 52% rename from autoinstall/uninstall.sh rename to autoinstall/2.x/uninstall.sh index 54535bb..e280067 100755 --- a/autoinstall/uninstall.sh +++ b/autoinstall/2.x/uninstall.sh @@ -4,19 +4,27 @@ PREFIX="" ### Local files -RUAB_CFG_DIR="${PREFIX}/etc/ruantiblock" +CONFIG_DIR="${PREFIX}/etc/ruantiblock" +USER_LISTS_DIR="${CONFIG_DIR}/user_lists" EXEC_DIR="${PREFIX}/usr/bin" -BACKUP_DIR="${RUAB_CFG_DIR}/autoinstall.bak.`date +%s`" +BACKUP_DIR="${CONFIG_DIR}/autoinstall.bak.`date +%s`" HTDOCS_VIEW="${PREFIX}/www/luci-static/resources/view" HTDOCS_RUAB="${HTDOCS_VIEW}/ruantiblock" CRONTAB_FILE="/etc/crontabs/root" DATA_DIR="/tmp/ruantiblock" -DNSMASQ_DATA_FILE="/tmp/dnsmasq.d/ruantiblock.dnsmasq" +DNSMASQ_DATA_FILE="/tmp/dnsmasq.d/02-ruantiblock.dnsmasq" +DNSMASQ_DATA_FILE_TMP="${DNSMASQ_DATA_FILE}.tmp" +DNSMASQ_DATA_FILE_BYPASS="/tmp/dnsmasq.d/01-ruantiblock_bypass.dnsmasq" +SCRIPTS_DIR="/usr/share/ruantiblock" +MODULES_DIR="/usr/libexec/ruantiblock" ### ruantiblock -FILE_CONFIG="${RUAB_CFG_DIR}/ruantiblock.conf" -FILE_FQDN_FILTER="${RUAB_CFG_DIR}/fqdn_filter" -FILE_IP_FILTER="${RUAB_CFG_DIR}/ip_filter" -FILE_USER_ENTRIES="${RUAB_CFG_DIR}/user_entries" +FILE_CONFIG="${CONFIG_DIR}/ruantiblock.conf" +FILE_FQDN_FILTER="${CONFIG_DIR}/fqdn_filter" +FILE_IP_FILTER="${CONFIG_DIR}/ip_filter" +FILE_USER_ENTRIES="${CONFIG_DIR}/user_entries" +FILE_BYPASS_ENTRIES="${CONFIG_DIR}/bypass_entries" +FILE_GR_EXCLUDED_SLD="${CONFIG_DIR}/gr_excluded_sld" +FILE_GR_EXCLUDED_NETS="${CONFIG_DIR}/gr_excluded_nets" FILE_UCI_CONFIG="${PREFIX}/etc/config/ruantiblock" FILE_INIT_SCRIPT="${PREFIX}/etc/init.d/ruantiblock" FILE_MAIN_SCRIPT="${EXEC_DIR}/ruantiblock" @@ -52,9 +60,13 @@ RemoveFile() { BackupCurrentConfig() { local _file MakeDir "$BACKUP_DIR" - for _file in "$FILE_CONFIG" "$FILE_FQDN_FILTER" "$FILE_IP_FILTER" "$FILE_USER_ENTRIES" "$FILE_UCI_CONFIG" "$FILE_TORRC" + for _file in `ls -1 "$CONFIG_DIR" | grep -v "$(basename $BACKUP_DIR)"` do - [ -e "$_file" ] && cp -f "$_file" "${BACKUP_DIR}/`basename ${_file}`" + cp -af "${CONFIG_DIR}/${_file}" "${BACKUP_DIR}/${_file}" + done + for _file in "$FILE_UCI_CONFIG" "$FILE_TORRC" + do + [ -e "$_file" ] && cp -af "$_file" "${BACKUP_DIR}/`basename ${_file}`" done } @@ -67,10 +79,12 @@ DisableStartup() { } RemoveCronTask() { - $AWK_CMD -v FILE_MAIN_SCRIPT="$FILE_MAIN_SCRIPT" '$0 !~ FILE_MAIN_SCRIPT { - print $0; - }' "$CRONTAB_FILE" > "${CRONTAB_FILE}.tmp" && mv -f "${CRONTAB_FILE}.tmp" "$CRONTAB_FILE" - /etc/init.d/cron restart + if [ -e "$CRONTAB_FILE" ]; then + $AWK_CMD -v FILE_MAIN_SCRIPT="$FILE_MAIN_SCRIPT" '$0 !~ FILE_MAIN_SCRIPT { + print $0; + }' "$CRONTAB_FILE" > "${CRONTAB_FILE}.tmp" && mv -f "${CRONTAB_FILE}.tmp" "$CRONTAB_FILE" + /etc/init.d/cron restart + fi } RestoreTorConfig() { @@ -85,9 +99,25 @@ RestoreTorConfig() { RemoveAppFiles() { RestoreTorConfig $OPKG_CMD remove ruantiblock-mod-py ruantiblock-mod-lua luci-i18n-ruantiblock-ru luci-app-ruantiblock ruantiblock + RemoveFile "$FILE_UCI_CONFIG" + RemoveFile "$FILE_CONFIG" + RemoveFile "$FILE_FQDN_FILTER" + RemoveFile "$FILE_IP_FILTER" + RemoveFile "$FILE_USER_ENTRIES" + RemoveFile "$FILE_BYPASS_ENTRIES" + RemoveFile "$FILE_GR_EXCLUDED_SLD" + RemoveFile "$FILE_GR_EXCLUDED_NETS" + RemoveFile "${FILE_UCI_CONFIG}.opkg" + RemoveFile "${FILE_CONFIG}.opkg" + RemoveFile "${FILE_FQDN_FILTER}.opkg" + RemoveFile "${FILE_IP_FILTER}.opkg" + RemoveFile "${FILE_USER_ENTRIES}.opkg" + RemoveFile "${FILE_BYPASS_ENTRIES}.opkg" rm -f "$DNSMASQ_DATA_FILE" + rm -f "$DNSMASQ_DATA_FILE_BYPASS" rm -rf "$DATA_DIR"/* - rmdir "${RUAB_CFG_DIR}/scripts" 2> /dev/null + rm -rf "$USER_LISTS_DIR" + rmdir "$SCRIPTS_DIR" "$MODULES_DIR" 2> /dev/null rmdir "$HTDOCS_RUAB" 2> /dev/null rm -f /tmp/luci-modulecache/* /tmp/luci-indexcache* /etc/init.d/rpcd restart @@ -117,7 +147,7 @@ ConfirmRemove() { ConfirmRemove AppStop -#BackupCurrentConfig +BackupCurrentConfig DisableStartup RemoveCronTask RemoveAppFiles diff --git a/luci-app-ruantiblock/Makefile b/luci-app-ruantiblock/Makefile index 70ee674..cad0f56 100644 --- a/luci-app-ruantiblock/Makefile +++ b/luci-app-ruantiblock/Makefile @@ -4,7 +4,9 @@ include $(TOPDIR)/rules.mk -PKG_VERSION:=1.6.0-r1 +PKG_NAME:=luci-app-ruantiblock +PKG_VERSION:=2.0.0 +PKG_RELEASE:=1 LUCI_TITLE:=LuCI support for ruantiblock LUCI_DEPENDS:=+ruantiblock LUCI_PKGARCH:=all diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/cron.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/cron.js index 5f54cf5..e950aa1 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/cron.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/cron.js @@ -10,26 +10,26 @@ return view.extend({ currentCrontabLines: [], - toDD: function(n){ + toDD(n){ return String(n).replace(/^(\d)$/, "0$1"); }, - cronStatusString: function(s) { + cronStatusString(s) { return s || _('No Sсhedule'); }, - stringifyRuabTasks: function(str_array) { + stringifyRuabTasks(str_array) { let current_tasks = str_array.filter(s => s.match(this.crontabRegexp)); return current_tasks.join('\n'); }, - setCronStatus: function(value) { + setCronStatus(value) { document.getElementById('cron_status').value = this.cronStatusString(value); document.getElementById("btn_cron_del").style.visibility = (value) ? 'visible' : 'hidden'; }, - writeCronFile: function() { + writeCronFile() { let btn_cron_add = document.getElementById('btn_cron_add'); let btn_cron_del = document.getElementById('btn_cron_del'); let crontab_string = this.currentCrontabLines.join('\n'); @@ -53,17 +53,17 @@ return view.extend({ }); }, - delRuabShedules: function() { + delRuabShedules() { this.currentCrontabLines = this.currentCrontabLines.filter( s => s.match(this.crontabRegexp) ? false : true); }, - delCronSchedule: function(ev) { + delCronSchedule(ev) { this.delRuabShedules(); return this.writeCronFile(); }, - setCronSchedule: function(ev) { + setCronSchedule(ev) { let hour_interval = document.getElementById('cron_hour_interval').value; let day_interval = document.getElementById('cron_day_interval').value; let hour = document.getElementById('cron_hour').value; @@ -88,7 +88,7 @@ return view.extend({ return this.writeCronFile(); }, - onchangeHourInterval: function(e) { + onchangeHourInterval(e) { let value = e.target.value; let bool = (value != ''); let cron_hour = document.getElementById('cron_hour'); @@ -106,7 +106,7 @@ return view.extend({ }; }, - load: function() { + load() { return fs.lines(tools.crontabFile).catch(e => { ui.addNotification(null, E('p', _('Unable to read the contents') + ': %s [ %s ]'.format( @@ -115,7 +115,7 @@ return view.extend({ }); }, - render: function(content) { + render(content) { this.currentCrontabLines = content; let current_task = this.stringifyRuabTasks(content); diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/info.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/info.js index b10ea54..c3ab9e7 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/info.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/info.js @@ -17,7 +17,7 @@ document.head.append(E('style', {'type': 'text/css'}, return view.extend({ pollInterval : L.env.pollinterval, - secToTimeString: function(value) { + secToTimeString(value) { let string = ''; if(/^\d+$/.test(value)) { value = Number(value); @@ -42,50 +42,103 @@ return view.extend({ return string; }, - formatNftJson: function(data) { - let output = { 'rules': [] }; - if(data.rules.nftables && data.rules.nftables.length > 1) { - for(let i of data.rules.nftables) { - if(!i.rule) continue; - let set, bytes; - i.rule.expr.forEach(e => { - if(e.match && e.match.left && e.match.left.payload) { - set = e.match.right.replace('@', ''); - } - else if(e.counter) { - bytes = e.counter.bytes; - }; - }); - output.rules.push([ set, bytes ]); - }; + formatNftJson(data) { + let output = { 'sink': [] }; + if(data.sink.nftables && data.sink.nftables.length > 1) { + let rules = []; - function parseDnsmasqData(set) { - let sArray = []; - if(data[set].nftables && data[set].nftables.length > 1) { - data[set].nftables.forEach(e => { - if(e.set && e.set.elem) { - e.set.elem.forEach(i => { - if(i.elem) { - sArray.push([ i.elem.val, i.elem.expires ]); - }; - }); + for(let i of data.sink.nftables) { + if(i.rule) { + let instance = (i.rule.comment === ' ') ? '-main-' : i.rule.comment; + let proto, bytes; + i.rule.expr.forEach(e => { + if(e.match && e.match.left && e.match.left.meta && e.match.left.meta.key && e.match.left.meta.key == "l4proto") { + proto = e.match.right; + } + else if(e.counter) { + bytes = e.counter.bytes; }; }); + rules.push([ instance, proto, bytes ]); + } else { + continue; }; - return sArray; }; - if(data.dnsmasq) { - output.dnsmasq = parseDnsmasqData('dnsmasq'); + if(rules.length > 0) { + output.sink = rules; }; - if(data.dnsmasq_bypass) { - output.dnsmasq_bypass = parseDnsmasqData('dnsmasq_bypass'); + }; + + if(data.sink_local && data.sink_local.nftables && data.sink_local.nftables.length > 1) { + output.sink_local = []; + let rules = []; + + for(let i of data.sink_local.nftables) { + if(i.rule) { + let instance = (i.rule.comment === ' ') ? '-main-' : i.rule.comment; + let proto, bytes; + i.rule.expr.forEach(e => { + if(e.match && e.match.left && e.match.left.meta && e.match.left.meta.key && e.match.left.meta.key == "l4proto") { + proto = e.match.right; + } + else if(e.counter) { + bytes = e.counter.bytes; + }; + }); + rules.push([ instance, proto, bytes ]); + } else { + continue; + }; + }; + + if(rules.length > 0) { + output.sink_local = rules; + }; + }; + + function parseDnsmasqData(set) { + let sArray = []; + if(set.nftables && set.nftables.length > 1) { + set.nftables.forEach(e => { + if(e.set && e.set.elem) { + e.set.elem.forEach(i => { + if(i.elem) { + sArray.push([ i.elem.val, i.elem.expires ]); + }; + }); + }; + }); + }; + return sArray; + }; + + if(data.dnsmasq) { + output.dnsmasq = parseDnsmasqData(data.dnsmasq); + }; + if(data.dnsmasq_bypass) { + output.dnsmasq_bypass = parseDnsmasqData(data.dnsmasq_bypass); + }; + if(data.dnsmasq_user_instances) { + output.dnsmasq_user_instances = []; + if(data.dnsmasq_user_instances && data.dnsmasq_user_instances.length > 1) { + for(let i of data.dnsmasq_user_instances) { + if(i.nftables) { + let name; + i.nftables.forEach(e => { + if(e.set) { + name = e.set.name; + }; + }); + output.dnsmasq_user_instances.push([ name, parseDnsmasqData(i) ]); + }; + }; }; }; return output; }, - makeDnsmasqTable: function(ipDataArray) { + makeDnsmasqTable(ipDataArray, title) { let lines = `${_('No entries available...')}`; let ipTable = E('table', { 'id': 'ipTable', 'class': 'table' }); @@ -122,6 +175,7 @@ return view.extend({ }; return E([ + E('h3', {}, title), E('div', { 'class': 'log-entries-count' }, `${_('Entries')}: ${ipDataArray.length}` ), @@ -129,7 +183,7 @@ return view.extend({ ]); }, - pollInfo: function() { + pollInfo() { return fs.exec_direct(tools.execPath, [ 'html-info' ], 'json').catch(e => { ui.addNotification(null, E('p', _('Unable to execute or read contents') + ': %s [ %s ]'.format(e.message, tools.execPath) @@ -174,11 +228,20 @@ return view.extend({ let nft_data = this.formatNftJson(data); - if(nft_data.rules.length > 0) { - for(let [set, bytes] of nft_data.rules) { - let elem = document.getElementById('rules.' + set); + if(nft_data.sink.length > 0) { + for(let i of nft_data.sink) { + let elem = document.getElementById('sink.' + i[0] + '.' + (i[1] || 'all')); if(elem) { - elem.textContent = bytes; + elem.textContent = i[2]; + }; + }; + }; + + if(nft_data.sink_local && nft_data.sink_local.length > 0) { + for(let i of nft_data.sink_local) { + let elem = document.getElementById('sink_local.' + i[0] + '.' + (i[1] || 'all')); + if(elem) { + elem.textContent = i[2]; }; }; }; @@ -186,15 +249,16 @@ return view.extend({ let rdTableWrapper = document.getElementById('rdTableWrapper'); if(rdTableWrapper) { rdTableWrapper.innerHTML = ''; - rdTableWrapper.append(this.makeDnsmasqTable(nft_data.dnsmasq)); + rdTableWrapper.append(this.makeDnsmasqTable(nft_data.dnsmasq, _('Dnsmasq'))); }; - let rdbTableWrapper = document.getElementById('rdbTableWrapper'); - if(rdbTableWrapper) { - rdbTableWrapper.innerHTML = ''; - rdbTableWrapper.append(this.makeDnsmasqTable(nft_data.dnsmasq_bypass)); + let rdsTableWrapper = document.getElementById('rdsTableWrapper'); + if(rdsTableWrapper) { + rdsTableWrapper.innerHTML = ''; + for(let i of nft_data.dnsmasq_user_instances) { + rdsTableWrapper.append(this.makeDnsmasqTable(i[1], _('Dnsmasq') + ' ' + i[0])); + }; }; - } else { if(poll.active()) { poll.stop(); @@ -203,7 +267,7 @@ return view.extend({ }); }, - load: function() { + load() { return fs.exec_direct(tools.execPath, [ 'html-info' ], 'json').catch(e => { ui.addNotification(null, E('p', _('Unable to execute or read contents') + ': %s [ %s ]'.format(e.message, tools.execPath) @@ -211,7 +275,7 @@ return view.extend({ }) }, - render: function(data) { + render(data) { if(!data) { return; }; @@ -220,11 +284,12 @@ return view.extend({ data = JSON.parse(data); } catch(e) {}; - let update_status = null, - user_entries = null, - rules = null, - dnsmasq = null, - dnsmasqBypass = null; + let update_status = null, + user_entries = null, + sink = null, + sink_local = null, + dnsmasq = null, + dnsmasqUserInstances = null; if(data) { if(data.status === 'enabled') { @@ -285,39 +350,87 @@ return view.extend({ let nft_data = this.formatNftJson(data); - if(nft_data.rules) { - let table_rules = E('table', { 'class': 'table' }, [ + if(nft_data.sink) { + let table = E('table', { 'class': 'table' }, [ E('tr', { 'class': 'tr table-titles' }, [ E('th', { 'class': 'th left', 'style': 'min-width:33%' }, - _('Match-set')), + _('Instance')), + E('th', { 'class': 'th left' }, _('Protocol')), E('th', { 'class': 'th left' }, _('Bytes')), ]), ]); + for(let i of nft_data.sink) { + let instance = i[0]; + let proto = (i[1] === undefined) ? _('all') : i[1]; + let bytes = i[2]; - for(let [set, bytes] of nft_data.rules) { - if(!set) { + if(!instance) { continue; }; - table_rules.append( + table.append( E('tr', { 'class': 'tr' }, [ - E('td',{ - 'class' : 'td left', - 'data-title': _('Match-set'), - }, set + ((set.length >= 1) ? ( - ' (' + set.replace(/^c/, 'CIDR').replace(/^i/, 'IP').replace(/^d/, 'dnsmasq').replace(/^bi/, 'bypass IP').replace(/^bd/, 'bypass dnsmasq').replace(/^fproxy/, 'full proxy') + ')' - ) : '')), E('td', { 'class' : 'td left', - 'id' : 'rules.' + set, + 'data-title': _('Instance'), + }, instance), + E('td', { + 'class' : 'td left', + 'data-title': _('Protocol'), + }, proto), + E('td', { + 'class' : 'td left', + 'id' : 'sink.' + instance + '.' + (i[1] || 'all'), 'data-title': _('Bytes'), }, bytes), ]) ); - }; - rules = E([ - E('h3', {}, _('Nftables rules')), - table_rules, + }; + sink = E([ + E('h3', {}, _('Transit traffic')), + table, + ]); + }; + + if(nft_data.sink_local) { + let table = E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th left', 'style': 'min-width:33%' }, + _('Instance')), + E('th', { 'class': 'th left' }, _('Protocol')), + E('th', { 'class': 'th left' }, _('Bytes')), + ]), + ]); + for(let i of nft_data.sink_local) { + let instance = i[0]; + let proto = (i[1] === undefined) ? _('all') : i[1]; + let bytes = i[2]; + + if(!instance) { + continue; + }; + table.append( + E('tr', { 'class': 'tr' }, [ + E('td', { + 'class' : 'td left', + 'data-title': _('Instance'), + }, instance), + E('td', { + 'class' : 'td left', + 'data-title': _('Protocol'), + }, proto), + E('td', { + 'class' : 'td left', + 'id' : 'sink_local.' + instance + '.' + (i[1] || 'all'), + 'data-title': _('Bytes'), + }, bytes), + ]) + ); + + }; + sink_local = E([ + E('h3', {}, _('Local traffic')), + table, ]); }; @@ -325,24 +438,28 @@ return view.extend({ let rdTableWrapper = E('div', { 'id' : 'rdTableWrapper', 'style': 'width:100%' - }, this.makeDnsmasqTable(nft_data.dnsmasq)); + }, this.makeDnsmasqTable(nft_data.dnsmasq, _('Dnsmasq'))); dnsmasq = E([ - E('h3', {}, _('Dnsmasq')), rdTableWrapper, ]); }; - if(nft_data.dnsmasq_bypass) { - let rdbTableWrapper = E('div', { - 'id' : 'rdbTableWrapper', + if(nft_data.dnsmasq_user_instances) { + let rdsTableWrapper = E('div', { + 'id' : 'rdsTableWrapper', 'style': 'width:100%' - }, this.makeDnsmasqTable(nft_data.dnsmasq_bypass)); + }); - dnsmasqBypass = E([ - E('h3', {}, _('Dnsmasq bypass')), - rdbTableWrapper, - ]); + for(let i of nft_data.dnsmasq_user_instances) { + rdsTableWrapper.append(this.makeDnsmasqTable(i[1], _('Dnsmasq') + ' ' + i[0])); + }; + + if(nft_data.dnsmasq_user_instances.length > 0) { + dnsmasqUserInstances = E([ + rdsTableWrapper, + ]); + }; }; poll.add(L.bind(this.pollInfo, this), this.pollInterval); @@ -360,7 +477,7 @@ return view.extend({ E('div', { 'class': 'cbi-section-node' }, update_status) ), E('div', { 'class': 'cbi-section fade-in' }, - E('div', { 'class': 'cbi-section-node' }, rules) + E('div', { 'class': 'cbi-section-node' }, sink) ), ]; @@ -373,16 +490,24 @@ return view.extend({ ); } - if(dnsmasqBypass) { + if(sink_local) { layout.splice(5, 0, E('div', { 'class': 'cbi-section fade-in' }, - E('div', { 'class': 'cbi-section-node' }, dnsmasqBypass) + E('div', { 'class': 'cbi-section-node' }, sink_local) + ) + ); + }; + + if(dnsmasqUserInstances) { + layout.splice(6, 0, + E('div', { 'class': 'cbi-section fade-in' }, + E('div', { 'class': 'cbi-section-node' }, dnsmasqUserInstances) ) ); }; if(dnsmasq) { - layout.splice(6, 0, + layout.splice(7, 0, E('div', { 'class': 'cbi-section fade-in' }, E('div', { 'class': 'cbi-section-node' }, dnsmasq) ) diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-abstract.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-abstract.js index a68e51e..3c40261 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-abstract.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/log-abstract.js @@ -1,6 +1,7 @@ 'use strict'; 'require baseclass'; 'require fs'; +'require ui'; 'require view.ruantiblock.log-widget as widget'; return baseclass.extend({ diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/service.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/service.js index 3cf34bb..a7c6b9a 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/service.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/service.js @@ -1,4 +1,5 @@ 'use strict'; +'require baseclass'; 'require fs'; 'require poll'; 'require uci'; @@ -15,7 +16,121 @@ const btn_style_warning = 'btn cbi-button-negative important' return view.extend({ statusTokenValue: null, - disableButtons: function(bool, btn, elems=[]) { + dialogDestroy: baseclass.extend({ + __init__(context) { + this.context = context; + }, + + currentDnsmasqCfgDir: null, + + dnsmasqCfgDirsSelect: null, + + cancelButton : E('button', { + 'id' : 'btn_cancel', + 'class': btn_style_neutral, + 'click': ui.hideModal, + }, _('Cancel')), + + load() { + return L.resolveDefault(fs.list(tools.dnsmasqCfgDirsRoot), null); + }, + + render(data) { + let section = uci.get(tools.appName, 'config'); + this.currentDnsmasqCfgDir = section.dnsmasq_cfg_dir; + let available_cfg_dirs = []; + + let dnsmasq_cfg_dirs_arr = data; + if(dnsmasq_cfg_dirs_arr) { + dnsmasq_cfg_dirs_arr.forEach(e => { + let fname = e.name; + if(fname.startsWith('dnsmasq')) { + available_cfg_dirs.push([ fname, tools.dnsmasqCfgDirsRoot + '/' + fname ]); + }; + }); + }; + + this.dnsmasqCfgDirsSelect = E('select', { + 'id' : 'dnsmasq_cfg_dirs_list', + 'class': "cbi-input-select", + }), + + available_cfg_dirs.forEach(e => { + this.dnsmasqCfgDirsSelect.append( + E('option', { 'value': e[1] }, e[0])); + }); + this.dnsmasqCfgDirsSelect.value = this.currentDnsmasqCfgDir; + + ui.showModal(this.title, [ + E('h4', _('The service will be disabled and all blacklist data will be deleted. Continue?')), + E('div', { 'class': 'cbi-section' }, [ + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, + _('Dnsmasq config directory')), + E('div', { 'class': 'cbi-value-field' }, [ + this.dnsmasqCfgDirsSelect, + E('div', { 'class': 'cbi-value-description' }, + _('Change dnsmasq config directory')), + ]), + ]), + ]), + E('div', { 'class': 'right' }, [ + this.cancelButton, + ' ', + E('button', { + 'id' : 'btn_apply', + 'class': btn_style_warning, + 'click': ui.createHandlerFn(this, this.handleApply), + }, _('Shutdown')), + ]), + ], 'cbi-modal'); + }, + + handleApply(ev) { + this.cancelButton.disabled = true; + return this.context.appAction('destroy').then(() => { + if(this.dnsmasqCfgDirsSelect.value !== this.currentDnsmasqCfgDir) { + uci.set(tools.appName, 'config', 'dnsmasq_cfg_dir', + this.dnsmasqCfgDirsSelect.value); + uci.save(); + uci.apply(); + }; + }).finally(() => { + this.cancelButton.disabled = false; + ui.hideModal(); + }); + }, + + error(e) { + ui.showModal(this.title, [ + E('div', { 'class': 'cbi-section' }, + E('p', {}, _('An error occurred') + + ': %s'.format(e.message)) + ), + E('div', { 'class': 'right' }, + E('button', { + 'class': btn_style_neutral, + 'click': ui.hideModal, + }, _('Dismiss')) + ), + ]); + }, + + show() { + ui.showModal(null, + E('p', { 'class': 'spinning' }, _('Loading')) + ); + this.load().then(content => { + ui.hideModal(); + return this.render(content); + }).catch(e => { + ui.hideModal(); + return this.error(e); + }) + }, + }), + + disableButtons(bool, btn, elems=[]) { let btn_start = elems[1] || document.getElementById("btn_start"); let btn_destroy = elems[4] || document.getElementById("btn_destroy"); let btn_enable = elems[2] || document.getElementById("btn_enable"); @@ -31,7 +146,7 @@ return view.extend({ }; }, - getAppStatus: function() { + getAppStatus() { return Promise.all([ fs.exec(tools.execPath, [ 'raw-status' ]), fs.exec(tools.execPath, [ 'vpn-route-status' ]), @@ -46,7 +161,7 @@ return view.extend({ }); }, - setAppStatus: function(status_array, elems=[], force_app_code) { + setAppStatus(status_array, elems=[], force_app_code) { let section = uci.get(tools.appName, 'config'); if(!status_array || typeof(section) !== 'object') { (elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString(1); @@ -59,8 +174,7 @@ return view.extend({ let app_status_code = (force_app_code) ? force_app_code : status_array[0].code; let vpn_route_status_code = status_array[1].code; let enabled_flag = status_array[2]; - let proxy_local_clients = section.proxy_local_clients; - let proxy_mode = section.proxy_mode; + let dnsmasq_cfg_dir = section.dnsmasq_cfg_dir; let bllist_preset = section.bllist_preset; let bllist_module = section.bllist_module; @@ -122,7 +236,6 @@ return view.extend({ (elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString( app_status_code, - proxy_mode, bllist_preset, bllist_module, vpn_route_status_code); @@ -132,7 +245,7 @@ return view.extend({ }; }, - serviceAction: function(action, button) { + serviceAction(action, button) { if(button) { let elem = document.getElementById(button); this.disableButtons(true, elem); @@ -149,7 +262,7 @@ return view.extend({ }); }, - appAction: function(action, button) { + appAction(action, button) { if(button) { let elem = document.getElementById(button); this.disableButtons(true, elem); @@ -167,13 +280,12 @@ return view.extend({ return this.getAppStatus().then( (status_array) => { this.setAppStatus(status_array); - ui.hideModal(); } ); }); }, - statusPoll: function() { + statusPoll() { return fs.read(tools.tokenFile).then(v => { v = tools.normalizeValue(v); if(v != this.statusTokenValue) { @@ -187,48 +299,21 @@ return view.extend({ }); }, - dialogDestroy: function(ev) { - ev.target.blur(); - let cancel_button = E('button', { - 'class': btn_style_neutral, - 'click': ui.hideModal, - }, _('Cancel')); - - let shutdown_btn = E('button', { - 'class': btn_style_warning, - }, _('Shutdown')); - shutdown_btn.onclick = ui.createHandlerFn(this, () => { - cancel_button.disabled = true; - return this.appAction('destroy'); - }); - - ui.showModal(_('Shutdown'), [ - E('div', { 'class': 'cbi-section' }, [ - E('p', _('The service will be disabled and all blacklist data will be deleted. Continue?')), - ]), - E('div', { 'class': 'right' }, [ - shutdown_btn, - ' ', - cancel_button, - ]) - ]); - }, - - load: function() { + load() { return this.getAppStatus(); }, - render: function(status_array) { + render(status_array) { if(!status_array) { return; }; let section = uci.get(tools.appName, 'config'); - let proxy_local_clients = (typeof(section) === 'object') ? - section.proxy_local_clients : null; this.statusTokenValue = (Array.isArray(status_array)) ? tools.normalizeValue(status_array[4]) : null; + let dialog_destroy = new this.dialogDestroy(this); + let status_string = E('div', { 'id' : 'status', 'name' : 'status', @@ -281,7 +366,7 @@ return view.extend({ 'name' : 'btn_destroy', 'class': btn_style_negative, }, _('Shutdown')); - btn_destroy.onclick = L.bind(this.dialogDestroy, this); + btn_destroy.onclick = () => dialog_destroy.show(); layout_append(btn_destroy, _('Shutdown'), _('Complete service shutdown, as well as deleting nftsets and blacklist data')); diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js index b10f7b2..1f0147c 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/settings.js @@ -8,11 +8,11 @@ 'require view.ruantiblock.tools as tools'; return view.extend({ - parsers : {}, + parsers : {}, - appStatusCode: null, + appStatusCode : null, - depends : function(elem, key, array, empty=true) { + depends(elem, key, array, empty=true) { if(empty && array.length === 0) { elem.depends(key, '_dummy'); } else { @@ -20,20 +20,82 @@ return view.extend({ }; }, - validateIpPort: function(section, value) { + validateIpPort(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) { + validateUrl(section, value) { return (/^$|^https?:\/\/[\w.-]+(:[0-9]{2,5})?[\w\/~.&?+=-]*$/.test(value)) ? true : _('Expecting:') + ` ${_('valid URL')}\n`; }, - load: function() { + CBIBlockFileEdit: form.Value.extend({ + __name__ : 'CBI.BlockFileEdit', + + __init__(map, section, ctx, id, file, title, description, callback) { + this.map = map; + this.section = section; + this.ctx = ctx; + this.id = id, + this.optional = true; + this.rmempty = true; + this.file = file; + this.title = title; + this.description = description; + this.callback = callback; + this.content = ''; + }, + + cfgvalue(section_id, option) { + return this.content; + }, + + formvalue(section_id) { + let value = this.content; + let textarea = document.getElementById('widget.file_edit.content.' + this.id); + if(textarea) { + value = textarea.value.trim().replace(/\r\n/g, '\n') + '\n'; + }; + return value; + }, + + write(section_id, formvalue) { + return fs.write(this.file, formvalue).then(rc => { + ui.addNotification(null, E('p', _('Contents have been saved.')), + 'info'); + if(this.callback) { + return this.callback(rc); + }; + }).catch(e => { + ui.addNotification(null, E('p', _('Unable to save the contents') + + ': %s'.format(e.message))); + }); + }, + + load() { + return L.resolveDefault(fs.read(this.file), '').then(c => { + this.content = c; + }); + }, + + renderWidget(section_id, option_index, cfgvalue) { + return E('textarea', { + 'id' : 'widget.file_edit.content.' + this.id, + 'class' : 'cbi-input-textarea', + 'style' : 'width:100% !important;resize:vertical !important', + 'rows' : 10, + 'wrap' : 'off', + 'spellcheck': 'false', + }, cfgvalue); + }, + }), + + load() { return Promise.all([ L.resolveDefault(fs.exec(tools.execPath, [ 'raw-status' ]), 1), L.resolveDefault(fs.list(tools.parsersDir), null), + L.resolveDefault(fs.list(tools.dnsmasqCfgDirsRoot), null), uci.load(tools.appName), ]).catch(e => { ui.addNotification(null, E('p', _('Unable to read the contents') @@ -43,14 +105,14 @@ return view.extend({ }); }, - render: function(data) { + render(data) { if(!data) { return; }; - this.appStatusCode = data[0].code; - let p_dir_arr = data[1]; - let curent_module = uci.get(tools.appName, 'config', 'bllist_module'); - let curent_preset = uci.get(tools.appName, 'config', 'bllist_preset'); + this.appStatusCode = data[0].code; + let p_dir_arr = data[1]; + let curent_module = uci.get(tools.appName, 'config', 'bllist_module'); + let curent_preset = uci.get(tools.appName, 'config', 'bllist_preset'); if(p_dir_arr) { p_dir_arr.forEach(e => { @@ -129,7 +191,7 @@ return view.extend({ '
#comment
domain.net
anotherdomain.com
' ); - let m, s, o; + let m, s, o, ss; m = new form.Map(tools.appName, _('Ruantiblock') + ' - ' + _('Settings')); @@ -140,39 +202,32 @@ return view.extend({ /* Main settings tab */ - s.tab('main_settings', _('Main settings')); - - // PROXY_MODE - o = s.taboption('main_settings', form.ListValue, 'proxy_mode', - _('Proxy mode')); - o.value('1', 'Tor'); - o.value('2', 'VPN'); - o.value('3', _('Transparent proxy')); - - // PROXY_LOCAL_CLIENTS - let proxy_local_clients = s.taboption('main_settings', form.Flag, 'proxy_local_clients', - _('Apply proxy rules to router application traffic')); - proxy_local_clients.rmempty = false; + s.tab('main_tab', _('Main settings')); // ENABLE_LOGGING - o = s.taboption('main_settings', form.Flag, 'enable_logging', + o = s.taboption('main_tab', form.Flag, 'enable_logging', _('Logging events')); o.rmempty = false; // update_at_startup - o = s.taboption('main_settings', form.Flag, 'update_at_startup', + o = s.taboption('main_tab', form.Flag, 'update_at_startup', _('Update at startup')); o.description = _('Update blacklist after system startup'); o.rmempty = false; + // PROXY_LOCAL_CLIENTS + o = s.taboption('main_tab', form.Flag, 'proxy_local_clients', + _('Apply proxy rules to router application traffic')); + o.rmempty = false; + // NFTSET_CLEAR_SETS - o = s.taboption('main_settings', form.Flag, 'nftset_clear_sets', + o = s.taboption('main_tab', form.Flag, 'nftset_clear_sets', _('Clean up nftsets before updating blacklist')); o.description = _('Reduces RAM consumption during update'); o.rmempty = false; // ALLOWED_HOSTS_MODE - o = s.taboption('main_settings', form.ListValue, 'allowed_hosts_mode', + o = s.taboption('main_tab', form.ListValue, 'allowed_hosts_mode', _('Host filter')); o.value('0', _('Disabled')); o.value('1', _('Only listed hosts')); @@ -180,40 +235,29 @@ return view.extend({ o.description = _('Restriction of hosts that are allowed to bypass blocking'); // ALLOWED_HOSTS_LIST - o = s.taboption('main_settings', form.DynamicList, 'allowed_hosts_list', + o = s.taboption('main_tab', form.DynamicList, 'allowed_hosts_list', _('IP addresses for host filter')); o.datatype = 'ip4addr'; - // ENABLE_FPROXY - o = s.taboption('main_settings', form.Flag, 'enable_fproxy', - _('Enable full proxy mode')); - o.description = _('All traffic of the specified hosts passes through the proxy, without a blacklist'); - o.rmempty = false; - - // FPROXY_LIST - o = s.taboption('main_settings', form.DynamicList, 'fproxy_list', - _('IP addresses for full proxy mode')); - o.datatype = 'ip4addr'; - /* Tor tab */ - s.tab('tor_settings', _('Tor mode')); + s.tab('tor_tab', _('Tor mode')); // TOR_TRANS_PORT - o = s.taboption('tor_settings', form.Value, 'tor_trans_port', + o = s.taboption('tor_tab', form.Value, 'tor_trans_port', _('Transparent proxy port')); o.rmempty = false; o.datatype = 'port'; // ONION_DNS_ADDR - o = s.taboption('tor_settings', form.Value, 'onion_dns_addr', + o = s.taboption('tor_tab', form.Value, 'onion_dns_addr', _("Optional DNS resolver for '.onion' zone"), 'ipaddress#port'); o.rmempty = false; o.validate = this.validateIpPort; // Torrc edit dialog - o = s.taboption('tor_settings', form.Button, '_torrc_btn', + o = s.taboption('tor_tab', form.Button, '_torrc_btn', _('Tor configuration file')); o.onclick = () => torrc_edit.show(); o.inputtitle = _('Edit'); @@ -222,10 +266,10 @@ return view.extend({ /* VPN tab */ - s.tab('vpn_settings', _('VPN mode')); + s.tab('vpn_tab', _('VPN mode')); // IF_VPN - o = s.taboption('vpn_settings', widgets.DeviceSelect, 'if_vpn', + o = s.taboption('vpn_tab', widgets.DeviceSelect, 'if_vpn', _('VPN interface')); o.multiple = false; o.noaliases = true; @@ -233,13 +277,13 @@ return view.extend({ o.default = 'tun0'; // VPN_GW_IP - o = s.taboption('vpn_settings', form.Value, 'vpn_gw_ip', + o = s.taboption('vpn_tab', form.Value, 'vpn_gw_ip', _('VPN gateway IP address'), _('If not specified, the VPN interface address is used (or peer address for PPP protocols)')); o.datatype = 'ip4addr(1)'; // VPN_ROUTE_CHECK - o = s.taboption('vpn_settings', form.ListValue, 'vpn_route_check', + o = s.taboption('vpn_tab', form.ListValue, 'vpn_route_check', _('Type of adding a VPN rule to the routing table')); o.value('0', 'hotplug.d'); o.value('1', 'ruab_route_check'); @@ -248,32 +292,46 @@ return view.extend({ _('ruab_route_check - script that regularly checks an entry in the routing table.'); - /* Proxy tab */ + /* Tproxy tab */ - s.tab('proxy_settings', _('Transparent proxy mode')); + s.tab('tproxy_tab', _('Transparent proxy mode')); + + // T_PROXY_TYPE + o = s.taboption('tproxy_tab', form.ListValue, 't_proxy_type', + _('Proxy type')); + o.value('0', _('redirect')); + o.value('1', _('tproxy')); + o.description = _('Statement in nftables rules'); // T_PROXY_PORT_TCP - o = s.taboption('proxy_settings', form.Value, 't_proxy_port_tcp', + o = s.taboption('tproxy_tab', form.Value, 't_proxy_port_tcp', _('Transparent proxy TCP port')); o.rmempty = false; o.datatype = 'port'; // T_PROXY_ALLOW_UDP - o = s.taboption('proxy_settings', form.Flag, 't_proxy_allow_udp', + o = s.taboption('tproxy_tab', form.Flag, 't_proxy_allow_udp', _('Send UDP traffic to transparent proxy')); o.rmempty = false; // T_PROXY_PORT_UDP - o = s.taboption('proxy_settings', form.Value, 't_proxy_port_udp', + o = s.taboption('tproxy_tab', form.Value, 't_proxy_port_udp', _('Transparent proxy UDP port')); o.rmempty = false; o.datatype = 'port'; - /* Blacklist module tab */ + /* Blacklist tab */ s.tab('blacklist_tab', _('Blacklist settings')); + // PROXY_MODE + o = s.taboption('blacklist_tab', form.ListValue, 'proxy_mode', + _('Proxy mode')); + o.value('1', 'Tor'); + o.value('2', 'VPN'); + o.value('3', _('Transparent proxy')); + // BLLIST_PRESET let bllist_preset = s.taboption('blacklist_tab', form.ListValue, 'bllist_preset', _('Blacklist update mode')); @@ -312,29 +370,16 @@ return view.extend({ o.rmempty = false; o.default = 0; - // ADD_USER_ENTRIES - o = s.taboption('blacklist_tab', form.Flag, 'add_user_entries', - _('Enable user entries'), _('Add user entries to the blacklist when updating')); + // ENABLE_FPROXY + o = s.taboption('blacklist_tab', form.Flag, 'enable_fproxy', + _('Enable full proxy mode')); + o.description = _('All traffic of the specified hosts passes through the proxy, without a blacklist'); o.rmempty = false; - o.default = 0; - o.depends({ bllist_preset: '', '!reverse': true }); - // USER_ENTRIES edit dialog - o = s.taboption('blacklist_tab', form.Button, '_user_entries_btn', - _('User entries')); - o.onclick = () => user_entries_edit.show(); - o.inputtitle = _('Edit'); - o.inputstyle = 'edit btn'; - - // USER_ENTRIES_REMOTE - o = s.taboption('blacklist_tab', form.DynamicList, 'user_entries_remote', - _('URLs of remote user entries file')); - o.validate = this.validateUrl; - - // USER_ENTRIES_DNS - o = s.taboption('blacklist_tab', form.Value, 'user_entries_dns', - _("DNS server that is used for the user's FQDN entries"), 'ipaddress[#port]'); - o.validate = this.validateIpPort; + // FPROXY_LIST + o = s.taboption('blacklist_tab', form.DynamicList, 'fproxy_list', + _('IP addresses for full proxy mode')); + o.datatype = 'ip4addr'; // BYPASS_MODE o = s.taboption('blacklist_tab', form.Flag, 'bypass_mode', @@ -354,6 +399,7 @@ return view.extend({ _('DNS server that is used for the FQDN entries of exclusion list'), 'ipaddress[#port]'); o.validate = this.validateIpPort; + if(availableParsers) { bllist_preset.description += '
( * - ' + _('requires installed blacklist module') + ' )'; @@ -398,10 +444,9 @@ return view.extend({ // BLLIST_GR_EXCLUDED_SLD_FILE edit dialog o = s.taboption('parser_settings_tab', form.Button, '_gr_excluded_sld_btn', _('2nd level domains that are excluded from optimization')); - o.onclick = () => gr_excluded_sld_edit.show(); - o.inputtitle = _('Edit'); - o.inputstyle = 'edit btn'; - //o.description = _('e.g:') + ' livejournal.com'; + o.onclick = () => gr_excluded_sld_edit.show(); + o.inputtitle = _('Edit'); + o.inputstyle = 'edit btn'; // BLLIST_ENABLE_IDN o = s.taboption('parser_settings_tab', form.Flag, 'bllist_enable_idn', @@ -447,10 +492,9 @@ return view.extend({ // BLLIST_GR_EXCLUDED_NETS_FILE edit dialog o = s.taboption('parser_settings_tab', form.Button, '_gr_excluded_nets_btn', _('IP subnet patterns (/24) that are excluded from optimization')); - o.onclick = () => gr_excluded_nets_edit.show(); - o.inputtitle = _('Edit'); - o.inputstyle = 'edit btn'; - //o.description = _('e.g:') + ' 192.168.1.'; + o.onclick = () => gr_excluded_nets_edit.show(); + o.inputtitle = _('Edit'); + o.inputstyle = 'edit btn'; // BLLIST_SUMMARIZE_IP o = s.taboption('parser_settings_tab', form.Flag, 'bllist_summarize_ip', @@ -461,7 +505,180 @@ return view.extend({ o = s.taboption('parser_settings_tab', form.Flag, 'bllist_summarize_cidr', _("Summarize '/24' networks")); o.rmempty = false; + }; + + /* User entries tab */ + + s.tab('user_entries_tab', _('User entries')); + + o = s.taboption('user_entries_tab', form.SectionValue, 'user_instance', form.GridSection, + 'user_instance'); + ss = o.subsection; + ss.addremove = false; + ss.sortable = false; + ss.nodescriptions = true; + ss.modaltitle = `${_('User entries')} - %s`; + ss.max_cols = 2; + + + /* User entries main settings tab */ + + ss.tab('u_main_tab', _('Main settings')); + + // U_ENABLED + o = ss.taboption('u_main_tab', form.Flag, 'u_enabled', + _('Enabled'), + ); + o.rmempty = false; + o.default = '1'; + o.editable = true; + o.modalonly = false; + + // description + o = ss.taboption('u_main_tab', form.Value, 'u_description', + _("Description")); + o.datatype = 'maxlength(100)'; + o.modalonly = null; + + // U_PROXY_MODE + o = ss.taboption('u_main_tab', form.ListValue, 'u_proxy_mode', + _('Proxy mode')); + o.value('1', 'Tor'); + o.value('2', 'VPN'); + o.value('3', _('Transparent proxy')); + o.default = '2'; + o.modalonly = true; + + // U_SKIP_MARKED_PACKETS + o = ss.taboption('u_main_tab', form.Flag, 'u_skip_marked_packets', + _('Lowest priority')); + o.description = _('This proxy will receive traffic last, even after the main blacklist'); + o.rmempty = false; + o.modalonly = true; + + // U_ENABLE_FPROXY + o = ss.taboption('u_main_tab', form.Flag, 'u_enable_fproxy', + _('Enable full proxy mode')); + o.description = _('All traffic of the specified hosts passes through the proxy, without a blacklist'); + o.rmempty = false; + o.modalonly = true; + + // U_FPROXY_LIST + o = ss.taboption('u_main_tab', form.DynamicList, 'u_fproxy_list', + _('IP addresses for full proxy mode')); + o.datatype = 'ip4addr'; + o.modalonly = true; + + + /* User entries tor tab */ + + ss.tab('u_tor_tab', _('Tor mode')); + + // U_TOR_TRANS_PORT + o = ss.taboption('u_tor_tab', form.Value, 'u_tor_trans_port', + _('Transparent proxy port')); + o.rmempty = false; + o.datatype = 'port'; + o.modalonly = true; + + // U_ONION_DNS_ADDR + o = ss.taboption('u_tor_tab', form.Value, 'u_onion_dns_addr', + _("Optional DNS resolver for '.onion' zone"), 'ipaddress#port'); + o.rmempty = false; + o.validate = this.validateIpPort; + o.modalonly = true; + + /* User entries VPN tab */ + + ss.tab('u_vpn_tab', _('VPN mode')); + + // U_IF_VPN + o = ss.taboption('u_vpn_tab', widgets.DeviceSelect, 'u_if_vpn', + _('VPN interface')); + o.multiple = false; + o.noaliases = true; + o.rmempty = false; + o.default = 'tun0'; + o.modalonly = true; + + // U_VPN_GW_IP + o = ss.taboption('u_vpn_tab', form.Value, 'u_vpn_gw_ip', + _('VPN gateway IP address'), + _('If not specified, the VPN interface address is used (or peer address for PPP protocols)')); + o.datatype = 'ip4addr(1)'; + o.modalonly = true; + + + /* User entries tproxy tab */ + + ss.tab('u_tproxy_tab', _('Transparent proxy mode')); + + // U_T_PROXY_TYPE + o = ss.taboption('u_tproxy_tab', form.ListValue, 'u_t_proxy_type', + _('Proxy type')); + o.value('0', _('redirect')); + o.value('1', _('tproxy')); + o.description = _('Statement in nftables rules'); + + // U_T_PROXY_PORT_TCP + o = ss.taboption('u_tproxy_tab', form.Value, 'u_t_proxy_port_tcp', + _('Transparent proxy TCP port')); + o.rmempty = false; + o.datatype = 'port'; + o.modalonly = true; + + // U_T_PROXY_ALLOW_UDP + o = ss.taboption('u_tproxy_tab', form.Flag, 'u_t_proxy_allow_udp', + _('Send UDP traffic to transparent proxy')); + o.rmempty = false; + o.modalonly = true; + + // U_T_PROXY_PORT_UDP + o = ss.taboption('u_tproxy_tab', form.Value, 'u_t_proxy_port_udp', + _('Transparent proxy UDP port')); + o.rmempty = false; + o.datatype = 'port'; + o.modalonly = true; + + + /* User entries items tab */ + + ss.tab('u_entries_tab', _('Entries')); + + ss.addModalOptions = (s, section_id, ev) => { + + // user entries edit dialog + o = s.taboption('u_entries_tab', this.CBIBlockFileEdit, this, + 'user-entries', + tools.userListsDir + '/' + s.section, + _('Edit entries'), + _('One entry (IP, CIDR or FQDN) per line. In the FQDN records, you can specify the DNS server for resolving this domain (separated by a space). You can also comment on lines (# is the first character of a line).
Examples:') + + '
#comment
domain.net
sub.domain.com 8.8.8.8
sub.domain.com 8.8.8.8#53
74.125.131.19
74.125.0.0/16
' + ); + + // DEBUG + console.log(tools.userListsDir + '/' + s.section); + + o.modalonly = true; + + // U_ENTRIES_REMOTE + o = s.taboption('u_entries_tab', form.DynamicList, 'u_entries_remote', + _('URLs of remote user entries file')); + o.validate = this.validateUrl; + o.modalonly = true; + + // U_ENABLE_ENTRIES_REMOTE_PROXY + o = s.taboption('u_entries_tab', form.Flag, 'u_enable_entries_remote_proxy', + _('Downloading files via proxy'), _('Turn on if files are blocked')); + o.rmempty = false; + o.default = 0; + + // U_ENTRIES_DNS + o = s.taboption('u_entries_tab', form.Value, 'u_entries_dns', + _("DNS server that is used for the user's FQDN entries"), 'ipaddress[#port]'); + o.validate = this.validateIpPort; + o.modalonly = true; }; let map_promise = m.render(); @@ -469,12 +686,28 @@ return view.extend({ return map_promise; }, - handleSaveApply: function(ev, mode) { - return this.handleSave(ev).then(() => { + handleSave(ev, restart) { + let tasks = []; + document.getElementById('maincontent') + .querySelectorAll('.cbi-map').forEach((map, i, a) => { + let res = DOM.callClassMethod(map, 'save'); + if(restart && i == a.length - 1 && this.appStatusCode != 1 && this.appStatusCode != 2) { + res.then(() => { + window.setTimeout(() => { + fs.exec_direct(tools.execPath, [ 'restart' ]).then( + () => console.log(tools.execPath + ' restarted...') + ); + }, 1000); + }); + }; + tasks.push(res); + }); + return Promise.all(tasks); + }, + + handleSaveApply(ev, mode) { + return this.handleSave(ev, true).then(() => { ui.changes.apply(mode == '0'); - if(this.appStatusCode != 1 && this.appStatusCode != 2) { - window.setTimeout(() => fs.exec(tools.execPath, [ 'restart' ]), 3000); - }; }); }, }); diff --git a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/tools.js b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/tools.js index 15b9a70..8bd97a8 100644 --- a/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/tools.js +++ b/luci-app-ruantiblock/htdocs/luci-static/resources/view/ruantiblock/tools.js @@ -38,8 +38,10 @@ return baseclass.extend({ execPath : '/usr/bin/ruantiblock', tokenFile : '/var/run/ruantiblock.token', parsersDir : '/usr/libexec/ruantiblock', + dnsmasqCfgDirsRoot: '/tmp', torrcFile : '/etc/tor/torrc', userEntriesFile : '/etc/ruantiblock/user_entries', + userListsDir : '/etc/ruantiblock/user_lists', bypassEntriesFile : '/etc/ruantiblock/bypass_entries', fqdnFilterFile : '/etc/ruantiblock/fqdn_filter', ipFilterFile : '/etc/ruantiblock/ip_filter', @@ -76,7 +78,7 @@ return baseclass.extend({ expect: { result: false } }), - getInitStatus: function(name) { + getInitStatus(name) { return this.callInitStatus(name).then(res => { if(res) { return res[name].enabled; @@ -89,7 +91,7 @@ return baseclass.extend({ }); }, - handleServiceAction: function(name, action) { + handleServiceAction(name, action) { return this.callInitAction(name, action).then(success => { if(!success) { throw _('Command failed'); @@ -101,13 +103,12 @@ return baseclass.extend({ }); }, - normalizeValue: function(v) { + normalizeValue(v) { return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v; }, makeStatusString: function( app_status_code, - proxy_mode, bllist_preset, bllist_module, vpn_route_status_code) { @@ -152,14 +153,6 @@ return baseclass.extend({ %s %s - - - ${_('Proxy mode')}: - - - %s - - ${_('Blacklist update mode')}: @@ -172,10 +165,9 @@ return baseclass.extend({ `.format( spinning, app_status_label, - (app_status_code != 2 && proxy_mode == 2 && vpn_route_status_code != 0) + (app_status_code != 2 && vpn_route_status_code != 0) ? '' + _('VPN routing error! Need restart') + '' : '', - (proxy_mode == 3) ? _('Transparent proxy') : (proxy_mode == 2) ? 'VPN' : 'Tor', (!bllist_preset || bllist_preset === '') ? _('user entries only') : (this.blacklistPresets[bllist_preset]) ? ` @@ -185,7 +177,7 @@ return baseclass.extend({ }, fileEditDialog: baseclass.extend({ - __init__: function(file, title, description, callback, file_exists=false) { + __init__(file, title, description, callback, file_exists=false) { this.file = file; this.title = title; this.description = description; @@ -193,11 +185,11 @@ return baseclass.extend({ this.file_exists = file_exists; }, - load: function() { + load() { return L.resolveDefault(fs.read(this.file), ''); }, - render: function(content) { + render(content) { ui.showModal(this.title, [ E('div', { 'class': 'cbi-section' }, [ E('div', { 'class': 'cbi-section-descr' }, this.description), @@ -230,7 +222,7 @@ return baseclass.extend({ ]); }, - handleSave: function(ev) { + handleSave(ev) { let textarea = document.getElementById('widget.modal_content'); let value = textarea.value.trim().replace(/\r\n/g, '\n') + '\n'; @@ -249,7 +241,7 @@ return baseclass.extend({ }); }, - error: function(e) { + error(e) { if(!this.file_exists && e instanceof Error && e.name === 'NotFoundError') { return this.render(); } else { @@ -268,7 +260,7 @@ return baseclass.extend({ }; }, - show: function() { + show() { ui.showModal(null, E('p', { 'class': 'spinning' }, _('Loading')) ); diff --git a/luci-app-ruantiblock/po/ru/ruantiblock.po b/luci-app-ruantiblock/po/ru/ruantiblock.po index d4b5221..13097f9 100644 --- a/luci-app-ruantiblock/po/ru/ruantiblock.po +++ b/luci-app-ruantiblock/po/ru/ruantiblock.po @@ -70,6 +70,9 @@ msgstr "Байты" msgid "Cancel" msgstr "Отмена" +msgid "Change dnsmasq config directory" +msgstr "Изменить директорию конфигов dnsmasq" + msgid "Changes have been saved." msgstr "Изменения сохранены." @@ -110,12 +113,18 @@ msgstr "День" msgid "Debug" msgstr "Отладка" +msgid "Description" +msgstr "Описание" + msgid "Disabled" msgstr "Отключено" msgid "Dismiss" msgstr "Закрыть" +msgid "Dnsmasq config directory" +msgstr "Директория конфигов dnsmasq" + msgid "Download error" msgstr "Ошибка загрузки" @@ -125,9 +134,15 @@ msgstr "Скачать журнал" msgid "Downloading a blacklist via proxy" msgstr "Скачивать блэклист через прокси" +msgid "Downloading files via proxy" +msgstr "Скачивать файлы через прокси" + msgid "Edit" msgstr "Изменить" +msgid "Edit entries" +msgstr "Изменить записи" + msgid "Emergency" msgstr "Чрезвычайная ситуация" @@ -233,15 +248,15 @@ msgstr "Шаблоны IP подсетей (/24) не подлежащих оп msgid "Info" msgstr "Информация" +msgid "Instance" +msgstr "Экземпляр" + msgid "Interval" msgstr "Интервал" msgid "Invalid regular expression" msgstr "Неправильное регулярное выражение" -msgid "Nftables rules" -msgstr "Правила nftables" - msgid "Last blacklist update" msgstr "Последнее обновление блэклиста" @@ -257,6 +272,9 @@ msgstr "Список хостов, которые исключаются из о msgid "Loading" msgstr "Загрузка" +msgid "Local traffic" +msgstr "Локальный трафик" + msgid "Log" msgstr "Лог" @@ -269,6 +287,9 @@ msgstr "Уровни логирования" msgid "Logread not found" msgstr "Logread не найден" +msgid "Lowest priority" +msgstr "Самый низкий приоритет" + msgid "Main settings" msgstr "Основные настройки" @@ -373,9 +394,15 @@ msgstr "Отбор IP адресов из блэклиста по шаблона msgid "Pick domains from blacklist by FQDN filter patterns" msgstr "Отбор доменов из блэклиста по шаблонам фильтра FQDN" +msgid "Protocol" +msgstr "Протокол" + msgid "Proxy mode" msgstr "Режим прокси" +msgid "Proxy type" +msgstr "Тип прокси" + msgid "Reduces RAM consumption during update" msgstr "Уменьшает потребление оперативной памяти при обновлении" @@ -418,8 +445,11 @@ msgstr "Настройки" msgid "Shutdown" msgstr "Выключение" -msgid "Size in memory" -msgstr "Размер в памяти" +msgid "Skip marked packets" +msgstr "Пропускать помеченные пакеты" + +msgid "Skip packets that have already been marked in previous rules" +msgstr "Пропускать пакеты, которые уже были помечены в предыдущих правилах" msgid "Sorting entries" msgstr "Сортировка записей" @@ -430,6 +460,9 @@ msgstr "Запускается" msgid "Statistics" msgstr "Статистика" +msgid "Statement in nftables rules" +msgstr "Действие в правилах nftables" + msgid "Status" msgstr "Статус" @@ -469,6 +502,9 @@ msgid "" msgstr "" "Служба будет выключена и все данные блэклиста будут удалены. Продолжить?" +msgid "This proxy will receive traffic last, even after the main blacklist" +msgstr "В этот прокси трафик будет попадать в последнюю очередь, даже после основного блэклиста" + msgid "Time" msgstr "Время" @@ -487,6 +523,9 @@ msgstr "Конфигурационный файл Tor" msgid "Tor mode" msgstr "Режим Tor" +msgid "Transit traffic" +msgstr "Транзитный трафик" + msgid "Transparent proxy" msgstr "Прозрачный прокси" @@ -505,6 +544,9 @@ msgstr "UDP порт прозрачного прокси" msgid "Turn on if blacklist source is blocked" msgstr "Включите, если источник блэклиста заблокирован" +msgid "Turn on if files are blocked" +msgstr "Включите, если файлы заблокированы" + msgid "Type a search pattern..." msgstr "Введите шаблон для поиска" @@ -568,6 +610,9 @@ msgstr "Ошибка маршрутизации VPN! Необходим пере msgid "Warning" msgstr "Внимание" +msgid "all" +msgstr "все" + msgid "ascending" msgstr "по возрастанию" diff --git a/luci-app-ruantiblock/po/templates/ruantiblock.pot b/luci-app-ruantiblock/po/templates/ruantiblock.pot index fff608e..89473c7 100644 --- a/luci-app-ruantiblock/po/templates/ruantiblock.pot +++ b/luci-app-ruantiblock/po/templates/ruantiblock.pot @@ -55,6 +55,9 @@ msgstr "" msgid "Cancel" msgstr "" +msgid "Change dnsmasq config directory" +msgstr "" + msgid "Changes have been saved." msgstr "" @@ -95,12 +98,18 @@ msgstr "" msgid "Debug" msgstr "" +msgid "Description" +msgstr "" + msgid "Disabled" msgstr "" msgid "Dismiss" msgstr "" +msgid "Dnsmasq config directory" +msgstr "" + msgid "Download error" msgstr "" @@ -110,9 +119,15 @@ msgstr "" msgid "Downloading a blacklist via proxy" msgstr "" +msgid "Downloading files via proxy" +msgstr "" + msgid "Edit" msgstr "" +msgid "Edit entries" +msgstr "" + msgid "Emergency" msgstr "" msgid "Enable" @@ -214,15 +229,15 @@ msgstr "" msgid "Info" msgstr "" +msgid "Instance" +msgstr "" + msgid "Interval" msgstr "" msgid "Invalid regular expression" msgstr "" -msgid "Nftables rules" -msgstr "" - msgid "Last blacklist update" msgstr "" @@ -238,6 +253,9 @@ msgstr "" msgid "Loading" msgstr "" +msgid "Local traffic" +msgstr "" + msgid "Log" msgstr "" @@ -250,6 +268,9 @@ msgstr "" msgid "Logread not found" msgstr "" +msgid "Lowest priority" +msgstr "" + msgid "Main settings" msgstr "" @@ -342,9 +363,15 @@ msgstr "" msgid "Pick domains from blacklist by FQDN filter patterns" msgstr "" +msgid "Protocol" +msgstr "" + msgid "Proxy mode" msgstr "" +msgid "Proxy type" +msgstr "" + msgid "Reduces RAM consumption during update" msgstr "" @@ -386,9 +413,6 @@ msgstr "" msgid "Shutdown" msgstr "" -msgid "Size in memory" -msgstr "" - msgid "Sorting entries" msgstr "" @@ -397,6 +421,10 @@ msgstr "" msgid "Statistics" msgstr "" + +msgid "Statement in nftables rules" +msgstr "" + msgid "Status" msgstr "" @@ -429,6 +457,9 @@ msgid "" "Continue?" msgstr "" +msgid "This proxy will receive traffic last, even after the main blacklist" +msgstr "" + msgid "Time" msgstr "" @@ -447,6 +478,9 @@ msgstr "" msgid "Tor mode" msgstr "" +msgid "Transit traffic" +msgstr "" + msgid "Transparent proxy" msgstr "" @@ -465,6 +499,9 @@ msgstr "" msgid "Turn on if blacklist source is blocked" msgstr "" +msgid "Turn on if files are blocked" +msgstr "" + msgid "Type a search pattern..." msgstr "" @@ -509,6 +546,7 @@ msgid "URLs of remote user entries file" msgid "Use optional DNS resolver" msgstr "" + msgid "User entries" msgstr "" @@ -527,6 +565,9 @@ msgstr "" msgid "Warning" msgstr "" +msgid "all" +msgstr "все" + msgid "ascending" msgstr "" diff --git a/luci-app-ruantiblock/root/usr/share/rpcd/acl.d/luci-app-ruantiblock.json b/luci-app-ruantiblock/root/usr/share/rpcd/acl.d/luci-app-ruantiblock.json index ad22748..6dfe703 100644 --- a/luci-app-ruantiblock/root/usr/share/rpcd/acl.d/luci-app-ruantiblock.json +++ b/luci-app-ruantiblock/root/usr/share/rpcd/acl.d/luci-app-ruantiblock.json @@ -7,7 +7,7 @@ "/usr/libexec/ruantiblock": [ "list" ], "/etc/ruantiblock/fqdn_filter": [ "read" ], "/etc/ruantiblock/ip_filter": [ "read" ], - "/etc/ruantiblock/user_entries": [ "read" ], + "/etc/ruantiblock/user_lists/*": [ "read" ], "/etc/ruantiblock/bypass_entries": [ "read" ], "/etc/ruantiblock/gr_excluded_nets": [ "read" ], "/etc/ruantiblock/gr_excluded_sld": [ "read" ], @@ -16,7 +16,8 @@ "/etc/crontabs/root": [ "read" ], "/usr/bin/ruantiblock*": [ "exec" ], "/sbin/logread -e ruantiblock:": [ "exec" ], - "/usr/sbin/logread -e ruantiblock:": [ "exec" ] + "/usr/sbin/logread -e ruantiblock:": [ "exec" ], + "/tmp": [ "list" ] }, "uci": [ "network", "ruantiblock" ], "ubus": { @@ -27,7 +28,7 @@ "file": { "/etc/ruantiblock/fqdn_filter": [ "write" ], "/etc/ruantiblock/ip_filter": [ "write" ], - "/etc/ruantiblock/user_entries": [ "write" ], + "/etc/ruantiblock/user_lists/*": [ "write" ], "/etc/ruantiblock/bypass_entries": [ "write" ], "/etc/ruantiblock/gr_excluded_nets": [ "write" ], "/etc/ruantiblock/gr_excluded_sld": [ "write" ], diff --git a/ruantiblock-mod-lua/Makefile b/ruantiblock-mod-lua/Makefile index 82ec6ae..366ecd7 100644 --- a/ruantiblock-mod-lua/Makefile +++ b/ruantiblock-mod-lua/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock-mod-lua -PKG_VERSION:=1.6.0 +PKG_VERSION:=2.0.0 PKG_RELEASE:=1 PKG_MAINTAINER:=gSpot diff --git a/ruantiblock-mod-lua/files/usr/libexec/ruantiblock/ruab_parser.lua b/ruantiblock-mod-lua/files/usr/libexec/ruantiblock/ruab_parser.lua index fe34241..e4fdde0 100755 --- a/ruantiblock-mod-lua/files/usr/libexec/ruantiblock/ruab_parser.lua +++ b/ruantiblock-mod-lua/files/usr/libexec/ruantiblock/ruab_parser.lua @@ -58,9 +58,8 @@ local Config = Class(nil, { ["NFTSET_CIDR"] = true, ["NFTSET_IP"] = true, ["NFTSET_DNSMASQ"] = true, - ["NFTSET_CIDR_CFG"] = true, - ["NFTSET_IP_CFG"] = true, - ["NFTSET_DNSMASQ"] = true, + ["NFTSET_CIDR_STRING_MAIN"] = true, + ["NFTSET_IP_STRING_MAIN"] = true, ["DNSMASQ_DATA_FILE"] = true, ["IP_DATA_FILE"] = true, ["UPDATE_STATUS_FILE"] = true, @@ -788,7 +787,7 @@ function WriteConfigFiles:write_ipset_config(ip_table, cidr_table) file_handler:write(string.format("flush set %s %s\n", self.NFT_TABLE, v)) end file_handler:write( - string.format("table %s {\n%s", self.NFT_TABLE, self.NFTSET_CIDR_CFG) + string.format("table %s {\n%s", self.NFT_TABLE, self.NFTSET_CIDR_STRING_MAIN) ) local c = 0 if next(cidr_table) then @@ -801,7 +800,7 @@ function WriteConfigFiles:write_ipset_config(ip_table, cidr_table) end self.cidr_count = c file_handler:write( - string.format("}\n%s", self.NFTSET_IP_CFG) + string.format("}\n%s", self.NFTSET_IP_STRING_MAIN) ) local i = 0 if next(ip_table) then @@ -1076,6 +1075,7 @@ if parser_classes then for _, i in ipairs(parser_instances) do ret_list[i:run()] = true end + local return_sum = 0 for i, _ in pairs(ret_list) do return_sum = return_sum + i diff --git a/ruantiblock-mod-py/Makefile b/ruantiblock-mod-py/Makefile index 9e550e1..74af266 100644 --- a/ruantiblock-mod-py/Makefile +++ b/ruantiblock-mod-py/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock-mod-py -PKG_VERSION:=1.6.0 +PKG_VERSION:=2.0.0 PKG_RELEASE:=1 PKG_MAINTAINER:=gSpot diff --git a/ruantiblock-mod-py/files/usr/libexec/ruantiblock/ruab_parser.py b/ruantiblock-mod-py/files/usr/libexec/ruantiblock/ruab_parser.py index b6a1009..934e52e 100755 --- a/ruantiblock-mod-py/files/usr/libexec/ruantiblock/ruab_parser.py +++ b/ruantiblock-mod-py/files/usr/libexec/ruantiblock/ruab_parser.py @@ -42,9 +42,8 @@ class Config: "NFTSET_CIDR", "NFTSET_IP", "NFTSET_DNSMASQ", - "NFTSET_CIDR_CFG", - "NFTSET_IP_CFG", - "NFTSET_DNSMASQ", + "NFTSET_CIDR_STRING_MAIN", + "NFTSET_IP_STRING_MAIN", "DNSMASQ_DATA_FILE", "IP_DATA_FILE", "UPDATE_STATUS_FILE", @@ -459,6 +458,7 @@ class Summarize: @classmethod def _group_nets(cls, cidr_list, raw_list=None): + def remove_items(start, end): for ip in range(int(start), int(end) + 1, 256): raw_list.remove(str(IPv4Address(ip)) + "/24") @@ -570,7 +570,7 @@ class WriteConfigFiles(Config): for i in (self.NFTSET_CIDR, self.NFTSET_IP): file_handler.write("flush set {} {}\n".format(self.NFT_TABLE, i)) file_handler.write( - "table {} {{\n{}".format(self.NFT_TABLE, self.NFTSET_CIDR_CFG) + "table {} {{\n{}".format(self.NFT_TABLE, self.NFTSET_CIDR_STRING_MAIN) ) if len(cidr_set) > 0: file_handler.write("elements={") @@ -578,7 +578,7 @@ class WriteConfigFiles(Config): file_handler.write(f"{i},") file_handler.write("};") file_handler.write( - "}}\n{}".format(self.NFTSET_IP_CFG) + "}}\n{}".format(self.NFTSET_IP_STRING_MAIN) ) if len(ip_dict) > 0: file_handler.write("elements={") diff --git a/ruantiblock/Makefile b/ruantiblock/Makefile index 8db4dc4..db35aa1 100644 --- a/ruantiblock/Makefile +++ b/ruantiblock/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ruantiblock -PKG_VERSION:=1.6.0 +PKG_VERSION:=2.0.0 PKG_RELEASE:=1 PKG_MAINTAINER:=gSpot @@ -17,7 +17,7 @@ define Package/$(PKG_NAME) TITLE:=Ruantiblock URL:=https://github.com/gSpotx2f/ruantiblock_openwrt PKGARCH:=all - DEPENDS:=+dnsmasq-full + DEPENDS:=+dnsmasq-full +kmod-nft-tproxy endef define Package/$(PKG_NAME)/description @@ -28,10 +28,14 @@ define Package/$(PKG_NAME)/conffiles /etc/ruantiblock/ruantiblock.conf /etc/ruantiblock/fqdn_filter /etc/ruantiblock/ip_filter -/etc/ruantiblock/user_entries /etc/ruantiblock/bypass_entries /etc/ruantiblock/gr_excluded_nets /etc/ruantiblock/gr_excluded_sld +/etc/ruantiblock/user_lists/list1 +/etc/ruantiblock/user_lists/list2 +/etc/ruantiblock/user_lists/list3 +/etc/ruantiblock/user_lists/list4 +/etc/ruantiblock/user_lists/list5 endef define Build/Configure @@ -51,15 +55,22 @@ define Package/$(PKG_NAME)/install $(INSTALL_CONF) ./files/etc/ruantiblock/ruantiblock.conf $(1)/etc/ruantiblock/ruantiblock.conf $(INSTALL_DATA) ./files/etc/ruantiblock/fqdn_filter $(1)/etc/ruantiblock/fqdn_filter $(INSTALL_DATA) ./files/etc/ruantiblock/ip_filter $(1)/etc/ruantiblock/ip_filter - $(INSTALL_DATA) ./files/etc/ruantiblock/user_entries $(1)/etc/ruantiblock/user_entries $(INSTALL_DATA) ./files/etc/ruantiblock/bypass_entries $(1)/etc/ruantiblock/bypass_entries $(INSTALL_DATA) ./files/etc/ruantiblock/gr_excluded_nets $(1)/etc/ruantiblock/gr_excluded_nets $(INSTALL_DATA) ./files/etc/ruantiblock/gr_excluded_sld $(1)/etc/ruantiblock/gr_excluded_sld + $(INSTALL_DIR) $(1)/etc/ruantiblock/user_lists + $(INSTALL_DATA) ./files/etc/ruantiblock/user_lists/list1 $(1)/etc/ruantiblock/user_lists/list1 + $(INSTALL_DATA) ./files/etc/ruantiblock/user_lists/list2 $(1)/etc/ruantiblock/user_lists/list2 + $(INSTALL_DATA) ./files/etc/ruantiblock/user_lists/list3 $(1)/etc/ruantiblock/user_lists/list3 + $(INSTALL_DATA) ./files/etc/ruantiblock/user_lists/list4 $(1)/etc/ruantiblock/user_lists/list4 + $(INSTALL_DATA) ./files/etc/ruantiblock/user_lists/list5 $(1)/etc/ruantiblock/user_lists/list5 $(INSTALL_DIR) $(1)/usr/share/ruantiblock + $(INSTALL_DATA) ./files/usr/share/ruantiblock/blacklist_sources $(1)/usr/share/ruantiblock/blacklist_sources $(INSTALL_DATA) ./files/usr/share/ruantiblock/config_script $(1)/usr/share/ruantiblock/config_script + $(INSTALL_DATA) ./files/usr/share/ruantiblock/config_script_user_instances $(1)/usr/share/ruantiblock/config_script_user_instances $(INSTALL_DATA) ./files/usr/share/ruantiblock/info_output $(1)/usr/share/ruantiblock/info_output $(INSTALL_DATA) ./files/usr/share/ruantiblock/nft_functions $(1)/usr/share/ruantiblock/nft_functions - $(INSTALL_DATA) ./files/usr/share/ruantiblock/blacklist_sources $(1)/usr/share/ruantiblock/blacklist_sources + $(INSTALL_DATA) ./files/usr/share/ruantiblock/user_instances_common $(1)/usr/share/ruantiblock/user_instances_common $(INSTALL_DIR) $(1)/usr/libexec/ruantiblock $(INSTALL_BIN) ./files/usr/libexec/ruantiblock/ruab_route_check $(1)/usr/libexec/ruantiblock/ruab_route_check $(INSTALL_DIR) $(1)/usr/bin @@ -82,14 +93,16 @@ define Package/$(PKG_NAME)/prerm FILE_INIT_SCRIPT="/etc/init.d/ruantiblock" FILE_MAIN_SCRIPT="/usr/bin/ruantiblock" CRONTAB_FILE="/etc/crontabs/root" -DNSMASQ_DATA_FILE="/tmp/dnsmasq.d/02-ruantiblock.dnsmasq" +DNSMASQ_DATA_FILE_BYPASS="/tmp/dnsmasq*.d/00-ruantiblock_bypass.dnsmasq" +DNSMASQ_DATA_FILE_USER_INSTANCES="/tmp/dnsmasq*.d/01-ruantiblock_user_instances.dnsmasq" +DNSMASQ_DATA_FILE="/tmp/dnsmasq*.d/02-ruantiblock.dnsmasq" +DNSMASQ_DATA_FILE_BYPASS_TMP="${DNSMASQ_DATA_FILE_BYPASS}.tmp" +DNSMASQ_DATA_FILE_USER_INSTANCES_TMP="${DNSMASQ_DATA_FILE_USER_INSTANCES}.tmp" DNSMASQ_DATA_FILE_TMP="${DNSMASQ_DATA_FILE}.tmp" -DNSMASQ_DATA_FILE_BYPASS="/tmp/dnsmasq.d/01-ruantiblock_bypass.dnsmasq" -rm -f $$DNSMASQ_DATA_FILE $$DNSMASQ_DATA_FILE_TMP $$DNSMASQ_DATA_FILE_BYPASS test -e "$$FILE_MAIN_SCRIPT" && $$FILE_MAIN_SCRIPT destroy - test -e "$$FILE_INIT_SCRIPT" && $$FILE_INIT_SCRIPT disable +rm -f $$DNSMASQ_DATA_FILE $$DNSMASQ_DATA_FILE_TMP $$DNSMASQ_DATA_FILE_BYPASS $$DNSMASQ_DATA_FILE_BYPASS_TMP $$DNSMASQ_DATA_FILE_USER_INSTANCES $$DNSMASQ_DATA_FILE_USER_INSTANCES_TMP awk -v FILE_MAIN_SCRIPT="$$FILE_MAIN_SCRIPT" '$$0 !~ FILE_MAIN_SCRIPT { print $$0; diff --git a/ruantiblock/files/etc/config/ruantiblock b/ruantiblock/files/etc/config/ruantiblock index 86b59e7..412ffaf 100644 --- a/ruantiblock/files/etc/config/ruantiblock +++ b/ruantiblock/files/etc/config/ruantiblock @@ -11,13 +11,13 @@ config main 'config' option vpn_route_check '0' option tor_trans_port '9040' option onion_dns_addr '127.0.0.1#9053' + option t_proxy_type '0' option t_proxy_port_tcp '1100' option t_proxy_port_udp '1100' option t_proxy_allow_udp '0' option bypass_mode '0' option enable_bllist_proxy '0' option enable_tmp_downloads '0' - option add_user_entries '0' option bllist_min_entries '3000' option bllist_ip_limit '0' option bllist_summarize_ip '1' @@ -30,3 +30,78 @@ config main 'config' option bllist_enable_idn '0' option bllist_alt_nslookup '0' option bllist_alt_dns_addr '8.8.8.8' + +config user_instance 'list1' + option u_enabled '0' + option u_proxy_mode '2' + option u_tor_trans_port '9040' + option u_onion_dns_addr '127.0.0.1#9053' + option u_if_vpn 'tun0' + option u_t_proxy_type '0' + option u_t_proxy_port_tcp '1100' + option u_t_proxy_port_udp '1100' + option u_t_proxy_allow_udp '0' + option u_enable_entries_remote_proxy '0' + option u_entries_dns '' + option u_enable_fproxy '0' + option u_skip_marked_packets '0' + +config user_instance 'list2' + option u_enabled '0' + option u_proxy_mode '2' + option u_tor_trans_port '9040' + option u_onion_dns_addr '127.0.0.1#9053' + option u_if_vpn 'tun0' + option u_t_proxy_type '0' + option u_t_proxy_port_tcp '1100' + option u_t_proxy_port_udp '1100' + option u_t_proxy_allow_udp '0' + option u_enable_entries_remote_proxy '0' + option u_entries_dns '' + option u_enable_fproxy '0' + option u_skip_marked_packets '0' + +config user_instance 'list3' + option u_enabled '0' + option u_proxy_mode '2' + option u_tor_trans_port '9040' + option u_onion_dns_addr '127.0.0.1#9053' + option u_if_vpn 'tun0' + option u_t_proxy_type '0' + option u_t_proxy_port_tcp '1100' + option u_t_proxy_port_udp '1100' + option u_t_proxy_allow_udp '0' + option u_enable_entries_remote_proxy '0' + option u_entries_dns '' + option u_enable_fproxy '0' + option u_skip_marked_packets '0' + +config user_instance 'list4' + option u_enabled '0' + option u_proxy_mode '2' + option u_tor_trans_port '9040' + option u_onion_dns_addr '127.0.0.1#9053' + option u_if_vpn 'tun0' + option u_t_proxy_type '0' + option u_t_proxy_port_tcp '1100' + option u_t_proxy_port_udp '1100' + option u_t_proxy_allow_udp '0' + option u_enable_entries_remote_proxy '0' + option u_entries_dns '' + option u_enable_fproxy '0' + option u_skip_marked_packets '0' + +config user_instance 'list5' + option u_enabled '0' + option u_proxy_mode '2' + option u_tor_trans_port '9040' + option u_onion_dns_addr '127.0.0.1#9053' + option u_if_vpn 'tun0' + option u_t_proxy_type '0' + option u_t_proxy_port_tcp '1100' + option u_t_proxy_port_udp '1100' + option u_t_proxy_allow_udp '0' + option u_enable_entries_remote_proxy '0' + option u_entries_dns '' + option u_enable_fproxy '0' + option u_skip_marked_packets '0' diff --git a/ruantiblock/files/etc/hotplug.d/iface/40-ruantiblock b/ruantiblock/files/etc/hotplug.d/iface/40-ruantiblock index 08f1693..f354656 100755 --- a/ruantiblock/files/etc/hotplug.d/iface/40-ruantiblock +++ b/ruantiblock/files/etc/hotplug.d/iface/40-ruantiblock @@ -1,20 +1,64 @@ #!/bin/sh -UCI_CMD=`which uci` -if [ $? -ne 0 ]; then - echo " Error! UCI doesn't exists" >&2 - exit 1 -fi -RUAB_CMD="/usr/bin/ruantiblock" -PROXY_MODE=`$UCI_CMD get ruantiblock.config.proxy_mode` -IF_VPN=`$UCI_CMD get ruantiblock.config.if_vpn` -VPN_ROUTE_CHECK=`$UCI_CMD get ruantiblock.config.vpn_route_check` +if [ "$ACTION" = "ifup" ]; then + NAME="ruantiblock" + RUAB_CMD="/usr/bin/ruantiblock" + CONFIG_FILE="/etc/ruantiblock/ruantiblock.conf" + USER_INSTANCES_COMMON="/usr/share/ruantiblock/user_instances_common" + CONFIG_SCRIPT_USER_INSTANCES="/usr/share/ruantiblock/config_script_user_instances" + USER_INSTANCES_DIR="/etc/ruantiblock/user_instances" + USER_INSTANCE_VARS="U_ENABLED U_NAME U_PROXY_MODE U_TOR_TRANS_PORT U_ONION_DNS_ADDR U_IF_VPN U_VPN_GW_IP U_T_PROXY_TYPE U_T_PROXY_PORT_TCP U_T_PROXY_PORT_UDP U_T_PROXY_ALLOW_UDP U_USER_ENTRIES_DNS U_USER_ENTRIES_REMOTE U_ENABLE_ENTRIES_REMOTE_PROXY U_ENABLE_FPROXY U_FPROXY_LIST U_SKIP_MARKED_PACKETS" + USER_INSTANCES_MAX=10 + DEBUG=0 + IF_VPN_CURRENT="" -[ "$VPN_ROUTE_CHECK" != "0" ] && exit 0 + ruab_route_status=`$RUAB_CMD raw-status` + [ $ruab_route_status -eq 1 -o $ruab_route_status -eq 2 ] && exit 0 -if [ "$ACTION" = "ifup" ] && [ "$PROXY_MODE" = "2" ] && [ "$DEVICE" = "$IF_VPN" ]; then - if [ `$RUAB_CMD raw-status` -ne 2 ]; then - sleep 5 - $RUAB_CMD reload - fi + UCI_CMD=`which uci` + if [ $? -ne 0 ]; then + echo " Error! UCI doesn't exists" >&2 + exit 1 + fi + + [ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE" + + VPN_ROUTE_CHECK=`$UCI_CMD get ruantiblock.config.vpn_route_check` + [ "$VPN_ROUTE_CHECK" != "0" ] && exit 0 + + PROXY_MODE=`$UCI_CMD get ruantiblock.config.proxy_mode` + if [ "$PROXY_MODE" = "2" ]; then + IF_VPN_CURRENT=`$UCI_CMD get ruantiblock.config.if_vpn` + fi + + if [ "$DEVICE" != "$IF_VPN_CURRENT" ]; then + + . "$USER_INSTANCES_COMMON" + + for inst in `GetUserInstances 2` + do + IncludeUserInstanceVars "$inst" + if [ "$DEVICE" = "$U_IF_VPN" ]; then + IF_VPN_CURRENT="$U_IF_VPN" + + if [ $DEBUG -ge 1 ]; then + echo " ruantiblock-vpn-iface-script: U_NAME=${U_NAME} U_IF_VPN=${U_IF_VPN}" >&2 + logger -p "user.debug" -t "ruantiblock-hotplug-script" "U_NAME=${U_NAME} U_IF_VPN=${U_IF_VPN}" + fi + + break + fi + ClearUserInstanceVars + done + fi + + if [ "$DEVICE" = "$IF_VPN_CURRENT" ]; then + if [ $DEBUG -ge 1 ]; then + echo " ruantiblock-vpn-iface-script: IF_VPN_CURRENT=${IF_VPN_CURRENT} ACTION=\"${ACTION}\" DEVICE=${DEVICE} INTERFACE=${INTERFACE}" >&2 + logger -p "user.debug" -t "ruantiblock-hotplug-script" "IF_VPN_CURRENT=${IF_VPN_CURRENT} ACTION=\"${ACTION}\" DEVICE=${DEVICE} INTERFACE=${INTERFACE}" + fi + + sleep 5 + $RUAB_CMD reload + fi fi diff --git a/ruantiblock/files/etc/init.d/ruantiblock b/ruantiblock/files/etc/init.d/ruantiblock index e54a79d..4dbf66c 100755 --- a/ruantiblock/files/etc/init.d/ruantiblock +++ b/ruantiblock/files/etc/init.d/ruantiblock @@ -5,14 +5,40 @@ STOP=01 APP_NAME="ruantiblock" APP_EXEC="/usr/bin/${APP_NAME}" +DNSMASQ_VAR_DIR="/tmp" config_load $APP_NAME +get_dnsmasq_cfg_dir() { + local _first_instance + if [ -d "${DNSMASQ_VAR_DIR}/dnsmasq.d" ]; then + printf "${DNSMASQ_VAR_DIR}/dnsmasq.d" + return 0 + else + _first_instance=`ls -1 "$DNSMASQ_VAR_DIR" | grep -e "^dnsmasq" | head -n 1` + if [ -n "$_first_instance" ]; then + printf "${DNSMASQ_VAR_DIR}/${_first_instance}" + return 0 + fi + fi + return 1 +} + start() { - local update_at_startup - config_get update_at_startup config update_at_startup + local _update_at_startup _dnsmasq_cfg_dir + config_get _update_at_startup config update_at_startup + config_get _dnsmasq_cfg_dir config dnsmasq_cfg_dir "" + if [ -z "$_dnsmasq_cfg_dir" ]; then + _dnsmasq_cfg_dir=`get_dnsmasq_cfg_dir` + if [ $? -eq 0 -a -n "$_dnsmasq_cfg_dir" ]; then + uci set "${APP_NAME}.config.dnsmasq_cfg_dir"="$_dnsmasq_cfg_dir" + uci commit ruantiblock + else + exit 1 + fi + fi $APP_EXEC start - if [ $? -eq 0 -a "$update_at_startup" = "1" ]; then + if [ $? -eq 0 -a "$_update_at_startup" = "1" ]; then $APP_EXEC update else /etc/init.d/dnsmasq restart diff --git a/ruantiblock/files/etc/ruantiblock/fqdn_filter b/ruantiblock/files/etc/ruantiblock/fqdn_filter index 55a5c3a..f8888d0 100644 --- a/ruantiblock/files/etc/ruantiblock/fqdn_filter +++ b/ruantiblock/files/etc/ruantiblock/fqdn_filter @@ -82,4 +82,3 @@ birds forex kraken zerkalo -#lord diff --git a/ruantiblock/files/etc/ruantiblock/ruantiblock.conf b/ruantiblock/files/etc/ruantiblock/ruantiblock.conf index ce0b7d6..4eacf1b 100644 --- a/ruantiblock/files/etc/ruantiblock/ruantiblock.conf +++ b/ruantiblock/files/etc/ruantiblock/ruantiblock.conf @@ -5,9 +5,10 @@ DATA_DIR="/tmp/ruantiblock" ### Директория модулей MODULES_DIR="/usr/libexec/ruantiblock" -### Дополнительный конфиг dnsmasq с FQDN записями блэклиста -DNSMASQ_DATA_FILE="/tmp/dnsmasq.d/02-ruantiblock.dnsmasq" -DNSMASQ_DATA_FILE_BYPASS="/tmp/dnsmasq.d/01-ruantiblock_bypass.dnsmasq" +### Директория PID-файлов и файлов статуса +RUN_FILES_DIR="/tmp/run" +### Директория доп. конфигов dnsmasq +DNSMASQ_CFG_DIR="/tmp/dnsmasq.d" ### Команда для перезапуска dnsmasq DNSMASQ_RESTART_CMD="/etc/init.d/dnsmasq restart" ### Директория для html-страницы статуса (не используется в OpenWrt) @@ -31,26 +32,26 @@ ONION_DNS_ADDR="127.0.0.1#9053" IF_VPN="tun0" ### IP адрес шлюза для VPN конфигурации. Если не задан, используется адрес VPN интерфейса (или адрес пира для протоколов PPP) VPN_GW_IP="" -### Метка для отбора пакетов в VPN туннель -VPN_PKTS_MARK=8 -### Таблица маршрутизации для отправки пакетов в VPN туннель -VPN_ROUTE_TABLE_ID=99 -### Приоритет правила отбора пакетов при маршрутизации в VPN-интерфейс -VPN_RULE_PRIO=1000 ### Способ добавления в таблицу маршрутизации правила для отправки пакетов в VPN туннель (0 - hotplug.d, 1 - скрипт ruab_route_check) VPN_ROUTE_CHECK=0 +### Тип прозрачного прокси (0 - redirect, 1 - tproxy) +T_PROXY_TYPE=0 ### TCP порт прокси в режиме прозрачного прокси T_PROXY_PORT_TCP=1100 ### UDP порт прокси в режиме прозрачного прокси T_PROXY_PORT_UDP=1100 ### Отправлять в прозрачный прокси UDP-трафик (0 - выкл, 1 - вкл) T_PROXY_ALLOW_UDP=0 +### Начальное значение метки для отбора пакетов в фильтрах +PKTS_MARK_START=8 ### Запись событий в syslog (0 - выкл, 1 - вкл) ENABLE_LOGGING=1 +### Вывод дополнительных сообщений в лог (0 - выкл, 1, 2) +DEBUG=0 ### Html-страница с инфо о текущем статусе (0 - выкл, 1 - вкл) (не используется в OpenWrt) ENABLE_HTML_INFO=0 ### Максимальное кол-во элементов списка nftables -#NFTSET_MAXELEM_CIDR=65535 +NFTSET_MAXELEM_CIDR=65535 NFTSET_MAXELEM_IP=1000000 NFTSET_MAXELEM_DNSMASQ=65535 NFTSET_MAXELEM_BYPASS_IP=65535 @@ -63,29 +64,14 @@ NFTSET_POLICY_DNSMASQ="performance" NFTSET_DNSMASQ_TIMEOUT="150m" ### Динамическое обновление таймаута записей в сете $NFTSET_DNSMASQ (0 - выкл, 1 - вкл) NFTSET_DNSMASQ_TIMEOUT_UPDATE=1 -### Приоритет правила отбора пакетов nftables для конфигупации Tor или прозрачного прокси -NFT_PRIO_NAT="dstnat - 10" -### Приоритет правила отбора пакетов nftables для трафика локальных клиентов в конфигупации Tor или прозрачного прокси -NFT_PRIO_NAT_LOCAL="filter - 10" -### Приоритет правила отбора пакетов nftables для VPN-конфигурации -NFT_PRIO_ROUTE="mangle + 10" -### Приоритет правила отбора пакетов nftables для трафика локальных клиентов в VPN-конфигурации -NFT_PRIO_ROUTE_LOCAL="mangle + 10" -### Добавление в список блокировок пользовательских записей из файла $USER_ENTRIES_FILE (0 - выкл, 1 - вкл) -### В $CONFIG_DIR можно создать текстовый файл user_entries с записями IP, CIDR или FQDN (одна на строку). Эти записи будут добавлены в список блокировок -### В записях FQDN можно задать DNS-сервер для разрешения данного домена, через пробел (прим.: domain.com 8.8.8.8) -### Можно комментировать строки (#) -ADD_USER_ENTRIES=0 -### DNS-сервер для пользовательских записей (пустая строка - без DNS-сервера). Можно с портом: 8.8.8.8#53. Если в записи указан свой DNS-сервер - он имеет приоритет -USER_ENTRIES_DNS="" -### Файл пользовательских записей -USER_ENTRIES_FILE="/etc/ruantiblock/user_entries" -### URL удаленных файлов записей пользователя, через пробел (прим.: http://server.lan/files/user_entries_1 http://server.lan/files/user_entries_2) -USER_ENTRIES_REMOTE="" ### Кол-во попыток скачивания удаленного файла записей пользователя (в случае неудачи) USER_ENTRIES_REMOTE_DOWNLOAD_ATTEMPTS=3 ### Таймаут между попытками скачивания USER_ENTRIES_REMOTE_DOWNLOAD_TIMEOUT=60 +### Кол-во экземпляров записей пользователя (не более 50!) +USER_INSTANCES_MAX=5 +### Пропускать мимо фильтра пакеты уже помеченные в записях пользователя (0 - выкл, 1 - вкл) +SKIP_MARKED_PACKETS=0 ### Режим списка записей, исключаемых из обхода блокировок (0 - выкл, 1 - вкл) BYPASS_MODE=0 ### DNS-сервер для исключаемых записей (пустая строка - без DNS-сервера). Можно с портом: 8.8.8.8#53. Если в записи указан свой DNS-сервер - он имеет приоритет @@ -143,7 +129,7 @@ BLLIST_SD_LIMIT=16 BLLIST_GR_EXCLUDED_SLD_FILE="/etc/ruantiblock/gr_excluded_sld" ### Файл с масками SLD не подлежащими группировке при оптимизации (одна запись на строку) BLLIST_GR_EXCLUDED_SLD_MASKS_FILE="/etc/ruantiblock/gr_excluded_sld_mask" -### Фильтрация записей блэклиста по шаблонам из файла ENTRIES_FILTER_FILE. Записи (FQDN) попадающие под шаблоны исключаются из кофига dnsmasq (0 - выкл, 1 - вкл) +### Фильтрация записей блэклиста по шаблонам из файла BLLIST_FQDN_FILTER_FILE. Записи (FQDN) попадающие под шаблоны исключаются из кофига dnsmasq (0 - выкл, 1 - вкл) BLLIST_FQDN_FILTER=0 ### Тип фильтра FQDN (0 - все записи, кроме совпадающих с шаблонами; 1 - только записи, совпадающие с шаблонами) BLLIST_FQDN_FILTER_TYPE=0 diff --git a/ruantiblock/files/etc/ruantiblock/user_entries b/ruantiblock/files/etc/ruantiblock/user_lists/list1 similarity index 100% rename from ruantiblock/files/etc/ruantiblock/user_entries rename to ruantiblock/files/etc/ruantiblock/user_lists/list1 diff --git a/ruantiblock/files/etc/ruantiblock/user_lists/list2 b/ruantiblock/files/etc/ruantiblock/user_lists/list2 new file mode 100644 index 0000000..e69de29 diff --git a/ruantiblock/files/etc/ruantiblock/user_lists/list3 b/ruantiblock/files/etc/ruantiblock/user_lists/list3 new file mode 100644 index 0000000..e69de29 diff --git a/ruantiblock/files/etc/ruantiblock/user_lists/list4 b/ruantiblock/files/etc/ruantiblock/user_lists/list4 new file mode 100644 index 0000000..e69de29 diff --git a/ruantiblock/files/etc/ruantiblock/user_lists/list5 b/ruantiblock/files/etc/ruantiblock/user_lists/list5 new file mode 100644 index 0000000..e69de29 diff --git a/ruantiblock/files/usr/bin/ruantiblock b/ruantiblock/files/usr/bin/ruantiblock index 899137d..e9dc6be 100755 --- a/ruantiblock/files/usr/bin/ruantiblock +++ b/ruantiblock/files/usr/bin/ruantiblock @@ -18,11 +18,11 @@ export LANGUAGE="en" CONFIG_DIR="/etc/${NAME}" CONFIG_FILE="${CONFIG_DIR}/${NAME}.conf" SCRIPTS_DIR="/usr/share/${NAME}" -export DATA_DIR="${CONFIG_DIR}/var" +export DATA_DIR="/var/${NAME}" export MODULES_DIR="/usr/libexec/${NAME}" -### Дополнительный конфиг dnsmasq с FQDN записями блэклиста -export DNSMASQ_DATA_FILE="/var/dnsmasq.d/02-${NAME}.dnsmasq" -export DNSMASQ_DATA_FILE_BYPASS="/var/dnsmasq.d/01-${NAME}_bypass.dnsmasq" +RUN_FILES_DIR="/var/run" +### Директория доп. конфигов dnsmasq +export DNSMASQ_CFG_DIR="/var/dnsmasq.d" ### Команда для перезапуска dnsmasq export DNSMASQ_RESTART_CMD="/etc/init.d/dnsmasq restart" ### Директория для html-страницы статуса (не используется в OpenWrt) @@ -48,22 +48,30 @@ export ONION_DNS_ADDR="127.0.0.1#9053" export IF_VPN="tun0" ### IP адрес шлюза для VPN конфигурации. Если не задан, используется адрес VPN интерфейса (или адрес пира для протоколов PPP) export VPN_GW_IP="" -### Метка для отбора пакетов в VPN туннель -export VPN_PKTS_MARK=8 -### Таблица маршрутизации для отправки пакетов в VPN туннель -export VPN_ROUTE_TABLE_ID=99 +### Начальный номер таблицы маршрутизации для отправки пакетов в VPN туннель +export VPN_ROUTE_TABLE_ID_START=149 +### Начальный номер таблицы маршрутизации для отправки локальных пакетов в tproxy +export TPROXY_ROUTE_TABLE_ID_START=201 ### Приоритет правила отбора пакетов при маршрутизации в VPN-интерфейс export VPN_RULE_PRIO=1000 +### Приоритет правила отбора пакетов при маршрутизации в lo интерфейс +export LO_RULE_PRIO=1000 ### Способ добавления в таблицу маршрутизации правила для отправки пакетов в VPN туннель (0 - hotplug.d, 1 - скрипт ruab_route_check) export VPN_ROUTE_CHECK=0 +### Тип прозрачного прокси (0 - redirect, 1 - tproxy) +export T_PROXY_TYPE=0 ### TCP порт прокси в режиме прозрачного прокси export T_PROXY_PORT_TCP=1100 ### UDP порт прокси в режиме прозрачного прокси export T_PROXY_PORT_UDP=1100 ### Отправлять в прозрачный прокси UDP-трафик (0 - выкл, 1 - вкл) export T_PROXY_ALLOW_UDP=0 +### Начальное значение метки для отбора пакетов в фильтрах +export PKTS_MARK_START=8 ### Запись событий в syslog (0 - выкл, 1 - вкл) export ENABLE_LOGGING=1 +### Вывод дополнительных сообщений в лог (0 - выкл, 1, 2) +export DEBUG=0 ### Html-страница с инфо о текущем статусе (0 - выкл, 1 - вкл) (не используется в OpenWrt) export ENABLE_HTML_INFO=0 ### Максимальное кол-во элементов списка nftables @@ -81,28 +89,27 @@ export NFTSET_DNSMASQ_TIMEOUT="150m" ### Динамическое обновление таймаута записей в сете $NFTSET_DNSMASQ (0 - выкл, 1 - вкл) export NFTSET_DNSMASQ_TIMEOUT_UPDATE=1 ### Приоритет правила отбора пакетов nftables для конфигупации Tor или прозрачного прокси -export NFT_PRIO_NAT="dstnat - 10" +export NFT_PRIO_NAT=-140 # dstnat - 10 (-110) ### Приоритет правила отбора пакетов nftables для трафика локальных клиентов в конфигупации Tor или прозрачного прокси -export NFT_PRIO_NAT_LOCAL="filter - 10" +export NFT_PRIO_NAT_LOCAL=-140 # dstnat - 10 (-110) ### Приоритет правила отбора пакетов nftables для VPN-конфигурации -export NFT_PRIO_ROUTE="mangle + 10" +export NFT_PRIO_ROUTE=-140 # mangle + 10 ### Приоритет правила отбора пакетов nftables для трафика локальных клиентов в VPN-конфигурации -export NFT_PRIO_ROUTE_LOCAL="mangle + 10" -### Добавление в список блокировок пользовательских записей из файла $USER_ENTRIES_FILE (0 - выкл, 1 - вкл) -### В $CONFIG_DIR можно создать текстовый файл user_entries с записями IP, CIDR или FQDN (одна на строку). Эти записи будут добавлены в список блокировок -### В записях FQDN можно задать DNS-сервер для разрешения данного домена, через пробел (прим.: domain.com 8.8.8.8) -### Можно комментировать строки (#) -export ADD_USER_ENTRIES=0 -### DNS-сервер для пользовательских записей (пустая строка - без DNS-сервера). Можно с портом: 8.8.8.8#53. Если в записи указан свой DNS-сервер - он имеет приоритет -export USER_ENTRIES_DNS="" -### Файл пользовательских записей -export USER_ENTRIES_FILE="${CONFIG_DIR}/user_entries" -### URL удаленных файлов записей пользователя, через пробел (прим.: http://server.lan/files/user_entries_1 http://server.lan/files/user_entries_2) -export USER_ENTRIES_REMOTE="" +export NFT_PRIO_ROUTE_LOCAL=-140 # mangle + 10 ### Кол-во попыток скачивания удаленного файла записей пользователя (в случае неудачи) export USER_ENTRIES_REMOTE_DOWNLOAD_ATTEMPTS=3 ### Таймаут между попытками скачивания export USER_ENTRIES_REMOTE_DOWNLOAD_TIMEOUT=60 +### Директория конфигов экземпляров записей пользователя +export USER_INSTANCES_DIR="${CONFIG_DIR}/user_instances" +### Директория списков записей пользователя +export USER_LISTS_DIR="${CONFIG_DIR}/user_lists" +### Переменные экземпляров записей пользователя +export USER_INSTANCE_VARS="U_ENABLED U_NAME U_PROXY_MODE U_TOR_TRANS_PORT U_ONION_DNS_ADDR U_IF_VPN U_VPN_GW_IP U_T_PROXY_TYPE U_T_PROXY_PORT_TCP U_T_PROXY_PORT_UDP U_T_PROXY_ALLOW_UDP U_USER_ENTRIES_DNS U_USER_ENTRIES_REMOTE U_ENABLE_ENTRIES_REMOTE_PROXY U_ENABLE_FPROXY U_FPROXY_LIST U_SKIP_MARKED_PACKETS" +### Кол-во экземпляров записей пользователя (не более 50!) +export USER_INSTANCES_MAX=5 +### Пропускать мимо фильтра пакеты уже помеченные в записях пользователя (0 - выкл, 1 - вкл) +export SKIP_MARKED_PACKETS=0 ### Режим списка IP адресов исключаемых из обхода блокировок (0 - выкл, 1 - вкл) export BYPASS_MODE=0 ### DNS-сервер для исключаемых записей (пустая строка - без DNS-сервера). Можно с портом: 8.8.8.8#53. Если в записи указан свой DNS-сервер - он имеет приоритет @@ -185,6 +192,8 @@ export BLLIST_ALT_DNS_ADDR="8.8.8.8" [ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE" CONFIG_SCRIPT="${SCRIPTS_DIR}/config_script" +export USER_INSTANCES_COMMON="${SCRIPTS_DIR}/user_instances_common" +export CONFIG_SCRIPT_USER_INSTANCES="${SCRIPTS_DIR}/config_script_user_instances" START_SCRIPT="${SCRIPTS_DIR}/start_script" STOP_SCRIPT="${SCRIPTS_DIR}/stop_script" BLLIST_SOURCES_SCRIPT="${SCRIPTS_DIR}/blacklist_sources" @@ -192,6 +201,10 @@ BLLIST_SOURCES_SCRIPT="${SCRIPTS_DIR}/blacklist_sources" ### Config script [ -f "$CONFIG_SCRIPT" ] && . "$CONFIG_SCRIPT" +export DNSMASQ_DATA_FILE_BYPASS="${DNSMASQ_CFG_DIR}/00-${NAME}_bypass.dnsmasq" +export DNSMASQ_DATA_FILE_USER_INSTANCES="${DNSMASQ_CFG_DIR}/01-${NAME}_user_instances.dnsmasq" +export DNSMASQ_DATA_FILE="${DNSMASQ_CFG_DIR}/02-${NAME}.dnsmasq" + ### Utilities AWK_CMD="awk" NFT_CMD=`which nft` @@ -223,6 +236,8 @@ if [ $? -ne 0 ]; then fi ROUTE_CHECK_EXEC="${MODULES_DIR}/ruab_route_check" export IP_DATA_FILE="${DATA_DIR}/${NAME}.ip" +export IP_DATA_FILE_BYPASS="${DATA_DIR}/${NAME}_bypass.ip" +export IP_DATA_FILE_USER_INSTANCES="${DATA_DIR}/${NAME}_user_instances.ip" export NFT_TABLE="ip r" export NFT_TABLE_DNSMASQ="4#ip#r" export NFTSET_ALLOWED_HOSTS="allowed_ip" @@ -235,6 +250,7 @@ export NFTSET_ONION="onion" export NFTSET_CIDR="c" export NFTSET_IP="i" export NFTSET_DNSMASQ="d" +export NFTSET_MARK_SET="mark_set" export NFTSET_ALLOWED_HOSTS_TYPE="ipv4_addr" export NFTSET_BYPASS_IP_TYPE="ipv4_addr" export NFTSET_BYPASS_FQDN_TYPE="ipv4_addr" @@ -244,28 +260,45 @@ export NFTSET_BLLIST_PROXY_TYPE="ipv4_addr" export NFTSET_CIDR_TYPE="ipv4_addr" export NFTSET_IP_TYPE="ipv4_addr" export NFTSET_DNSMASQ_TYPE="ipv4_addr" -export NFTSET_CIDR_CFG="set ${NFTSET_CIDR} {type ${NFTSET_CIDR_TYPE};size ${NFTSET_MAXELEM_CIDR};policy ${NFTSET_POLICY_CIDR};flags interval;auto-merge;" -export NFTSET_IP_CFG="set ${NFTSET_IP} {type ${NFTSET_IP_TYPE};size ${NFTSET_MAXELEM_IP};policy ${NFTSET_POLICY_IP};flags dynamic;" -export NFTSET_BYPASS_IP_CFG="set ${NFTSET_BYPASS_IP} {type ${NFTSET_BYPASS_IP_TYPE};size ${NFTSET_MAXELEM_BYPASS_IP};policy ${NFTSET_POLICY_CIDR};flags interval;auto-merge;" +export NFTSET_MARK_SET_TYPE="mark" +export NFTSET_CIDR_PATTERN="set %s {type ${NFTSET_CIDR_TYPE};size ${NFTSET_MAXELEM_CIDR};policy ${NFTSET_POLICY_CIDR};flags interval;auto-merge;" +export NFTSET_IP_PATTERN="set %s {type ${NFTSET_IP_TYPE};size ${NFTSET_MAXELEM_IP};policy ${NFTSET_POLICY_IP};flags dynamic;" +export NFTSET_CIDR_STRING_MAIN=`printf "$NFTSET_CIDR_PATTERN" "${NFTSET_CIDR}"` +export NFTSET_IP_STRING_MAIN=`printf "$NFTSET_IP_PATTERN" "${NFTSET_IP}"` +export NFTSET_BYPASS_IP_STRING="set ${NFTSET_BYPASS_IP} {type ${NFTSET_BYPASS_IP_TYPE};size ${NFTSET_MAXELEM_BYPASS_IP};policy ${NFTSET_POLICY_CIDR};flags interval;auto-merge;" export UPDATE_STATUS_FILE="${DATA_DIR}/update_status" export USER_ENTRIES_STATUS_FILE="${DATA_DIR}/user_entries_status" -U_PID_FILE="/var/run/${NAME}_update.pid" -START_PID_FILE="/var/run/${NAME}_start.pid" -TOKEN_FILE="/var/run/${NAME}.token" +U_PID_FILE="${RUN_FILES_DIR}/${NAME}_update.pid" +START_PID_FILE="${RUN_FILES_DIR}/${NAME}_start.pid" +TOKEN_FILE="${RUN_FILES_DIR}/${NAME}.token" export HTML_OUTPUT="${HTML_DIR}/${NAME}.html" NFT_FUNCTIONS="${SCRIPTS_DIR}/nft_functions" INFO_OUTPUT_FUNCTION="${SCRIPTS_DIR}/info_output" export IP_DATA_FILE_TMP="${IP_DATA_FILE}.tmp" +export IP_DATA_FILE_USER_INSTANCES_TMP="${IP_DATA_FILE_USER_INSTANCES}.tmp" +export DNSMASQ_DATA_FILE_TMP="${DNSMASQ_DATA_FILE}.tmp" +export DNSMASQ_DATA_FILE_USER_INSTANCES_TMP="${DNSMASQ_DATA_FILE_USER_INSTANCES}.tmp" export DNSMASQ_DATA_FILE_TMP="${DNSMASQ_DATA_FILE}.tmp" export UPDATE_STATUS_FILE_TMP="${UPDATE_STATUS_FILE}.tmp" export USER_ENTRIES_STATUS_FILE_TMP="${USER_ENTRIES_STATUS_FILE}.tmp" +export USER_INSTANCES_ALL="" +export USER_INSTANCES_ALL_FNAMES="" +export USER_INSTANCES_VPN="" +export USER_INSTANCES_VPN_FNAMES="" +export USER_INSTANCES_CFG="" +export USER_INSTANCES_CFG_FNAMES="" +INSTANCES_CACHE="${RUN_FILES_DIR}/${NAME}.instances" DL_IPSET_URL="" DL_DMASK_URL="" DL_STAT_URL="" +### for compatibility with v1.x parsers +export NFTSET_CIDR_CFG="$NFTSET_CIDR_STRING_MAIN" +export NFTSET_IP_CFG="$NFTSET_IP_STRING_MAIN" ######################### External functions ########################### . "$NFT_FUNCTIONS" +. "$USER_INSTANCES_COMMON" if [ -f "$INFO_OUTPUT_FUNCTION" ]; then . "$INFO_OUTPUT_FUNCTION" else @@ -276,7 +309,7 @@ fi Help() { cat << EOF - Usage: ${APP_NAME} start|force-start|stop|destroy|restart|reload|update|force-update|data-files|status|raw-status|html-info|help + Usage: ${APP_NAME} start|force-start|stop|destroy|restart|reload|update|force-update|blacklist-files|status|raw-status|html-info|help start : Start force-start : Removing the PID-file before running stop : Stop @@ -285,7 +318,7 @@ cat << EOF reload : Renew nftables configuration update : Update blacklist force-update : Force update blacklist - data-files : Create ${IP_DATA_FILE}, ${DNSMASQ_DATA_FILE}, ${DNSMASQ_DATA_FILE_BYPASS} (without network functions) + blacklist-files : Create ${IP_DATA_FILE}, ${DNSMASQ_DATA_FILE}, ${DNSMASQ_DATA_FILE_BYPASS} (without network functions) status : Status & some info raw-status : Return code: 0 - enabled, 1 - error, 2 - disabled, 3 - starting, 4 - updating html-info : Return the html-info output @@ -299,7 +332,7 @@ cat << EOF ${APP_NAME} reload ${APP_NAME} update ${APP_NAME} force-update - ${APP_NAME} data-files + ${APP_NAME} blacklist-files ${APP_NAME} status ${APP_NAME} raw-status ${APP_NAME} html-info @@ -307,12 +340,17 @@ EOF } MakeLogRecord() { - if [ $ENABLE_LOGGING = "1" ]; then + if [ "$ENABLE_LOGGING" = "1" ]; then $LOGGER_CMD $LOGGER_PARAMS -p "user.${1}" "$2" fi } Download() { + if [ $DEBUG -ge 1 ]; then + echo " ruantiblock.Download ${1} ${2}" >&2 + MakeLogRecord "debug" "ruantiblock.Download ${1} ${2}" + fi + $WGET_CMD $WGET_PARAMS "$1" "$2" if [ $? -ne 0 ]; then echo " Downloading failed! Connection error (${2})" >&2 @@ -377,16 +415,35 @@ FlushNftSets() { done } +FlushInstancesNftSets() { + local _arg="$1" _name + for _name in $USER_INSTANCES_ALL " " + do + if [ "$_name" = " " ]; then + _name="" + else + _name="-${_name}" + fi + case "$_arg" in + fqdn) + FlushNftSets "${NFTSET_DNSMASQ}${_name}" "${NFTSET_ONION}${_name}" + ;; + bllist) + FlushNftSets "${NFTSET_CIDR}${_name}" "${NFTSET_IP}${_name}" "${NFTSET_DNSMASQ}${_name}" + ;; + *) + FlushNftSets "${NFTSET_FPROXY}${_name}" "${NFTSET_BLLIST_PROXY}${_name}" "${NFTSET_CIDR}${_name}" "${NFTSET_IP}${_name}" "${NFTSET_DNSMASQ}${_name}" "${NFTSET_ONION}${_name}" + ;; + esac + done +} + FormatNftSetElemsList() { printf "$1" | $AWK_CMD '{gsub(/[ ]+/, ",", $0); printf $0;}' } -AddNftSets() { - local _allowed_hosts _bypass_ips _fproxy_hosts _fproxy_private - $NFT_CMD add set $NFT_TABLE "$NFTSET_CIDR" { type "$NFTSET_CIDR_TYPE"\; size $NFTSET_MAXELEM_CIDR\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; } - $NFT_CMD add set $NFT_TABLE "$NFTSET_IP" { type "$NFTSET_IP_TYPE"\; size $NFTSET_MAXELEM_IP\; policy "$NFTSET_POLICY_IP"\; flags dynamic\; } - $NFT_CMD add set $NFT_TABLE "$NFTSET_DNSMASQ" { type "$NFTSET_DNSMASQ_TYPE"\; size $NFTSET_MAXELEM_DNSMASQ\; policy "$NFTSET_POLICY_DNSMASQ"\; flags dynamic,timeout\; timeout "$NFTSET_DNSMASQ_TIMEOUT"\; } - $NFT_CMD add set $NFT_TABLE "$NFTSET_ONION" { type "$NFTSET_DNSMASQ_TYPE"\; size $NFTSET_MAXELEM_DNSMASQ\; policy "$NFTSET_POLICY_DNSMASQ"\; flags dynamic,timeout\; timeout "$NFTSET_DNSMASQ_TIMEOUT"\; } +AddBaseNftSets() { + local _allowed_hosts _fproxy_private $NFT_CMD add set $NFT_TABLE "$NFTSET_ALLOWED_HOSTS" { type "$NFTSET_ALLOWED_HOSTS_TYPE"\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; } _allowed_hosts=`FormatNftSetElemsList "$ALLOWED_HOSTS_LIST"` if [ -n "$_allowed_hosts" ]; then @@ -394,42 +451,103 @@ AddNftSets() { fi $NFT_CMD add set $NFT_TABLE "$NFTSET_BYPASS_IP" { type "$NFTSET_BYPASS_IP_TYPE"\; size $NFTSET_MAXELEM_BYPASS_IP\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; } $NFT_CMD add set $NFT_TABLE "$NFTSET_BYPASS_FQDN" { type "$NFTSET_BYPASS_FQDN_TYPE"\; size $NFTSET_MAXELEM_BYPASS_FQDN\; policy "$NFTSET_POLICY_DNSMASQ"\; flags dynamic,timeout\; timeout "$NFTSET_DNSMASQ_TIMEOUT"\; } - $NFT_CMD add set $NFT_TABLE "$NFTSET_FPROXY" { type "$NFTSET_FPROXY_TYPE"\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; } - _fproxy_hosts=`FormatNftSetElemsList "$FPROXY_LIST"` - if [ -n "$_fproxy_hosts" ]; then - $NFT_CMD add element $NFT_TABLE "$NFTSET_FPROXY" { "$_fproxy_hosts" } - fi $NFT_CMD add set $NFT_TABLE "$NFTSET_FPROXY_PRIVATE" { type "$NFTSET_FPROXY_PRIVATE_TYPE"\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; } _fproxy_private=`FormatNftSetElemsList "$FPROXY_PRIVATE_NETS"` if [ -n "$_fproxy_private" ]; then $NFT_CMD add element $NFT_TABLE "$NFTSET_FPROXY_PRIVATE" { "$_fproxy_private" } fi - $NFT_CMD add set $NFT_TABLE "$NFTSET_BLLIST_PROXY" { type "$NFTSET_BLLIST_PROXY_TYPE"\; policy "$NFTSET_POLICY_IP"\; flags dynamic\; } + $NFT_CMD add set $NFT_TABLE "$NFTSET_MARK_SET" { type "$NFTSET_MARK_SET_TYPE"\; } +} + +MakeInstanceNftSets() { + local _name="$1" _fproxy_list="$2" _fproxy_hosts + if [ "$_name" = " " ]; then + _name="" + else + _name="-${_name}" + fi + $NFT_CMD add set $NFT_TABLE "${NFTSET_CIDR}${_name}" { type "$NFTSET_CIDR_TYPE"\; size $NFTSET_MAXELEM_CIDR\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; } + $NFT_CMD add set $NFT_TABLE "${NFTSET_IP}${_name}" { type "$NFTSET_IP_TYPE"\; size $NFTSET_MAXELEM_IP\; policy "$NFTSET_POLICY_IP"\; flags dynamic\; } + $NFT_CMD add set $NFT_TABLE "${NFTSET_DNSMASQ}${_name}" { type "$NFTSET_DNSMASQ_TYPE"\; size $NFTSET_MAXELEM_DNSMASQ\; policy "$NFTSET_POLICY_DNSMASQ"\; flags dynamic,timeout\; timeout "$NFTSET_DNSMASQ_TIMEOUT"\; } + $NFT_CMD add set $NFT_TABLE "${NFTSET_ONION}${_name}" { type "$NFTSET_DNSMASQ_TYPE"\; size $NFTSET_MAXELEM_DNSMASQ\; policy "$NFTSET_POLICY_DNSMASQ"\; flags dynamic,timeout\; timeout "$NFTSET_DNSMASQ_TIMEOUT"\; } + $NFT_CMD add set $NFT_TABLE "${NFTSET_FPROXY}${_name}" { type "$NFTSET_FPROXY_TYPE"\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; } + _fproxy_hosts=`FormatNftSetElemsList "$_fproxy_list"` + if [ -n "$_fproxy_hosts" ]; then + $NFT_CMD add element $NFT_TABLE "${NFTSET_FPROXY}${_name}" { "$_fproxy_hosts" } + fi + $NFT_CMD add set $NFT_TABLE "${NFTSET_BLLIST_PROXY}${_name}" { type "$NFTSET_BLLIST_PROXY_TYPE"\; policy "$NFTSET_POLICY_IP"\; flags dynamic\; } +} + +AddInstancesNftSets() { + local _inst + for _inst in $USER_INSTANCES_ALL_FNAMES + do + IncludeUserInstanceVars "$_inst" + MakeInstanceNftSets "$U_NAME" "$U_FPROXY_LIST" + ClearUserInstanceVars + done + MakeInstanceNftSets " " "$FPROXY_LIST" } UpdateBllistProxySet() { - local _ip_string="" - FlushNftSets "$NFTSET_BLLIST_PROXY" - for host in $BLLIST_HOSTS + local _name="$1" _urls="$2" _host _ip_string="" + if [ "$_name" = " " ]; then + _name="" + else + _name="-${_name}" + fi + FlushNftSets "${NFTSET_BLLIST_PROXY}${_name}" + for _host in `echo "$_urls" | $AWK_CMD ' + BEGIN { + RS = " "; + } + { + gsub("\n", "", $0); + sub(/^https?:\/\//, "", $0); + sub(/\/.*$/, "", $0); + sub(/:[0-9]{2,5}$/, "", $0); + if($0 ~ /^([a-z0-9._-]+[.])+([a-z]{2,}|xn--[a-z0-9]+)$/ || $0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}$/) { + hosts_arr[$0]; + }; + } + END { + for(i in hosts_arr) { + printf i " "; + }; + }'` do - if printf "$host" | $AWK_CMD '{exit ($0 ~ /^([0-9]{1,3}.){3}[0-9]{1,3}$/) ? 0 : 1}'; then - _ip_string="${_ip_string}${host} " + if printf "$_host" | $AWK_CMD '{exit ($0 ~ /^([0-9]{1,3}.){3}[0-9]{1,3}$/) ? 0 : 1}'; then + _ip_string="${_ip_string}${_host} " else - _ip_string="${_ip_string}`$NSLOOKUP_CMD $host 2> /dev/null | $AWK_CMD '/^Address: ([0-9]{1,3}.){3}[0-9]{1,3}$/ {printf $2" "}'`" + _ip_string="${_ip_string}`$NSLOOKUP_CMD $_host 2> /dev/null | $AWK_CMD '/^Address: ([0-9]{1,3}.){3}[0-9]{1,3}$/ {printf $2" "}'`" fi done _ip_string=`FormatNftSetElemsList "$_ip_string"` + + if [ $DEBUG -ge 1 ]; then + echo " ruantiblock.UpdateBllistProxySet()._ip_string=${_ip_string=}; _name=${_name}" >&2 + MakeLogRecord "debug" "ruantiblock.UpdateBllistProxySet()._ip_string=${_ip_string=}; _name=${_name}" + fi + if [ -n "$_ip_string" ]; then - $NFT_CMD add element $NFT_TABLE "$NFTSET_BLLIST_PROXY" { "$_ip_string" } + $NFT_CMD add element $NFT_TABLE "${NFTSET_BLLIST_PROXY}${_name}" { "$_ip_string" } fi } UpdateBllistSets() { local _return_code=0 - if [ -f "$IP_DATA_FILE" ]; then + if [ -f "$IP_DATA_FILE" -a -f "$IP_DATA_FILE_USER_INSTANCES" -a -f "$IP_DATA_FILE_BYPASS" ]; then echo " Updating nft sets..." - $NFT_CMD -f "$IP_DATA_FILE" + $NFT_CMD -f "$IP_DATA_FILE_BYPASS" _return_code=$? + if [ $_return_code -eq 0 ]; then + $NFT_CMD -f "$IP_DATA_FILE_USER_INSTANCES" + _return_code=$? + if [ $_return_code -eq 0 ]; then + $NFT_CMD -f "$IP_DATA_FILE" + _return_code=$? + fi + fi if [ $_return_code -eq 0 ]; then echo " Ok" else @@ -440,23 +558,94 @@ UpdateBllistSets() { return $_return_code } +AddUserInstancesNftRules() { + local _prio_offset=0 _pkts_mark=$PKTS_MARK_START _chain_prio_first _chain_prio_local _inst _vpn_route_table_id=$VPN_ROUTE_TABLE_ID_START _tproxy_route_table_id=$TPROXY_ROUTE_TABLE_ID_START _route_table_id + for _inst in $USER_INSTANCES_ALL_FNAMES + do + IncludeUserInstanceVars "$_inst" + if [ "$U_PROXY_MODE" = "2" ]; then + _chain_prio_first=$(($NFT_PRIO_ROUTE + $USER_INSTANCES_MAX + $_prio_offset)) + _chain_prio_local=$(($NFT_PRIO_ROUTE_LOCAL + $USER_INSTANCES_MAX + $_prio_offset)) + _vpn_route_table_id=$(($_vpn_route_table_id + 1)) + _route_table_id=$_vpn_route_table_id + else + _chain_prio_first=$(($NFT_PRIO_NAT + $USER_INSTANCES_MAX + $_prio_offset)) + _chain_prio_local=$(($NFT_PRIO_NAT_LOCAL + $USER_INSTANCES_MAX + $_prio_offset)) + if [ "$U_PROXY_MODE" = "3" -a "$U_T_PROXY_TYPE" = "1" ]; then + _tproxy_route_table_id=$(($_tproxy_route_table_id + 1)) + fi + _route_table_id=$_tproxy_route_table_id + fi + _pkts_mark=$(($_pkts_mark + 1)) + NftInstanceAdd "\"$U_NAME\"" $_pkts_mark $_chain_prio_first $_chain_prio_local $U_PROXY_MODE $U_TOR_TRANS_PORT $_route_table_id "\"$U_IF_VPN\"" $U_T_PROXY_TYPE $U_T_PROXY_PORT_TCP $U_T_PROXY_PORT_UDP $U_T_PROXY_ALLOW_UDP $U_ENABLE_ENTRIES_REMOTE_PROXY $U_ENABLE_FPROXY $U_SKIP_MARKED_PACKETS "\"$U_VPN_GW_IP\"" + $NFT_CMD add element $NFT_TABLE "$NFTSET_MARK_SET" { $_pkts_mark } + ClearUserInstanceVars + _prio_offset=$(($_prio_offset - 1)) + done +} + +DeleteUserInstancesNftRules() { + local _inst _i=1 _j=1 + for _inst in $USER_INSTANCES_CFG_FNAMES + do + IncludeUserInstanceVars "$_inst" + NftInstanceDelete "$U_NAME" 2> /dev/null + if [ "$U_PROXY_MODE" = "2" ]; then + NftRouteDelete $(($VPN_ROUTE_TABLE_ID_START + $_i)) 2> /dev/null + _i=$(($_i + 1)) + elif [ "$U_PROXY_MODE" = "3" -a "$U_T_PROXY_TYPE" = "1" ]; then + NftRouteDelete $(($TPROXY_ROUTE_TABLE_ID_START + $_j)) 2> /dev/null + _j=$(($_j + 1)) + fi + ClearUserInstanceVars + done +} + AddNftRules() { - NftMainAdd + local _chain_prio_first _chain_prio_local _route_table_id + if [ "$PROXY_MODE" = "2" ]; then + _chain_prio_first=$NFT_PRIO_ROUTE + _chain_prio_local=$NFT_PRIO_ROUTE_LOCAL + _chain_prio_sink=$(($NFT_PRIO_ROUTE + $USER_INSTANCES_MAX + 1)) + _chain_prio_action=$(($NFT_PRIO_ROUTE + $USER_INSTANCES_MAX + 2)) + _route_table_id=$VPN_ROUTE_TABLE_ID_START + else + _chain_prio_first=$NFT_PRIO_NAT + _chain_prio_local=$NFT_PRIO_NAT_LOCAL + _chain_prio_sink=$(($NFT_PRIO_NAT + $USER_INSTANCES_MAX + 1)) + _chain_prio_action=$(($NFT_PRIO_NAT + $USER_INSTANCES_MAX + 2)) + _route_table_id=$TPROXY_ROUTE_TABLE_ID_START + fi + NftAddActionChains $_chain_prio_action + NftAddSinkChains $_chain_prio_sink + AddUserInstancesNftRules + NftInstanceAdd "\" \"" $PKTS_MARK_START $_chain_prio_first $_chain_prio_local $PROXY_MODE $TOR_TRANS_PORT $_route_table_id "\"$IF_VPN\"" $T_PROXY_TYPE $T_PROXY_PORT_TCP $T_PROXY_PORT_UDP $T_PROXY_ALLOW_UDP $ENABLE_BLLIST_PROXY $ENABLE_FPROXY $SKIP_MARKED_PACKETS "\"$VPN_GW_IP\"" + $NFT_CMD add element $NFT_TABLE "$NFTSET_MARK_SET" { $PKTS_MARK_START } } DeleteNftRules() { - NftMainDelete + NftInstanceDelete " " + DeleteUserInstancesNftRules + NftDeleteSinkChains + NftDeleteActionChains + if [ "$PROXY_MODE" = "2" ]; then + NftRouteDelete $VPN_ROUTE_TABLE_ID_START 2> /dev/null + elif [ "$PROXY_MODE" = "3" -a "$T_PROXY_TYPE" = "1" ]; then + NftRouteDelete $TPROXY_ROUTE_TABLE_ID_START 2> /dev/null + fi } SetNetConfig() { $NFT_CMD add table $NFT_TABLE - AddNftSets + AddBaseNftSets + AddInstancesNftSets AddNftRules } DropNetConfig() { DeleteNftRules - FlushNftSets "$NFTSET_ALLOWED_HOSTS" "$NFTSET_FPROXY" "$NFTSET_FPROXY_PRIVATE" "$NFTSET_BLLIST_PROXY" "$NFTSET_BYPASS_IP" "$NFTSET_BYPASS_FQDN" "$NFTSET_CIDR" "$NFTSET_IP" "$NFTSET_DNSMASQ" "$NFTSET_ONION" + FlushInstancesNftSets + FlushNftSets "$NFTSET_ALLOWED_HOSTS" "$NFTSET_FPROXY_PRIVATE" "$NFTSET_BLLIST_PROXY" "$NFTSET_BYPASS_IP" "$NFTSET_BYPASS_FQDN" "$NFTSET_MARK_SET" } DestroyNetConfig() { @@ -464,19 +653,62 @@ DestroyNetConfig() { $NFT_CMD delete table $NFT_TABLE &> /dev/null } -ClearDataFiles() { - if [ -d "$DATA_DIR" ]; then - printf "" > "$DNSMASQ_DATA_FILE" - printf "" > "$DNSMASQ_DATA_FILE_BYPASS" - printf "" > "$IP_DATA_FILE" - printf "0 0 0" > "$UPDATE_STATUS_FILE" - printf "" > "$USER_ENTRIES_STATUS_FILE" - fi +CheckStatus() { + NftReturnInstanceStatus " " + return $? } -CheckStatus() { - NftReturnStatus - return $? +GetVpnRouteStatus() { + local _inst _i=1 _ret_val=0 + for _inst in $USER_INSTANCES_VPN_FNAMES + + do + if ! NftRouteStatus $(($VPN_ROUTE_TABLE_ID_START + $_i)); then + _ret_val=1 + break + fi + _i=$(($_i + 1)) + done + if [ "$PROXY_MODE" = "2" ] && ! NftRouteStatus $VPN_ROUTE_TABLE_ID_START; then + _ret_val=1 + fi + return $_ret_val +} + +GetBllistChains() { + local _inst + for _inst in $USER_INSTANCES_ALL " " + do + NftListBllistChain "$_inst" + done +} + +GetBllistChainsJson() { + local _inst + for _inst in $USER_INSTANCES_ALL " " + do + NftListBllistChainJson "$_inst" + done +} + +ClearDataFiles() { + local _arg="$1" + if [ -d "$DATA_DIR" ]; then + if [ -z "$_arg" -o "$_arg" = "main_instance" ]; then + printf "" > "$IP_DATA_FILE" + printf "" > "$DNSMASQ_DATA_FILE" + printf "0 0 0" > "$UPDATE_STATUS_FILE" + fi + if [ -z "$_arg" -o "$_arg" = "user_instances" ]; then + printf "" > "$IP_DATA_FILE_USER_INSTANCES" + printf "" > "$DNSMASQ_DATA_FILE_USER_INSTANCES" + printf "" > "$USER_ENTRIES_STATUS_FILE" + fi + if [ -z "$_arg" ]; then + printf "" > "$IP_DATA_FILE_BYPASS" + printf "" > "$DNSMASQ_DATA_FILE_BYPASS" + fi + fi } PreStartCheck() { @@ -485,158 +717,15 @@ PreStartCheck() { ### Костыль для старта dnsmasq [ -e "$DNSMASQ_DATA_FILE" ] || printf "" > "$DNSMASQ_DATA_FILE" [ -e "$DNSMASQ_DATA_FILE_BYPASS" ] || printf "" > "$DNSMASQ_DATA_FILE_BYPASS" -} - -ParseUserEntries() { - $AWK_CMD -v IP_DATA_FILE="$1" -v DNSMASQ_DATA_FILE="$2" -v USER_ENTRIES_STATUS_FILE="$3" -v ID="$4" 'BEGIN { - null = ""; - ip_array[0] = null; - cidr_array[0] = null; - fqdn_array[0] = null; - } - function writeIpList(array, _str) { - _str = ""; - for(i in array) { - _str = _str i ","; - }; - return _str; - }; - function writeDNSData(val, dns) { - if(length(dns) == 0 && length(ENVIRON["USER_ENTRIES_DNS"]) > 0) { - dns = ENVIRON["USER_ENTRIES_DNS"]; - }; - if(length(dns) > 0) { - printf "server=/%s/%s\n", val, dns >> DNSMASQ_DATA_FILE; - }; - printf "nftset=/%s/%s#%s\n", val, ENVIRON["NFT_TABLE_DNSMASQ"], ENVIRON["NFTSET_DNSMASQ"] >> DNSMASQ_DATA_FILE; - }; - function writeFqdnEntries() { - delete fqdn_array[0]; - for(i in fqdn_array) { - split(fqdn_array[i], a, " "); - writeDNSData(a[1], a[2]); - }; - }; - ($0 !~ /^([\040\011]*$|#)/) { - if($0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}$/) { - ip_array[$0] = null; - } - else if($0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}[\057][0-9]{1,2}$/) { - cidr_array[$0] = null; - } - else if($0 ~ /^[a-z0-9.\052-]+[.]([a-z]{2,}|xn--[a-z0-9]+)([ ][0-9]{1,3}([.][0-9]{1,3}){3}([#][0-9]{2,5})?)?$/) { - fqdn_array[length(fqdn_array)] = $1 " " $2; - }; - } - END { - ret_code = 0; - if($0 ~ /[0-9]+/) { - ret_code = $0; - }; - delete cidr_array[0]; - delete ip_array[0]; - if(ret_code == 0 && (length(cidr_array) > 0 || length(ip_array) > 0)) { - printf "table %s {\n%s", ENVIRON["NFT_TABLE"], ENVIRON["NFTSET_CIDR_CFG"] >> IP_DATA_FILE; - if(length(cidr_array) > 0) { - printf "elements={%s};", writeIpList(cidr_array) >> IP_DATA_FILE; - }; - printf "}\n%s", ENVIRON["NFTSET_IP_CFG"] >> IP_DATA_FILE; - - if(length(ip_array) > 0) { - printf "elements={%s};", writeIpList(ip_array) >> IP_DATA_FILE; - }; - printf "}\n}\n" >> IP_DATA_FILE; - }; - writeFqdnEntries(); - if(ret_code == 0) { - printf "%s %s %s %s\n", length(cidr_array), length(ip_array), length(fqdn_array), ID >> USER_ENTRIES_STATUS_FILE; - }; - exit ret_code; - }' - -} - -AddUserEntries() { - local _url _return_code=0 _attempt=1 _ip_data_file _dnsmasq_data_file _user_entries_status_file _str _update_string - if [ "$ADD_USER_ENTRIES" = "1" ]; then - if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then - _ip_data_file="$IP_DATA_FILE_TMP" - _dnsmasq_data_file="$DNSMASQ_DATA_FILE_TMP" - _user_entries_status_file="$USER_ENTRIES_STATUS_FILE_TMP" - rm -f "$_ip_data_file" "$_dnsmasq_data_file" "$_user_entries_status_file" - else - _ip_data_file="$IP_DATA_FILE" - _dnsmasq_data_file="$DNSMASQ_DATA_FILE" - _user_entries_status_file="$USER_ENTRIES_STATUS_FILE" - fi - if [ "$1" = "flush" ]; then - if [ "$ENABLE_TMP_DOWNLOADS" != "1" ]; then - ClearDataFiles - fi - printf "flush set %s %s\nflush set %s %s\n" "$NFT_TABLE" "$NFTSET_CIDR" "$NFT_TABLE" "$NFTSET_IP" >> "$_ip_data_file" - else - printf "" > "$USER_ENTRIES_STATUS_FILE" - fi - if [ -f "$USER_ENTRIES_FILE" ]; then - { cat "$USER_ENTRIES_FILE"; echo 0; } | ParseUserEntries "$_ip_data_file" "$_dnsmasq_data_file" "$_user_entries_status_file" "local" - fi - if [ -n "$USER_ENTRIES_REMOTE" ]; then - for _url in $USER_ENTRIES_REMOTE - do - _attempt=1 - while : - do - if [ "$ENABLE_BLLIST_PROXY" = "1" ]; then - UpdateBllistProxySet - fi - { Download - "$_url"; echo $?; } | ParseUserEntries "$_ip_data_file" "$_dnsmasq_data_file" "$_user_entries_status_file" "$_url" - if [ $? -eq 0 ]; then - break - else - _return_code=1 - ### STDOUT - echo " User entries download attempt ${_attempt}: failed [${_url}]" >&2 - MakeLogRecord "err" "User entries download attempt ${_attempt}: failed [${_url}]" - _attempt=$(($_attempt + 1)) - [ $_attempt -gt $USER_ENTRIES_REMOTE_DOWNLOAD_ATTEMPTS ] && break - sleep $USER_ENTRIES_REMOTE_DOWNLOAD_TIMEOUT - fi - done - done - if [ "$ENABLE_BLLIST_PROXY" = "1" ]; then - FlushNftSets "$NFTSET_BLLIST_PROXY" - fi - fi - if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then - if [ $_return_code -eq 0 ]; then - if [ "$1" = "flush" ]; then - ClearDataFiles - fi - cat "$_ip_data_file" >> "$IP_DATA_FILE" - cat "$_dnsmasq_data_file" >> "$DNSMASQ_DATA_FILE" - mv -f "$_user_entries_status_file" "$USER_ENTRIES_STATUS_FILE" - fi - rm -f "$_ip_data_file" "$_dnsmasq_data_file" "$_user_entries_status_file" - fi - while read _str - do - _update_string=`printf "$_str" | $AWK_CMD '{ - if(NF == 4) { - printf "User entries (%s): CIDR: %s, IP: %s, FQDN: %s", $4, $1, $2, $3; - }; - }'` - if [ -n "$_update_string" ]; then - ### STDOUT - echo " ${_update_string}" - MakeLogRecord "notice" "${_update_string}" - fi - done < "$USER_ENTRIES_STATUS_FILE" - else - printf "" > "$USER_ENTRIES_STATUS_FILE" - fi + [ -e "$DNSMASQ_DATA_FILE_USER_INSTANCES" ] || printf "" > "$DNSMASQ_DATA_FILE_USER_INSTANCES" } AddBypassEntries() { - [ -d "$DATA_DIR" ] && printf "" > "$DNSMASQ_DATA_FILE_BYPASS" + if [ -d "$DATA_DIR" ]; then + printf "" > "$DNSMASQ_DATA_FILE_BYPASS" + printf "" > "$IP_DATA_FILE_BYPASS" + printf "flush set %s %s\nflush set %s %s\n" "$NFT_TABLE" "$NFTSET_BYPASS_IP" "$NFT_TABLE" "$NFTSET_BYPASS_FQDN" >> "$IP_DATA_FILE_BYPASS" + fi FlushNftSets "$NFTSET_BYPASS_IP" "$NFTSET_BYPASS_FQDN" if [ "$BYPASS_MODE" = "1" ]; then if [ -f "$BYPASS_ENTRIES_FILE" ]; then @@ -669,26 +758,209 @@ AddBypassEntries() { }; }; ($0 !~ /^([\040\011]*$|#)/) { + sub("\015", "", $0); if($0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}([\057][0-9]{1,2})?$/) { ip_array[$0] = null; } - else if($0 ~ /^[a-z0-9.\052-]+[.]([a-z]{2,}|xn--[a-z0-9]+)([ ][0-9]{1,3}([.][0-9]{1,3}){3}([#][0-9]{2,5})?)?$/) { + else if($0 ~ /^([a-z0-9._-]+[.])*([a-z]{2,}|xn--[a-z0-9]+)([ ][0-9]{1,3}([.][0-9]{1,3}){3}([#][0-9]{2,5})?)?$/) { fqdn_array[length(fqdn_array)] = $1 " " $2; }; } END { - printf "table %s {\n%s", ENVIRON["NFT_TABLE"], ENVIRON["NFTSET_BYPASS_IP_CFG"] >> ENVIRON["IP_DATA_FILE"]; + printf "table %s {\n%s", ENVIRON["NFT_TABLE"], ENVIRON["NFTSET_BYPASS_IP_STRING"] >> ENVIRON["IP_DATA_FILE_BYPASS"]; delete ip_array[0]; if(length(ip_array) > 0) { - printf "elements={%s};", writeIpList(ip_array) >> ENVIRON["IP_DATA_FILE"]; + printf "elements={%s};", writeIpList(ip_array) >> ENVIRON["IP_DATA_FILE_BYPASS"]; }; - printf "}\n}\n" >> ENVIRON["IP_DATA_FILE"]; + printf "}\n}\n" >> ENVIRON["IP_DATA_FILE_BYPASS"]; writeFqdnEntries(); }' "$BYPASS_ENTRIES_FILE" fi fi } +ParseUserEntries() { + $AWK_CMD -v NFTSET_IP_STRING="$1" -v NFTSET_CIDR_STRING="$2" -v NFTSET_DNSMASQ="$3" \ + -v IP_DATA_FILE="$4" -v DNSMASQ_DATA_FILE="$5" -v USER_ENTRIES_STATUS_FILE="$6" \ + -v ID="$7" -v USER_ENTRIES_DNS="$8" ' + BEGIN { + null = ""; + ip_array[0] = null; + cidr_array[0] = null; + fqdn_array[0] = null; + } + function writeIpList(array, _str) { + _str = ""; + for(i in array) { + _str = _str i ","; + }; + return _str; + }; + function writeDNSData(val, dns) { + if(length(dns) == 0 && length(USER_ENTRIES_DNS) > 0) { + dns = USER_ENTRIES_DNS; + }; + if(length(dns) > 0) { + printf "server=/%s/%s\n", val, dns >> DNSMASQ_DATA_FILE; + }; + printf "nftset=/%s/%s#%s\n", val, ENVIRON["NFT_TABLE_DNSMASQ"], NFTSET_DNSMASQ >> DNSMASQ_DATA_FILE; + }; + function writeFqdnEntries() { + delete fqdn_array[0]; + for(i in fqdn_array) { + split(fqdn_array[i], a, " "); + writeDNSData(a[1], a[2]); + }; + }; + ($0 !~ /^([\040\011]*$|#)/) { + sub("\015", "", $0); + if($0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}$/) { + ip_array[$0] = null; + } + else if($0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}[\057][0-9]{1,2}$/) { + cidr_array[$0] = null; + } + else if($0 ~ /^([a-z0-9._-]+[.])*([a-z]{2,}|xn--[a-z0-9]+)([ ][0-9]{1,3}([.][0-9]{1,3}){3}([#][0-9]{2,5})?)?$/) { + fqdn_array[length(fqdn_array)] = $1 " " $2; + }; + } + END { + ret_code = 0; + if($0 ~ /[0-9]+/) { + ret_code = $0; + }; + delete cidr_array[0]; + delete ip_array[0]; + if(ret_code == 0 && (length(cidr_array) > 0 || length(ip_array) > 0)) { + printf "table %s {\n%s", ENVIRON["NFT_TABLE"], NFTSET_CIDR_STRING >> IP_DATA_FILE; + if(length(cidr_array) > 0) { + printf "elements={%s};", writeIpList(cidr_array) >> IP_DATA_FILE; + }; + printf "}\n%s", NFTSET_IP_STRING >> IP_DATA_FILE; + + if(length(ip_array) > 0) { + printf "elements={%s};", writeIpList(ip_array) >> IP_DATA_FILE; + }; + printf "}\n}\n" >> IP_DATA_FILE; + }; + writeFqdnEntries(); + if(ret_code == 0) { + printf "%s %s %s %s\n", length(cidr_array), length(ip_array), length(fqdn_array), ID >> USER_ENTRIES_STATUS_FILE; + }; + exit ret_code; + }' - +} + +AddUserEntries() { + local _inst _url _return_code=0 _instance_return_code=0 _attempt=1 _instance_entries_file _ip_data_file_user_instances _dnsmasq_data_file_user_instances _user_entries_status_file _str _update_string + + if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then + _ip_data_file_user_instances="$IP_DATA_FILE_USER_INSTANCES_TMP" + _dnsmasq_data_file="$DNSMASQ_DATA_FILE_TMP" + _dnsmasq_data_file_user_instances="$DNSMASQ_DATA_FILE_USER_INSTANCES_TMP" + _user_entries_status_file="$USER_ENTRIES_STATUS_FILE_TMP" + rm -f "$_ip_data_file_user_instances" "$_dnsmasq_data_file_user_instances" "$_user_entries_status_file" + else + _ip_data_file_user_instances="$IP_DATA_FILE_USER_INSTANCES" + _dnsmasq_data_file_user_instances="$DNSMASQ_DATA_FILE_USER_INSTANCES" + _user_entries_status_file="$USER_ENTRIES_STATUS_FILE" + fi + + if [ "$ENABLE_TMP_DOWNLOADS" != "1" ]; then + ClearDataFiles user_instances + fi + + for _inst in $USER_INSTANCES_ALL + do + IncludeUserInstanceVars "$_inst" + _instance_entries_file="${USER_LISTS_DIR}/${_inst}" + + if [ $DEBUG -ge 1 ]; then + echo " ruantiblock.AddUserEntries._instance_entries_file=${_instance_entries_file}" >&2 + MakeLogRecord "debug" "ruantiblock.AddUserEntries._instance_entries_file=${_instance_entries_file}" + fi + + printf "flush set %s %s\nflush set %s %s\n" "$NFT_TABLE" "${NFTSET_CIDR}-${_inst}" "$NFT_TABLE" "${NFTSET_IP}-${_inst}" >> "$_ip_data_file_user_instances" + + if [ "$U_PROXY_MODE" != "2" -a "$U_PROXY_MODE" != "3" ]; then + ### Запись для .onion + printf "server=/onion/%s\nnftset=/onion/%s#%s\n" "$U_ONION_DNS_ADDR" "$NFT_TABLE_DNSMASQ" "${NFTSET_ONION}-${_inst}" >> "$_dnsmasq_data_file_user_instances" + fi + if [ -f "$_instance_entries_file" ]; then + { cat "$_instance_entries_file"; printf "\n0\n"; } | ParseUserEntries "`printf "$NFTSET_IP_PATTERN" "${NFTSET_IP}-${_inst}"`" "`printf "$NFTSET_CIDR_PATTERN" "${NFTSET_CIDR}-${_inst}"`" "${NFTSET_DNSMASQ}-${_inst}" "$_ip_data_file_user_instances" "$_dnsmasq_data_file_user_instances" "$_user_entries_status_file" "${_inst}:local" "$U_ENTRIES_DNS" + fi + if [ -n "$U_ENTRIES_REMOTE" ]; then + for _url in $U_ENTRIES_REMOTE + do + _instance_return_code=0 + _attempt=1 + while : + do + if [ "$U_ENABLE_ENTRIES_REMOTE_PROXY" = "1" ]; then + UpdateBllistProxySet "$_inst" "$_url" + fi + { Download - "$_url"; printf "\n$?\n"; } | ParseUserEntries "`printf "$NFTSET_IP_PATTERN" "${NFTSET_IP}-${_inst}"`" "`printf "$NFTSET_CIDR_PATTERN" "${NFTSET_CIDR}-${_inst}"`" "${NFTSET_DNSMASQ}-${_inst}" "$_ip_data_file_user_instances" "$_dnsmasq_data_file_user_instances" "$_user_entries_status_file" "${_inst}:${_url}" "$U_ENTRIES_DNS" + if [ $? -eq 0 ]; then + _instance_return_code=0 + break + else + _instance_return_code=1 + ### STDOUT + echo " User entries download attempt ${_attempt}: failed [${_inst}:${_url}]" >&2 + MakeLogRecord "err" "User entries download attempt ${_attempt}: failed [${_inst}:${_url}]" + _attempt=$(($_attempt + 1)) + [ $_attempt -gt $USER_ENTRIES_REMOTE_DOWNLOAD_ATTEMPTS ] && break + sleep $USER_ENTRIES_REMOTE_DOWNLOAD_TIMEOUT + fi + done + if [ $_instance_return_code -ne 0 ]; then + _return_code=$_instance_return_code + if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then + break 2 + fi + fi + done + if [ "$U_ENABLE_ENTRIES_REMOTE_PROXY" = "1" ]; then + FlushNftSets "${NFTSET_BLLIST_PROXY}-${_inst}" + fi + fi + ClearUserInstanceVars + done + + if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then + if [ $_return_code -eq 0 ]; then + ClearDataFiles user_instances + if [ -e "$_ip_data_file_user_instances" ]; then + cat "$_ip_data_file_user_instances" >> "$IP_DATA_FILE_USER_INSTANCES" + fi + if [ -e "$_dnsmasq_data_file_user_instances" ]; then + cat "$_dnsmasq_data_file_user_instances" >> "$DNSMASQ_DATA_FILE_USER_INSTANCES" + fi + if [ -e "$_user_entries_status_file" ]; then + mv -f "$_user_entries_status_file" "$USER_ENTRIES_STATUS_FILE" + fi + fi + rm -f "$_ip_data_file_user_instances" "$_dnsmasq_data_file_user_instances" "$_user_entries_status_file" + fi + if [ "$ENABLE_TMP_DOWNLOADS" != "1" ] || [ "$ENABLE_TMP_DOWNLOADS" = "1" -a $_return_code -eq 0 ]; then + while read _str + do + _update_string=`printf "$_str" | $AWK_CMD '{ + if(NF == 4) { + printf "User entries (%s): CIDR: %s, IP: %s, FQDN: %s", $4, $1, $2, $3; + }; + }'` + if [ -n "$_update_string" ]; then + ### STDOUT + echo " ${_update_string}" + MakeLogRecord "notice" "${_update_string}" + fi + done < "$USER_ENTRIES_STATUS_FILE" + fi + + return $_return_code +} + ToggleUPIDFile() { if [ "$1" = "del" ]; then rm -f "$U_PID_FILE" @@ -697,14 +969,14 @@ ToggleUPIDFile() { fi } -GetDataFiles() { +GetMainInstanceEntries() { local _return_code=1 _attempt=1 _update_string PreStartCheck if [ -n "$BLLIST_PRESET" -a -n "$BLLIST_MODULE" ]; then while : do if [ "$ENABLE_BLLIST_PROXY" = "1" ]; then - UpdateBllistProxySet + UpdateBllistProxySet " " "$BLLIST_HOSTS" fi $BLLIST_MODULE _return_code=$? @@ -728,14 +1000,10 @@ GetDataFiles() { echo " ${_update_string}" MakeLogRecord "notice" "${_update_string}" printf " `date +%d.%m.%Y-%H:%M`\n" >> "$UPDATE_STATUS_FILE" - AddUserEntries - AddBypassEntries fi elif [ -z "$BLLIST_PRESET" -a -z "$BLLIST_MODULE" ]; then - ADD_USER_ENTRIES=1 - AddUserEntries flush - AddBypassEntries - _return_code=0 + ClearDataFiles main_instance + _return_code=3 else _return_code=2 return $_return_code @@ -751,48 +1019,87 @@ GetDataFiles() { return $_return_code } +GetBlacklistFiles() { + local _return_code=1 _user_entries_ret_code=1 + AddBypassEntries + GetMainInstanceEntries + case $? in + 0) + echo " Blacklist updated" + MakeLogRecord "notice" "Blacklist updated" + ;; + 2) + echo " Error! Blacklist update error" >&2 + MakeLogRecord "err" "Error! Blacklist update error" + _return_code=1 + ;; + 3) + : + ;; + *) + echo " Module error! [${BLLIST_MODULE}]" >&2 + MakeLogRecord "err" "Module error! [${BLLIST_MODULE}]" + _return_code=1 + ;; + esac + AddUserEntries + _user_entries_ret_code=$? + if [ $_return_code -eq 0 ]; then + _return_code=$_user_entries_ret_code + fi + return $_return_code +} + +MakeInstancesCache() { + printf "USER_INSTANCES_ALL=\"${USER_INSTANCES_ALL}\"\nUSER_INSTANCES_ALL_FNAMES=\"${USER_INSTANCES_ALL_FNAMES}\"\nUSER_INSTANCES_VPN=\"${USER_INSTANCES_VPN}\"\nUSER_INSTANCES_VPN_FNAMES=\"${USER_INSTANCES_VPN_FNAMES}\"\nUSER_INSTANCES_CFG=\"${USER_INSTANCES_CFG}\"\nUSER_INSTANCES_CFG_FNAMES=\"${USER_INSTANCES_CFG_FNAMES}\"\n" > "$INSTANCES_CACHE" +} + +DeleteInstancesCache() { + rm -f "$INSTANCES_CACHE" +} + +Init() { + local _arg="$1" + . "$BLLIST_SOURCES_SCRIPT" + if [ -e "$INSTANCES_CACHE" ]; then + . "$INSTANCES_CACHE" + + if [ $DEBUG -ge 2 ]; then + echo " ruantiblock.Init(): read from INSTANCES_CACHE" >&2 + MakeLogRecord "debug" "ruantiblock.Init(): read from INSTANCES_CACHE" + fi + + else + SetUserInstancesItems + fi +} + MakeToken() { date +%s > "$TOKEN_FILE" } Update() { - local _return_code=0 + local _arg="$1" _return_code=0 if CheckStatus; then : else - echo " ${NAME} ${1} - Error! ${NAME} does not running or another error has occurred" >&2 + echo " ${NAME} ${_arg} - Error! ${NAME} does not running or another error has occurred" >&2 return 1 fi MakeToken - if [ -e "$U_PID_FILE" ] && [ "$1" != "force-update" ]; then - echo " ${NAME} ${1} - Error! Another instance of update is already running" >&2 - MakeLogRecord "err" "${1} - Error! Another instance of update is already running" + if [ -e "$U_PID_FILE" ] && [ "$_arg" != "force-update" ]; then + echo " ${NAME} ${_arg} - Error! Another instance of update is already running" >&2 + MakeLogRecord "err" "${_arg} - Error! Another instance of update is already running" _return_code=2 else ToggleUPIDFile add - echo " ${NAME} ${1}..." - MakeLogRecord "notice" "${1}..." + echo " ${NAME} ${_arg}..." + MakeLogRecord "notice" "${_arg}..." if [ "$NFTSET_CLEAR_SETS" = "1" ]; then - FlushNftSets "$NFTSET_CIDR" "$NFTSET_IP" "$NFTSET_DNSMASQ" + FlushInstancesNftSets bllist fi - GetDataFiles - case $? in - 0) - echo " Blacklist updated" - MakeLogRecord "notice" "Blacklist updated" - ;; - 2) - echo " Error! Blacklist update error" >&2 - MakeLogRecord "err" "Error! Blacklist update error" - _return_code=1 - ;; - *) - echo " Module error! [${BLLIST_MODULE}]" >&2 - MakeLogRecord "err" "Module error! [${BLLIST_MODULE}]" - _return_code=1 - ;; - esac - FlushNftSets "$NFTSET_DNSMASQ" "$NFTSET_ONION" + GetBlacklistFiles + FlushInstancesNftSets fqdn UpdateBllistSets _return_code=$? RestartDnsmasq @@ -803,7 +1110,7 @@ Update() { } Start() { - local _return_code=1 + local _arg="$1" _return_code=1 if [ -e "$START_PID_FILE" ]; then echo " ${NAME} is currently starting..." >&2 return 1 @@ -811,20 +1118,22 @@ Start() { echo "$$" > "$START_PID_FILE" fi MakeToken + Init if CheckStatus; then echo " ${NAME} is already running" >&2 _return_code=1 else - echo " ${NAME} ${1}..." - MakeLogRecord "info" "${1}..." + echo " ${NAME} ${_arg}..." + MakeLogRecord "info" "${_arg}..." DropNetConfig &> /dev/null SetNetConfig PreStartCheck UpdateBllistSets _return_code=$? - if [ "$PROXY_MODE" = "2" -a "$VPN_ROUTE_CHECK" = "1" -a -x "$ROUTE_CHECK_EXEC" ]; then + if [ "$VPN_ROUTE_CHECK" = "1" -a -x "$ROUTE_CHECK_EXEC" ] && [ "$PROXY_MODE" = "2" -o -n "$USER_INSTANCES_VPN" ]; then $ROUTE_CHECK_EXEC start &> /dev/null & fi + MakeInstancesCache ### Start-script [ -x "$START_SCRIPT" ] && $START_SCRIPT > /dev/null 2>&1 & fi @@ -834,11 +1143,11 @@ Start() { } Stop() { - local _return_code=1 + local _arg="$1" _return_code=1 if CheckStatus; then MakeToken - echo " ${NAME} ${1}..." - MakeLogRecord "info" "${1}..." + echo " ${NAME} ${_arg}..." + MakeLogRecord "info" "${_arg}..." DropNetConfig &> /dev/null _return_code=$? if [ -x "$ROUTE_CHECK_EXEC" ]; then @@ -850,6 +1159,7 @@ Stop() { else echo " ${NAME} does not running" >&2 fi + DeleteInstancesCache return $_return_code } @@ -862,8 +1172,20 @@ Reload() { return 1 fi _i=$(($_i + 1)) + + if [ $DEBUG -ge 1 ]; then + echo " ruantiblock.Reload._i=${_i}" >&2 + MakeLogRecord "debug" "ruantiblock.Reload._i ${_i}" + fi + sleep 1 done + + if [ $DEBUG -ge 1 ]; then + echo " ruantiblock.Reload()" >&2 + MakeLogRecord "debug" "ruantiblock.Reload()" + fi + echo " ${NAME} reload..." DeleteNftRules &> /dev/null AddNftRules &> /dev/null @@ -871,7 +1193,7 @@ Reload() { } Status() { - local _update_status _user_entries_status _vpn_error + local _inst _update_status _user_entries_status _vpn_error if [ -f "$UPDATE_STATUS_FILE" ]; then _update_status=`$AWK_CMD '{ update_string=(NF < 4) ? "No data" : $4" (CIDR: "$1" | IP: "$2" | FQDN: "$3")"; @@ -889,30 +1211,32 @@ Status() { }' "$USER_ENTRIES_STATUS_FILE"` fi - if [ "$PROXY_MODE" = "2" ] && ! NftVpnRouteStatus; then + if ! GetVpnRouteStatus; then _vpn_error="\033[1;31mVPN ROUTING ERROR! (NEED THE RESTART)\033[m" fi - NftListBllistChain 2> /dev/null | $AWK_CMD -v UPDATE_STATUS="$_update_status" -v USER_ENTRIES_STATUS="$_user_entries_status" -v VPN_ERROR="$_vpn_error" ' + NftListSinkChain 2> /dev/null | $AWK_CMD -v UPDATE_STATUS="$_update_status" -v USER_ENTRIES_STATUS="$_user_entries_status" -v VPN_ERROR="$_vpn_error" ' BEGIN { - rules_str = ""; - nftset = ""; - bytes = ""; + rules_str = ""; } - /@/ { - if(match($0, /@[^ ]+/) != 0) { - nftset = substr($0, RSTART+1, RLENGTH-1); - if(match($0, /bytes [^ ]+/) != 0) { - bytes = substr($0, RSTART+6, RLENGTH-6); - }; - rules_str = rules_str " Match-set: " nftset "\n Bytes: " bytes "\n\n"; + { + if($0 ~ /(table|chain|type|return|\{|\})/) { + next; }; + instance = $NF; + if(instance == "\"") { + instance = "-main-"; + }; + gsub("\"", "", instance); + proto = ($3 ~ /(tcp|udp)/) ? $3 : "all"; + bytes = (match($0, /bytes [^ ]+/) != 0) ? substr($0, RSTART+6, RLENGTH-6) : ""; + rules_str = rules_str " Instance:\t" instance "\n Protocol:\t" proto "\n Bytes:\t" bytes "\n\n"; } END { if(NR == 0) { printf "\n \033[1m" ENVIRON["NAME"] " status\033[m: \033[1mDisabled\033[m\n\n"; exit 2; }; - printf "\n \033[1m" ENVIRON["NAME"] " status\033[m: \033[1;32mEnabled\033[m\n\n PROXY_MODE: " ENVIRON["PROXY_MODE"] "\n PROXY_LOCAL_CLIENTS: " ENVIRON["PROXY_LOCAL_CLIENTS"] "\n BLLIST_PRESET: " ENVIRON["BLLIST_PRESET"] "\n BLLIST_MODULE: " ENVIRON["BLLIST_MODULE"] "\n"; + printf "\n \033[1m" ENVIRON["NAME"] " status\033[m: \033[1;32mEnabled\033[m\n\n DNSMASQ_CFG_DIR: " ENVIRON["DNSMASQ_CFG_DIR"] "\n\n PROXY_LOCAL_CLIENTS: " ENVIRON["PROXY_LOCAL_CLIENTS"] "\n\n Main Instance: \n PROXY_MODE: " ENVIRON["PROXY_MODE"] "\n BLLIST_PRESET: " ENVIRON["BLLIST_PRESET"] "\n BLLIST_MODULE: " ENVIRON["BLLIST_MODULE"] "\n"; printf "\n "UPDATE_STATUS"\n"; if(length(USER_ENTRIES_STATUS) > 0) { printf "\n"USER_ENTRIES_STATUS"\n"; @@ -920,9 +1244,37 @@ Status() { if(length(VPN_ERROR) > 0) { printf "\n "VPN_ERROR"\n"; }; - printf "\n \033[4mNftables rules\033[m:\n\n"; + printf "\n Transit traffic:\n\n"; printf rules_str; }' + if [ $? -eq 0 -a "$PROXY_LOCAL_CLIENTS" = "1" ]; then + NftListSinkLocalChain 2> /dev/null | $AWK_CMD -v UPDATE_STATUS="$_update_status" -v USER_ENTRIES_STATUS="$_user_entries_status" ' + BEGIN { + rules_str = ""; + } + { + if($0 ~ /(table|chain|type|return|\{|\})/) { + next; + }; + instance = $NF; + if(instance == "\"") { + instance = "-main-"; + }; + gsub("\"", "", instance); + proto = ($3 ~ /(tcp|udp)/) ? $3 : "all"; + bytes = (match($0, /bytes [^ ]+/) != 0) ? substr($0, RSTART+6, RLENGTH-6) : ""; + rules_str = rules_str " Instance:\t" instance "\n Protocol:\t" proto "\n Bytes:\t" bytes "\n\n"; + } + END { + if(NR == 0) { + exit 2; + }; + printf " Local traffic:\n\n"; + printf rules_str; + }' + else + return 2 + fi } StatusOutput() { @@ -933,9 +1285,6 @@ StatusOutput() { ############################ Main section ############################## -### Blacklist sources -. "$BLLIST_SOURCES_SCRIPT" - return_code=1 case "$1" in start|force-start) @@ -945,22 +1294,41 @@ case "$1" in StatusOutput ;; stop) + Init Stop "$1" return_code=$? StatusOutput ;; - restart) - Stop "stop" - Start "start" - return_code=$? - StatusOutput + restart|delayed-restart) + if [ "$1" == "delayed-restart" -a -n "$2" ]; then + { + echo "$$" > "$START_PID_FILE" + sleep $2 &> /dev/null + rm -f "$START_PID_FILE" + Init + Stop "stop" + Start "start" + return_code=$? + StatusOutput + exit $return_code; + } &> /dev/null & + return_code=0 + else + Init + Stop "stop" + Start "start" + return_code=$? + StatusOutput + fi ;; reload) + Init Reload return_code=$? StatusOutput ;; destroy) + Init Stop "$1" &> /dev/null DestroyNetConfig ClearDataFiles @@ -970,24 +1338,28 @@ case "$1" in StatusOutput ;; update|force-update) + Init Update "$1" return_code=$? StatusOutput ;; - data-files) + blacklist-files) + Init if [ -e "$U_PID_FILE" ] && [ "$1" != "force-update" ]; then echo " ${NAME} - Error! Another instance of update is already running" >&2 exit 2 else - GetDataFiles + GetBlacklistFiles return_code=$? fi ;; status) + Init Status return_code=$? ;; raw-status) + Init CheckStatus return_code=$? case $return_code in @@ -1009,11 +1381,13 @@ case "$1" in esac ;; vpn-route-status) - NftVpnRouteStatus + Init + GetVpnRouteStatus return_code=$? echo $return_code ;; html-info) + Init Info return_code=$? ;; diff --git a/ruantiblock/files/usr/libexec/ruantiblock/ruab_route_check b/ruantiblock/files/usr/libexec/ruantiblock/ruab_route_check index 4920a26..76ae813 100755 --- a/ruantiblock/files/usr/libexec/ruantiblock/ruab_route_check +++ b/ruantiblock/files/usr/libexec/ruantiblock/ruab_route_check @@ -1,17 +1,69 @@ #!/bin/sh PID_FILE="/var/run/`basename $0`.pid" +APP_EXEC="/usr/bin/ruantiblock" -VpnRouteStatus() { - [ -n "`$IP_CMD route show table $VPN_ROUTE_TABLE_ID 2> /dev/null`" ] && return 0 +. "$USER_INSTANCES_COMMON" + +VPN_IFACES_STATUS=1 + +CheckIfaceStatus() { + local _iface="$1" _ret_val=0 + if [ -z "`$IP_CMD link show dev $_iface up 2> /dev/null`" ]; then + _ret_val=1 + + if [ $DEBUG -ge 1 ]; then + echo " ruab_route_check.GetVpnRouteStatus: ${_iface} disabled" >&2 + logger -p "user.debug" -t "ruantiblock" "ruab_route_check.GetVpnRouteStatus: iface ${_iface} disabled" + fi + + fi + return $_ret_val +} + +VpnRouteInstanceStatus() { + local _vpn_route_table_id=$1 + [ -n "`$IP_CMD route show table $_vpn_route_table_id 2> /dev/null`" ] && return 0 return 1 } +GetVpnRouteStatus() { + local _inst _i=1 _ret_val=0 + for _inst in $USER_INSTANCES_VPN_FNAMES + do + IncludeUserInstanceVars "$_inst" + if ! CheckIfaceStatus $U_IF_VPN; then + VPN_IFACES_STATUS=0 + fi + if ! VpnRouteInstanceStatus $(($VPN_ROUTE_TABLE_ID_START + $_i)); then + _ret_val=1 + break + fi + _i=$(($_i + 1)) + ClearUserInstanceVars + done + if [ $_ret_val -eq 0 -a "$PROXY_MODE" = "2" ]; then + if ! CheckIfaceStatus $IF_VPN; then + VPN_IFACES_STATUS=0 + fi + if ! VpnRouteInstanceStatus $VPN_ROUTE_TABLE_ID_START; then + _ret_val=1 + fi + fi + return $_ret_val +} + Main() { while [ -e "$PID_FILE" ] do - if ! VpnRouteStatus; then - if $IP_CMD link show $IF_VPN &> /dev/null; then + VPN_IFACES_STATUS=1 + if ! GetVpnRouteStatus; then + if [ "$VPN_IFACES_STATUS" = "1" ]; then + + if [ $DEBUG -ge 1 ]; then + echo " ruab_route_check.Main: ${APP_EXEC} reload" >&2 + logger -p "user.debug" -t "ruantiblock" "ruab_route_check.Main: ${APP_EXEC} reload" + fi $APP_EXEC reload fi fi diff --git a/ruantiblock/files/usr/share/ruantiblock/blacklist_sources b/ruantiblock/files/usr/share/ruantiblock/blacklist_sources index 603cf95..e9350bb 100644 --- a/ruantiblock/files/usr/share/ruantiblock/blacklist_sources +++ b/ruantiblock/files/usr/share/ruantiblock/blacklist_sources @@ -6,7 +6,6 @@ export RBL_DPI_URL="https://reestr.rublacklist.net/api/v3/dpi/" export RBL_ENCODING="" ## zapret-info export ZI_ALL_URL="https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv" -#export ZI_ALL_URL="https://app.assembla.com/spaces/z-i/git/source/master/dump.csv?_format=raw" export ZI_ENCODING="CP1251" ## antifilter export AF_IP_URL="https://antifilter.download/list/allyouneed.lst" @@ -52,7 +51,6 @@ case "$BLLIST_PRESET" in export BLLIST_SOURCE="ruantiblock" export BLLIST_MODE="ip" BLLIST_MODULE="DownloadNativeBlacklist" - # github DL_IPSET_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist-1.1/ip/ruantiblock.ip" DL_DMASK_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist-1.1/ip/ruantiblock.dnsmasq" DL_STAT_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist-1.1/ip/update_status" @@ -61,7 +59,6 @@ case "$BLLIST_PRESET" in export BLLIST_SOURCE="ruantiblock" export BLLIST_MODE="fqdn" BLLIST_MODULE="DownloadNativeBlacklist" - # github DL_IPSET_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist-1.1/fqdn/ruantiblock.ip" DL_DMASK_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist-1.1/fqdn/ruantiblock.dnsmasq" DL_STAT_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist-1.1/fqdn/update_status" diff --git a/ruantiblock/files/usr/share/ruantiblock/config_script b/ruantiblock/files/usr/share/ruantiblock/config_script index 309d15c..a2a67bc 100644 --- a/ruantiblock/files/usr/share/ruantiblock/config_script +++ b/ruantiblock/files/usr/share/ruantiblock/config_script @@ -1,5 +1,5 @@ UCI_SECTION="ruantiblock.config" -UCI_VARS="proxy_mode proxy_local_clients nftset_clear_sets allowed_hosts_mode allowed_hosts_list bypass_mode bypass_entries_dns enable_fproxy fproxy_list enable_bllist_proxy if_vpn vpn_gw_ip vpn_route_check tor_trans_port onion_dns_addr t_proxy_port_tcp t_proxy_port_udp t_proxy_allow_udp add_user_entries user_entries_dns user_entries_remote enable_logging bllist_min_entries bllist_module bllist_preset bllist_ip_limit bllist_summarize_ip bllist_summarize_cidr bllist_ip_filter bllist_ip_filter_type bllist_sd_limit bllist_fqdn_filter bllist_fqdn_filter_type bllist_enable_idn bllist_alt_nslookup bllist_alt_dns_addr update_at_startup enable_tmp_downloads" +UCI_VARS="dnsmasq_cfg_dir proxy_mode proxy_local_clients nftset_clear_sets allowed_hosts_mode allowed_hosts_list bypass_mode bypass_entries_dns enable_fproxy fproxy_list enable_bllist_proxy if_vpn vpn_gw_ip vpn_route_check tor_trans_port onion_dns_addr t_proxy_type t_proxy_port_tcp t_proxy_port_udp t_proxy_allow_udp enable_logging bllist_min_entries bllist_module bllist_preset bllist_ip_limit bllist_summarize_ip bllist_summarize_cidr bllist_ip_filter bllist_ip_filter_type bllist_sd_limit bllist_fqdn_filter bllist_fqdn_filter_type bllist_enable_idn bllist_alt_nslookup bllist_alt_dns_addr update_at_startup enable_tmp_downloads" UCI_CMD=`which uci` if [ $? -ne 0 ]; then echo " Error! UCI doesn't exists" >&2 diff --git a/ruantiblock/files/usr/share/ruantiblock/config_script_user_instances b/ruantiblock/files/usr/share/ruantiblock/config_script_user_instances new file mode 100644 index 0000000..6f8ed91 --- /dev/null +++ b/ruantiblock/files/usr/share/ruantiblock/config_script_user_instances @@ -0,0 +1,54 @@ +UCI_VARS="u_enabled u_proxy_mode u_tor_trans_port u_onion_dns_addr u_if_vpn u_vpn_gw_ip u_t_proxy_type u_t_proxy_port_tcp u_t_proxy_port_udp u_t_proxy_allow_udp u_entries_dns u_entries_remote u_enable_entries_remote_proxy u_enable_fproxy u_fproxy_list u_skip_marked_packets" +UCI_CMD=`which uci` +if [ $? -ne 0 ]; then + echo " Error! UCI doesn't exists" >&2 + exit 1 +fi +AWK_CMD="awk" + +ListUserInstances() { + $UCI_CMD export "$NAME" | $AWK_CMD -v TYPE="user_instance" ' + BEGIN { + instances=""; + } + { + if($0 ~ "config "TYPE) { + gsub(/["\047]/, "", $3); + instances=instances (length(instances) > 0 ? "\n" : "") $3; + }; + } + END { + print instances; + }' +} + +IncludeUserInstanceVars() { + local _inst="$1" + local _uci_section="${NAME}.${_inst}" + U_NAME="$_inst" + eval `$UCI_CMD show "$_uci_section" | $AWK_CMD -F "=" -v UCI_VARS="$UCI_VARS" ' + BEGIN { + split(UCI_VARS, split_array, " "); + for(i in split_array) + vars_array[split_array[i]]=""; + } + { + sub(/^.*[.]/, "", $1); + gsub(/["\047]/, "", $2); + if($1 in vars_array) { + print toupper($1) "=\"" $2 "\""; + delete vars_array[$1]; + }; + } + END { + if(length(vars_array) > 0) { + for(i in vars_array) + print toupper(i) "=\"""\""; + }; + }'` + + if [ $DEBUG -ge 2 ]; then + echo " user_instances_config_script.IncludeUserInstanceVars: _inst=${_inst} U_NAME=${U_NAME} U_PROXY_MODE=${U_PROXY_MODE}" >&2 + MakeLogRecord "debug" "user_instances_config_script.IncludeUserInstanceVars: _inst=${_inst} U_NAME=${U_NAME} U_PROXY_MODE=${U_PROXY_MODE}" + fi +} diff --git a/ruantiblock/files/usr/share/ruantiblock/info_output b/ruantiblock/files/usr/share/ruantiblock/info_output index 68aa49d..50c77d9 100644 --- a/ruantiblock/files/usr/share/ruantiblock/info_output +++ b/ruantiblock/files/usr/share/ruantiblock/info_output @@ -1,5 +1,5 @@ Info() { - local _update_status _user_entries_status + local _update_status _user_entries_status _inst if [ -f "$UPDATE_STATUS_FILE" ]; then _update_status=`$AWK_CMD '{ if(NF < 4) { @@ -33,29 +33,30 @@ Info() { else _user_entries_status="[]" fi - NftListBllistChainJson 2> /dev/null | $AWK_CMD -v UPDATE_STATUS="$_update_status" -v USER_ENTRIES_STATUS="$_user_entries_status" ' - BEGIN { - rules_str = ""; - } - { - rules_str = rules_str $0; - } + NftListSinkChainJson 2> /dev/null | $AWK_CMD -v UPDATE_STATUS="$_update_status" -v USER_ENTRIES_STATUS="$_user_entries_status" ' END { if(NR == 0) { printf "{\"status\": \"disabled\"}"; exit 1; } else { - printf "{\"status\":\"enabled\",\"last_blacklist_update\":%s,\"user_entries\":%s,\"rules\":%s", UPDATE_STATUS, USER_ENTRIES_STATUS, rules_str; + printf "{\"status\": \"enabled\",\"last_blacklist_update\": %s,\"user_entries\" :%s,\"sink\": %s", UPDATE_STATUS, USER_ENTRIES_STATUS, $0; exit 0; }; }' if [ $? -eq 0 ]; then + if [ "$PROXY_LOCAL_CLIENTS" = "1" ]; then + printf ",\"sink_local\":" + NftListSinkLocalChainJson 2> /dev/null + fi printf ",\"dnsmasq\":" $NFT_CMD -j list set $NFT_TABLE "$NFTSET_DNSMASQ" 2> /dev/null - if [ "$BYPASS_MODE" = "1" ]; then - printf ",\"dnsmasq_bypass\":" - $NFT_CMD -j list set $NFT_TABLE "$NFTSET_BYPASS_FQDN" 2> /dev/null - fi + printf ",\"dnsmasq_user_instances\":[" + for _inst in $USER_INSTANCES_ALL + do + $NFT_CMD -j list set $NFT_TABLE "${NFTSET_DNSMASQ}-${_inst}" 2> /dev/null + printf "," + done + printf "{\"dummy\": {}}]" printf "}" fi } diff --git a/ruantiblock/files/usr/share/ruantiblock/nft_functions b/ruantiblock/files/usr/share/ruantiblock/nft_functions index 2659820..8c48b7c 100644 --- a/ruantiblock/files/usr/share/ruantiblock/nft_functions +++ b/ruantiblock/files/usr/share/ruantiblock/nft_functions @@ -2,35 +2,26 @@ NFT_ALLOWED_HOSTS_CHAIN="allowed_hosts" NFT_BLLIST_CHAIN="blacklist" NFT_FPROXY_FILTER="fproxy_filter" NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN="dnsmasq_timeout_update" -NFT_ACTION_CHAIN="action" +NFT_MARK_CHAIN="mark_chain" NFT_LOCAL_CLIENTS_CHAIN="local_clients" - -if [ "$PROXY_MODE" = "2" ]; then - MAIN_CHAIN_TYPE="type filter hook prerouting priority ${NFT_PRIO_ROUTE}; policy accept;" - LOCAL_CLIENTS_CHAIN_TYPE="type route hook output priority ${NFT_PRIO_ROUTE_LOCAL}; policy accept;" -else - MAIN_CHAIN_TYPE="type nat hook prerouting priority ${NFT_PRIO_NAT}; policy accept;" - LOCAL_CLIENTS_CHAIN_TYPE="type nat hook output priority ${NFT_PRIO_NAT_LOCAL}; policy accept;" -fi +NFT_SINK_CHAIN="sink" +NFT_SINK_LOCAL_CHAIN="sink_local" +NFT_ACTION_FILTER_CHAIN="action_filter" +NFT_ACTION_NAT_CHAIN="action_nat" +NFT_ACTION_NAT_LOCAL_CHAIN="action_nat_local" case "$ALLOWED_HOSTS_MODE" in "1") - NFT_ALLOWED_HOSTS_EXPR="ip saddr @${NFTSET_ALLOWED_HOSTS} jump ${NFT_BLLIST_CHAIN}" + NFT_ALLOWED_HOSTS_PATTERN="ip saddr @${NFTSET_ALLOWED_HOSTS} jump ${NFT_BLLIST_CHAIN}%s" ;; "2") - NFT_ALLOWED_HOSTS_EXPR="ip saddr != @${NFTSET_ALLOWED_HOSTS} jump ${NFT_BLLIST_CHAIN}" + NFT_ALLOWED_HOSTS_PATTERN="ip saddr != @${NFTSET_ALLOWED_HOSTS} jump ${NFT_BLLIST_CHAIN}%s" ;; *) - NFT_ALLOWED_HOSTS_EXPR="jump ${NFT_BLLIST_CHAIN}" + NFT_ALLOWED_HOSTS_PATTERN="jump ${NFT_BLLIST_CHAIN}%s" ;; esac -if [ "$NFTSET_DNSMASQ_TIMEOUT_UPDATE" = "1" ]; then - NFT_DNSMASQ_RULE_TARGET="$NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN" -else - NFT_DNSMASQ_RULE_TARGET="$NFT_ACTION_CHAIN" -fi - NftCmdWrapper() { local _i=0 _attempts=10 _return_code=1 while [ $_i -lt $_attempts ] @@ -44,105 +35,247 @@ NftCmdWrapper() { return $_return_code } -NftVpnRouteDelete() { - $IP_CMD route flush table $VPN_ROUTE_TABLE_ID - $IP_CMD rule del table $VPN_ROUTE_TABLE_ID +NftRouteDelete() { + local _route_table_id=$1 + $IP_CMD route flush table $_route_table_id + $IP_CMD rule del table $_route_table_id } -NftVpnRouteAdd() { - local _vpn_ip - if [ -n "$VPN_GW_IP" ]; then - _vpn_ip="$VPN_GW_IP" +NftRouteAdd() { + local _vpn_ip _type="$1" _route_table_id=$2 _pkts_mark=$3 _if_vpn="$4" _vpn_gw_ip="$5" + if [ "$_type" = "lo" ]; then + echo 0 > /proc/sys/net/ipv4/conf/lo/rp_filter + $IP_CMD rule add fwmark $_pkts_mark table $_route_table_id priority $LO_RULE_PRIO + $IP_CMD route add local default dev lo table $_route_table_id + + if [ $DEBUG -ge 1 ]; then + echo " nft_functions.NftRouteAdd: ${IP_CMD} rule add fwmark ${_pkts_mark} table ${_route_table_id} priority ${LO_RULE_PRIO}" >&2 + MakeLogRecord "debug" "nft_functions.NftRouteAdd: ${IP_CMD} rule add fwmark ${_pkts_mark} table ${_route_table_id} priority ${LO_RULE_PRIO}" + echo " nft_functions.NftRouteAdd: ${IP_CMD} route add local default dev lo table ${_route_table_id}" >&2 + MakeLogRecord "debug" "nft_functions.NftRouteAdd: ${IP_CMD} route add local default dev lo table ${_route_table_id}" + fi else - _vpn_ip=`$IP_CMD addr list dev $IF_VPN 2> /dev/null | $AWK_CMD '/inet/{f=($3 == "peer") ? 4 : 2; sub("/[0-9]{1,2}$", "", $f); print $f; exit}'` - fi - if [ -n "$_vpn_ip" ]; then - echo 0 > /proc/sys/net/ipv4/conf/$IF_VPN/rp_filter - NftVpnRouteDelete 2> /dev/null - $IP_CMD rule add fwmark $VPN_PKTS_MARK table $VPN_ROUTE_TABLE_ID priority $VPN_RULE_PRIO - $IP_CMD route add default via $_vpn_ip table $VPN_ROUTE_TABLE_ID + if [ -n "$_vpn_gw_ip" ]; then + _vpn_ip="$_vpn_gw_ip" + else + _vpn_ip=`$IP_CMD addr list dev $_if_vpn 2> /dev/null | $AWK_CMD '/inet/{f=($3 == "peer") ? 4 : 2; sub("/[0-9]{1,2}$", "", $f); print $f; exit}'` + fi + if [ -n "$_vpn_ip" -a "$_type" = "vpn" ]; then + echo 0 > /proc/sys/net/ipv4/conf/$_if_vpn/rp_filter + NftRouteDelete $_route_table_id 2> /dev/null + $IP_CMD rule add fwmark $_pkts_mark table $_route_table_id priority $VPN_RULE_PRIO + $IP_CMD route add default via $_vpn_ip table $_route_table_id + if [ $? -ne 0 ]; then + echo " Error! An error occurred while adding the route. Routing table id=${_route_table_id}, VPN gateway IP=${_vpn_ip}" >&2 + MakeLogRecord "err" "Error! An error occurred while adding the route. Routing table id=${_route_table_id}, VPN gateway IP=${_vpn_ip}" + fi + + if [ $DEBUG -ge 1 ]; then + echo " nft_functions.NftRouteAdd: ${IP_CMD} rule add fwmark ${_pkts_mark} table ${_route_table_id} priority ${VPN_RULE_PRIO}" >&2 + MakeLogRecord "debug" "nft_functions.NftRouteAdd: ${IP_CMD} rule add fwmark ${_pkts_mark} table ${_route_table_id} priority ${VPN_RULE_PRIO}" + echo " nft_functions.NftRouteAdd: ${IP_CMD} route add default via ${_vpn_ip} table ${_route_table_id}" >&2 + MakeLogRecord "debug" "nft_functions.NftRouteAdd: ${IP_CMD} route add default via ${_vpn_ip} table ${_route_table_id}" + fi + fi fi } -NftVpnRouteStatus() { - [ -n "`$IP_CMD route show table $VPN_ROUTE_TABLE_ID 2> /dev/null`" ] && return 0 +NftRouteStatus() { + local _route_table_id=$1 + [ -n "`$IP_CMD route show table $_route_table_id 2> /dev/null`" ] && return 0 return 1 } -NftMainAdd() { - local _set - $NFT_CMD add chain $NFT_TABLE "$NFT_LOCAL_CLIENTS_CHAIN" { $LOCAL_CLIENTS_CHAIN_TYPE } - $NFT_CMD add chain $NFT_TABLE "$NFT_ACTION_CHAIN" - $NFT_CMD add chain $NFT_TABLE "$NFT_FPROXY_FILTER" - $NFT_CMD add chain $NFT_TABLE "$NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN" - $NFT_CMD add chain $NFT_TABLE "$NFT_BLLIST_CHAIN" - $NFT_CMD add chain $NFT_TABLE "$NFT_ALLOWED_HOSTS_CHAIN" { $MAIN_CHAIN_TYPE } - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE $NFT_FPROXY_FILTER ip daddr "@${NFTSET_FPROXY_PRIVATE}" return - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_FPROXY_FILTER" jump "$NFT_ACTION_CHAIN" - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN" ct state new set update ip daddr "@${NFTSET_DNSMASQ}" - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN" jump "$NFT_ACTION_CHAIN" - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_ALLOWED_HOSTS_CHAIN" $NFT_ALLOWED_HOSTS_EXPR - if [ "$PROXY_MODE" = "2" ]; then - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_ACTION_CHAIN" mark set $VPN_PKTS_MARK - elif [ "$PROXY_MODE" = "3" ]; then - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_ACTION_CHAIN" tcp dport { 0-65535 } redirect to $T_PROXY_PORT_TCP - if [ "$T_PROXY_ALLOW_UDP" = "1" ]; then - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_ACTION_CHAIN" udp dport { 0-65535 } redirect to $T_PROXY_PORT_UDP - fi +NftAddSinkChains() { + local _chain_prio_sink=$1 + $NFT_CMD add chain $NFT_TABLE "${NFT_SINK_CHAIN}" { type filter hook prerouting priority ${_chain_prio_sink}\; policy accept\; } + $NFT_CMD add chain $NFT_TABLE "${NFT_SINK_LOCAL_CHAIN}" { type route hook output priority ${_chain_prio_sink}\; policy accept\; } + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_CHAIN}" meta iif lo return +} + +NftDeleteSinkChains() { + $NFT_CMD delete chain $NFT_TABLE "${NFT_SINK_CHAIN}" + $NFT_CMD delete chain $NFT_TABLE "${NFT_SINK_LOCAL_CHAIN}" +} + +NftAddActionChains() { + local _chain_prio_action=$1 + $NFT_CMD add chain $NFT_TABLE "${NFT_ACTION_FILTER_CHAIN}" { type filter hook prerouting priority ${_chain_prio_action}\; policy accept\; } + $NFT_CMD add chain $NFT_TABLE "${NFT_ACTION_NAT_CHAIN}" { type nat hook prerouting priority ${_chain_prio_action}\; policy accept\; } + $NFT_CMD add chain $NFT_TABLE "${NFT_ACTION_NAT_LOCAL_CHAIN}" { type nat hook output priority ${_chain_prio_action}\; policy accept\; } +} + +NftDeleteActionChains() { + $NFT_CMD delete chain $NFT_TABLE "${NFT_ACTION_FILTER_CHAIN}" + $NFT_CMD delete chain $NFT_TABLE "${NFT_ACTION_NAT_CHAIN}" + $NFT_CMD delete chain $NFT_TABLE "${NFT_ACTION_NAT_LOCAL_CHAIN}" +} + +NftInstanceAdd() { + local _i _inst _first_chain_type _t_proxy_statement _chain_action_type _set + + for _i in "_name" "_pkts_mark" "_chain_prio_first" "_chain_prio_local" "_proxy_mode" "_tor_trans_port" "_route_table_id" "_if_vpn" "_t_proxy_type" "_t_proxy_port_tcp" "_t_proxy_port_udp" "_t_proxy_allow_udp" "_enable_bllist_proxy" "_enable_fproxy" "_skip_marked_packets" "_vpn_gw_ip" + do + eval "local $_i=$1" + shift + done + + _inst="$_name" + if [ "$_name" = " " ]; then + _name="" else - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_ACTION_CHAIN" tcp dport { 0-65535 } redirect to $TOR_TRANS_PORT - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_BLLIST_CHAIN" ip daddr "@${NFTSET_ONION}" counter goto "$NFT_ACTION_CHAIN" + _name="-${_name}" fi - if [ "$ENABLE_FPROXY" = "1" ]; then - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_BLLIST_CHAIN" ip saddr "@${NFTSET_FPROXY}" counter goto "$NFT_FPROXY_FILTER" + + if [ $DEBUG -ge 1 ]; then + echo " nft_functions.NftInstanceAdd.args: _name=${_name} _pkts_mark=${_pkts_mark} _chain_prio_first=${_chain_prio_first} _chain_prio_local=${_chain_prio_local} _proxy_mode=${_proxy_mode} _tor_trans_port=${_tor_trans_port} _route_table_id=${_route_table_id} _if_vpn=${_if_vpn} _t_proxy_type=${_t_proxy_type} _t_proxy_port_tcp=${_t_proxy_port_tcp} _t_proxy_port_udp=${_t_proxy_port_udp} _t_proxy_allow_udp=${_t_proxy_allow_udp} _enable_bllist_proxy=${_enable_bllist_proxy} _enable_fproxy=${_enable_fproxy} _skip_marked_packets=${_skip_marked_packets} _vpn_gw_ip=${_vpn_gw_ip}" >&2 + MakeLogRecord "debug" "nft_functions.NftInstanceAdd.args: _name=${_name} _pkts_mark=${_pkts_mark} _chain_prio_first=${_chain_prio_first} _chain_prio_local=${_chain_prio_local} _proxy_mode=${_proxy_mode} _tor_trans_port=${_tor_trans_port} _route_table_id=${_route_table_id} _if_vpn=${_if_vpn} _t_proxy_type=${_t_proxy_type} _t_proxy_port_tcp=${_t_proxy_port_tcp} _t_proxy_port_udp=${_t_proxy_port_udp} _t_proxy_allow_udp=${_t_proxy_allow_udp} _enable_bllist_proxy=${_enable_bllist_proxy} _enable_fproxy=${_enable_fproxy} _skip_marked_packets=${_skip_marked_packets} _vpn_gw_ip=${_vpn_gw_ip}" fi + + if [ "$NFTSET_DNSMASQ_TIMEOUT_UPDATE" = "1" ]; then + _nft_dnsmasq_rule_target="${NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN}${_name}" + else + _nft_dnsmasq_rule_target="${NFT_MARK_CHAIN}${_name}" + fi + + $NFT_CMD add chain $NFT_TABLE "${NFT_LOCAL_CLIENTS_CHAIN}${_name}" { type route hook output priority ${_chain_prio_local}\; policy accept\; } + $NFT_CMD add chain $NFT_TABLE "${NFT_MARK_CHAIN}${_name}" + $NFT_CMD add chain $NFT_TABLE "${NFT_FPROXY_FILTER}${_name}" + $NFT_CMD add chain $NFT_TABLE "${NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN}${_name}" + $NFT_CMD add chain $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" + $NFT_CMD add chain $NFT_TABLE "${NFT_ALLOWED_HOSTS_CHAIN}${_name}" { type filter hook prerouting priority ${_chain_prio_first}\; policy accept\; } + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_FPROXY_FILTER}${_name}" ip daddr "@${NFTSET_FPROXY_PRIVATE}" return + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_FPROXY_FILTER}${_name}" jump "${NFT_MARK_CHAIN}${_name}" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN}${_name}" ct state new set update ip daddr "@${NFTSET_DNSMASQ}${_name}" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN}${_name}" jump "${NFT_MARK_CHAIN}${_name}" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ALLOWED_HOSTS_CHAIN}${_name}" "`printf "$NFT_ALLOWED_HOSTS_PATTERN" "$_name"`" + + if [ "$_proxy_mode" = "2" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_CHAIN}" meta mark $_pkts_mark counter comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_LOCAL_CHAIN}" meta mark $_pkts_mark counter comment \""$_inst"\" + elif [ "$_proxy_mode" = "3" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_CHAIN}" meta l4proto tcp meta mark $_pkts_mark counter comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_LOCAL_CHAIN}" meta l4proto tcp meta mark $_pkts_mark counter comment \""$_inst"\" + if [ "$_t_proxy_type" = "1" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ACTION_FILTER_CHAIN}" meta l4proto tcp meta mark $_pkts_mark tproxy to ":${_t_proxy_port_tcp}" comment \""$_inst"\" + if [ "$_t_proxy_allow_udp" = "1" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ACTION_FILTER_CHAIN}" meta l4proto udp meta mark $_pkts_mark tproxy to ":${_t_proxy_port_udp}" comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_CHAIN}" meta l4proto udp meta mark $_pkts_mark counter comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_LOCAL_CHAIN}" meta l4proto udp meta mark $_pkts_mark counter comment \""$_inst"\" + fi + else + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ACTION_NAT_CHAIN}" meta l4proto tcp meta mark $_pkts_mark redirect to ":${_t_proxy_port_tcp}" comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ACTION_NAT_LOCAL_CHAIN}" meta l4proto tcp meta mark $_pkts_mark redirect to ":${_t_proxy_port_tcp}" comment \""$_inst"\" + if [ "$_t_proxy_allow_udp" = "1" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ACTION_NAT_CHAIN}" meta l4proto udp meta mark $_pkts_mark redirect to ":${_t_proxy_port_udp}" comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ACTION_NAT_LOCAL_CHAIN}" meta l4proto udp meta mark $_pkts_mark redirect to ":${_t_proxy_port_udp}" comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_CHAIN}" meta l4proto udp meta mark $_pkts_mark counter comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_LOCAL_CHAIN}" meta l4proto udp meta mark $_pkts_mark counter comment \""$_inst"\" + fi + fi + elif [ "$_proxy_mode" != "2" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ACTION_NAT_CHAIN}" meta l4proto tcp meta mark $_pkts_mark redirect to ":${_tor_trans_port}" comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_ACTION_NAT_LOCAL_CHAIN}" meta l4proto tcp meta mark $_pkts_mark redirect to ":${_tor_trans_port}" comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_CHAIN}" meta l4proto tcp meta mark $_pkts_mark counter comment \""$_inst"\" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_SINK_LOCAL_CHAIN}" meta l4proto tcp meta mark $_pkts_mark counter comment \""$_inst"\" + fi + + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_MARK_CHAIN}${_name}" mark set $_pkts_mark + if [ "$_proxy_mode" != "2" -a "$_proxy_mode" != "3" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" ip daddr "@${NFTSET_ONION}${_name}" counter goto "${NFT_MARK_CHAIN}${_name}" + fi + if [ "$_skip_marked_packets" = "1" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" meta mark "@${NFTSET_MARK_SET}" return + fi + if [ "$_enable_fproxy" = "1" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" ip saddr "@${NFTSET_FPROXY}${_name}" goto "${NFT_FPROXY_FILTER}${_name}" + fi + if [ "$BYPASS_MODE" = "1" ]; then for _set in "$NFTSET_BYPASS_IP" "$NFTSET_BYPASS_FQDN" do - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_BLLIST_CHAIN" ip daddr "@${_set}" counter accept + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" ip daddr "@${_set}" accept done fi - for _set in "$NFTSET_CIDR" "$NFTSET_IP" + + for _set in "${NFTSET_CIDR}${_name}" "${NFTSET_IP}${_name}" do - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_BLLIST_CHAIN" ip daddr "@${_set}" counter goto "$NFT_ACTION_CHAIN" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" ip daddr "@${_set}" counter goto "${NFT_MARK_CHAIN}${_name}" done - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_BLLIST_CHAIN" ip daddr "@${NFTSET_DNSMASQ}" counter goto "$NFT_DNSMASQ_RULE_TARGET" - if [ "$PROXY_MODE" = "2" ]; then - NftVpnRouteAdd + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" ip daddr "@${NFTSET_DNSMASQ}${_name}" counter goto "$_nft_dnsmasq_rule_target" + + if [ "$_proxy_mode" = "2" ]; then + NftRouteAdd vpn $_route_table_id $_pkts_mark "$_if_vpn" "$_vpn_gw_ip" + elif [ "$_proxy_mode" = "3" -a "$_t_proxy_type" = "1" ]; then + NftRouteAdd lo $_route_table_id $_pkts_mark fi - if [ "$ENABLE_BLLIST_PROXY" = "1" ]; then - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_LOCAL_CLIENTS_CHAIN" ip daddr "@${NFTSET_BLLIST_PROXY}" counter goto "$NFT_ACTION_CHAIN" + + if [ "$_enable_bllist_proxy" = "1" ]; then + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_LOCAL_CLIENTS_CHAIN}${_name}" ip daddr "@${NFTSET_BLLIST_PROXY}${_name}" counter goto "${NFT_MARK_CHAIN}${_name}" fi if [ "$PROXY_LOCAL_CLIENTS" = "1" ]; then - NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_LOCAL_CLIENTS_CHAIN" jump "$NFT_BLLIST_CHAIN" + NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "${NFT_LOCAL_CLIENTS_CHAIN}${_name}" jump "${NFT_BLLIST_CHAIN}${_name}" fi } -NftMainDelete() { - $NFT_CMD flush chain $NFT_TABLE "$NFT_ALLOWED_HOSTS_CHAIN" - $NFT_CMD delete chain $NFT_TABLE "$NFT_ALLOWED_HOSTS_CHAIN" - $NFT_CMD flush chain $NFT_TABLE "$NFT_LOCAL_CLIENTS_CHAIN" - $NFT_CMD delete chain $NFT_TABLE "$NFT_LOCAL_CLIENTS_CHAIN" - $NFT_CMD flush chain $NFT_TABLE "$NFT_BLLIST_CHAIN" - $NFT_CMD delete chain $NFT_TABLE "$NFT_BLLIST_CHAIN" - $NFT_CMD flush chain $NFT_TABLE "$NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN" - $NFT_CMD delete chain $NFT_TABLE "$NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN" - $NFT_CMD flush chain $NFT_TABLE "$NFT_FPROXY_FILTER" - $NFT_CMD delete chain $NFT_TABLE "$NFT_FPROXY_FILTER" - $NFT_CMD flush chain $NFT_TABLE "$NFT_ACTION_CHAIN" - $NFT_CMD delete chain $NFT_TABLE "$NFT_ACTION_CHAIN" - NftVpnRouteDelete 2> /dev/null +NftInstanceDelete() { + local _name="$1" + if [ -z "$_name" -o "$_name" = " " ]; then + _name="" + else + _name="-${_name}" + fi + $NFT_CMD delete chain $NFT_TABLE "${NFT_ALLOWED_HOSTS_CHAIN}${_name}" + $NFT_CMD delete chain $NFT_TABLE "${NFT_LOCAL_CLIENTS_CHAIN}${_name}" + $NFT_CMD delete chain $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" + $NFT_CMD delete chain $NFT_TABLE "${NFT_DNSMASQ_TIMEOUT_UPDATE_CHAIN}${_name}" + $NFT_CMD delete chain $NFT_TABLE "${NFT_FPROXY_FILTER}${_name}" + $NFT_CMD delete chain $NFT_TABLE "${NFT_MARK_CHAIN}${_name}" } NftListBllistChain() { - $NFT_CMD -t list chain $NFT_TABLE "$NFT_BLLIST_CHAIN" + local _name="$1" + if [ -z "$_name" -o "$_name" = " " ]; then + _name="" + else + _name="-${_name}" + fi + $NFT_CMD -t list chain $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" } NftListBllistChainJson() { - $NFT_CMD -t -j list chain $NFT_TABLE "$NFT_BLLIST_CHAIN" + local _name="$1" + if [ -z "$_name" -o "$_name" = " " ]; then + _name="" + else + _name="-${_name}" + fi + $NFT_CMD -t -j list chain $NFT_TABLE "${NFT_BLLIST_CHAIN}${_name}" } -NftReturnStatus() { - $NFT_CMD -c add rule $NFT_TABLE "$NFT_BLLIST_CHAIN" continue &> /dev/null +NftListSinkChain() { + $NFT_CMD -t list chain $NFT_TABLE "$NFT_SINK_CHAIN" +} + +NftListSinkChainJson() { + $NFT_CMD -t -j list chain $NFT_TABLE "$NFT_SINK_CHAIN" +} + +NftListSinkLocalChain() { + $NFT_CMD -t list chain $NFT_TABLE "$NFT_SINK_LOCAL_CHAIN" +} + +NftListSinkLocalChainJson() { + $NFT_CMD -t -j list chain $NFT_TABLE "$NFT_SINK_LOCAL_CHAIN" +} + +NftReturnInstanceStatus() { + local _name="$1" + if [ -z "$_name" -o "$_name" = " " ]; then + _name="" + else + _name="-${_name}" + fi + $NFT_CMD -c add rule $NFT_TABLE "${NFT_ALLOWED_HOSTS_CHAIN}${_name}" continue &> /dev/null return $? } diff --git a/ruantiblock/files/usr/share/ruantiblock/user_instances_common b/ruantiblock/files/usr/share/ruantiblock/user_instances_common new file mode 100644 index 0000000..8882386 --- /dev/null +++ b/ruantiblock/files/usr/share/ruantiblock/user_instances_common @@ -0,0 +1,75 @@ + +if [ $USER_INSTANCES_MAX -gt 50 ]; then + USER_INSTANCES_MAX=50 +fi + +IncludeUserInstanceVars() { + local _inst="$1" + . "${USER_INSTANCES_DIR}/${_inst}" + + if [ $DEBUG -ge 2 ]; then + echo " user_instances_common.IncludeUserInstanceVars: _inst=${_inst} U_NAME=${U_NAME} U_PROXY_MODE=${U_PROXY_MODE}" >&2 + MakeLogRecord "debug" "user_instances_common.IncludeUserInstanceVars: _inst=${_inst} U_NAME=${U_NAME} U_PROXY_MODE=${U_PROXY_MODE}" + fi +} + +ClearUserInstanceVars() { + unset $USER_INSTANCE_VARS +} + +ListUserInstances() { + ls -1 "$USER_INSTANCES_DIR" +} + +[ -f "$CONFIG_SCRIPT_USER_INSTANCES" ] && . "$CONFIG_SCRIPT_USER_INSTANCES" + +GetUserInstances() { + local _type="$1" _fnames="$2" _i=0 _inst _instances="" + for _inst in `ListUserInstances` + do + IncludeUserInstanceVars "$_inst" + if [ $_i -lt $USER_INSTANCES_MAX -a -n "$U_NAME" -a "$U_ENABLED" != "0" ]; then + if [ "$_type" = "0" -o "$U_PROXY_MODE" = "$_type" ]; then + if [ "$_fnames" = "fnames" ]; then + _instances="${_instances}${_inst} " + else + _instances="${_instances}${U_NAME} " + fi + fi + _i=$(($_i + 1)) + fi + ClearUserInstanceVars + done + printf "$_instances" +} + +SetUserInstancesItems() { + local _i=0 _inst _instances_all="" _instances_all_fnames="" _instances_vpn="" _instances_vpn_fnames="" _instances_cfg="" _instances_cfg_fnames="" + for _inst in `ListUserInstances` + do + IncludeUserInstanceVars "$_inst" + if [ $_i -lt $USER_INSTANCES_MAX -a -n "$U_NAME" -a "$U_ENABLED" != "0" ]; then + _instances_all="${_instances_all}${U_NAME} " + _instances_all_fnames="${_instances_all_fnames}${_inst} " + if [ "$U_PROXY_MODE" = "2" ]; then + _instances_vpn="${_instances_vpn}${U_NAME} " + _instances_vpn_fnames="${_instances_vpn_fnames}${_inst} " + fi + _i=$(($_i + 1)) + fi + _instances_cfg="${_instances_cfg}${U_NAME} " + _instances_cfg_fnames="${_instances_cfg_fnames}${_inst} " + ClearUserInstanceVars + done + USER_INSTANCES_ALL="$_instances_all" + USER_INSTANCES_ALL_FNAMES="$_instances_all_fnames" + USER_INSTANCES_VPN="$_instances_vpn" + USER_INSTANCES_VPN_FNAMES="$_instances_vpn_fnames" + USER_INSTANCES_CFG="$_instances_cfg" + USER_INSTANCES_CFG_FNAMES="$_instances_cfg_fnames" + + if [ $DEBUG -ge 2 ]; then + echo " user_instances_common.SetUserInstancesItems: USER_INSTANCES_ALL=\"${USER_INSTANCES_ALL}\"; USER_INSTANCES_ALL_FNAMES=\"${USER_INSTANCES_ALL_FNAMES}\"; USER_INSTANCES_VPN=\"${USER_INSTANCES_VPN}\"; USER_INSTANCES_VPN_FNAMES=\"${USER_INSTANCES_VPN_FNAMES}\"" >&2 + MakeLogRecord "debug" "user_instances_common.SetUserInstancesItems: USER_INSTANCES_ALL=\"${USER_INSTANCES_ALL}\"; USER_INSTANCES_ALL_FNAMES=\"${USER_INSTANCES_ALL_FNAMES}\"; USER_INSTANCES_VPN=\"${USER_INSTANCES_VPN}\"; USER_INSTANCES_VPN_FNAMES=\"${USER_INSTANCES_VPN_FNAMES}\"" + fi +} diff --git a/screenshots/01.jpg b/screenshots/01.jpg index 2db737d..ea26518 100644 Binary files a/screenshots/01.jpg and b/screenshots/01.jpg differ diff --git a/screenshots/02.jpg b/screenshots/02.jpg index f21638c..85c738e 100644 Binary files a/screenshots/02.jpg and b/screenshots/02.jpg differ diff --git a/screenshots/03.jpg b/screenshots/03.jpg index 9f3528a..d86bf08 100644 Binary files a/screenshots/03.jpg and b/screenshots/03.jpg differ diff --git a/screenshots/04.jpg b/screenshots/04.jpg index d7e2bc6..d00ed54 100644 Binary files a/screenshots/04.jpg and b/screenshots/04.jpg differ diff --git a/screenshots/05.jpg b/screenshots/05.jpg index 7ba9e8f..06bf40a 100644 Binary files a/screenshots/05.jpg and b/screenshots/05.jpg differ diff --git a/screenshots/06.jpg b/screenshots/06.jpg index dbba3e2..7ba9e8f 100644 Binary files a/screenshots/06.jpg and b/screenshots/06.jpg differ diff --git a/screenshots/07.jpg b/screenshots/07.jpg new file mode 100644 index 0000000..385008e Binary files /dev/null and b/screenshots/07.jpg differ