mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-03 08:13:56 +08:00
🌴 Sync 2026-03-05 23:51:42
This commit is contained in:
1 parent
97c049ed0a
commit
0acff03804
14253 files changed
+3893239
No files matched your search
@@ -0,0 +1,211 @@
|
||||
-- Copyright (C) 2019 github.com/peter-tank
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
module("luci.controller.dnscrypt-proxy", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/dnscrypt-proxy") then
|
||||
return
|
||||
end
|
||||
|
||||
entry({"admin", "services", "dnscrypt-proxy"},alias("admin", "services", "dnscrypt-proxy", "global"),_("DNSCrypt Proxy"), 10).acl_depends = { "luci-app-dnscrypt-proxy2" }
|
||||
|
||||
entry({"admin", "services", "dnscrypt-proxy", "global"},cbi("dnscrypt-proxy/global"),_("Overview"), 10).leaf = true
|
||||
entry({"admin", "services", "dnscrypt-proxy", "dnscrypt-resolvers"},cbi("dnscrypt-proxy/dnscrypt-resolvers"),_("Resolvers"), 20).leaf = true
|
||||
entry({"admin", "services", "dnscrypt-proxy", "dnscrypt-resolvers"},arcombine(cbi("dnscrypt-proxy/dnscrypt-resolvers"), cbi("dnscrypt-proxy/dnscrypt-resolvers-config")),_("Resolvers"), 25).dependent = true
|
||||
entry({"admin", "services", "dnscrypt-proxy", "dnscrypt-proxy-acl"},cbi("dnscrypt-proxy/dnscrypt-proxy-acl"),_("Resolver ACL"), 30).leaf = true
|
||||
entry({"admin", "services", "dnscrypt-proxy", "dnscrypt-proxy"},cbi("dnscrypt-proxy/dnscrypt-proxy"),_("Proxy Setting"), 40).dependent = true
|
||||
entry({"admin", "services", "dnscrypt-proxy", "refresh_c"}, call("refresh_cmd"))
|
||||
entry({"admin", "services", "dnscrypt-proxy", "resolve_c"}, call("resolve_cmd"))
|
||||
entry({"admin", "services", "dnscrypt-proxy", "update_c"}, call("update_cmd"))
|
||||
|
||||
entry({"admin", "services", "dnscrypt-proxy", "fileread"}, call("act_read"), nil).leaf=true
|
||||
|
||||
entry({"admin", "services", "dnscrypt-proxy", "logview"}, cbi("dnscrypt-proxy/logview"), _("Log") ,80).leaf=true
|
||||
|
||||
end
|
||||
|
||||
function update_cmd()
|
||||
local dc = require "luci.tools.dnscrypt".init()
|
||||
local set = luci.http.formvalue("set")
|
||||
local surl = luci.http.formvalue("url")
|
||||
local ecount, retstring = 0, "-1"
|
||||
|
||||
if set == "dnscrypt_bin" then
|
||||
local bin_file = "/usr/sbin/dnscrypt-proxy"
|
||||
local ret = action_update(surl)
|
||||
retstring = type(ret) == "table" and table.concat(ret,", ") or ret
|
||||
ecount = nixio.fs.chmod(bin_file, 755)
|
||||
else
|
||||
ecount = -1
|
||||
retstring = "Unkown CMD: " .. set
|
||||
end
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ err=ecount, status=retstring})
|
||||
end
|
||||
|
||||
function refresh_cmd()
|
||||
local set = luci.http.formvalue("set")
|
||||
local icount, retstring = 0, "-1"
|
||||
|
||||
if set == "remove_caches" then
|
||||
local dir = "/usr/share/dnscrypt-proxy"
|
||||
local output = { }
|
||||
exec("/bin/busybox", { "find", dir, "-type", "f" },
|
||||
function(chunk) output[#output+1] = chunk:match("%S+") end)
|
||||
exec("/bin/busybox", { "find", dir, "-type", "f", "-exec", "rm", "{}", ";" })
|
||||
icount = #output
|
||||
retstring = "[%d]<br />%s" % { icount, table.concat(output, "<br />") }
|
||||
elseif set == "dump_resolver" then
|
||||
local output = "/usr/share/dnscrypt-proxy/running.json"
|
||||
luci.sys.exec("/usr/sbin/dnscrypt-proxy -json --list-all -config /var/etc/dnscrypt-proxy-ns1.conf > %s" % output)
|
||||
local lua_data = luci.jsonc.parse(nixio.fs.readfile(output))
|
||||
icount = #lua_data
|
||||
retstring = "[%d] - %s" % { icount, output }
|
||||
else
|
||||
icount = -1
|
||||
retstring = "Unkown CMD: " .. set
|
||||
end
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ ret=retstring ,retcount=icount})
|
||||
end
|
||||
|
||||
function resolve_cmd()
|
||||
local set = luci.http.formvalue("set")
|
||||
local retstring="<br /><br />"
|
||||
|
||||
retstring = luci.sys.exec("/usr/sbin/dnscrypt-proxy -resolve www.google.com,127.0.0.1:7915 -config /var/etc/dnscrypt-proxy-ns1.conf")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ ret=retstring })
|
||||
end
|
||||
|
||||
-- called by XHR.get from logview.htm
|
||||
function act_read(lfile)
|
||||
local fs = require "nixio.fs"
|
||||
local http = require "luci.http"
|
||||
local lfile = http.formvalue("lfile")
|
||||
local ldata={}
|
||||
ldata[#ldata+1] = fs.readfile(lfile) or "_nofile_"
|
||||
if ldata[1] == "" then
|
||||
ldata[1] = "_nodata_"
|
||||
end
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(ldata)
|
||||
end
|
||||
|
||||
function action_data()
|
||||
local http = require "luci.http"
|
||||
|
||||
local types = {
|
||||
csv = "text/csv",
|
||||
json = "application/json"
|
||||
}
|
||||
|
||||
local args = { }
|
||||
local mtype = http.formvalue("type") or "json"
|
||||
|
||||
http.prepare_content(types[mtype])
|
||||
exec("/usr/sbin/dnscrypt-proxy", args, http.write)
|
||||
end
|
||||
|
||||
function action_list()
|
||||
local http = require "luci.http"
|
||||
|
||||
local fd = io.popen("/usr/sbin/dnscrypt-proxy -c list")
|
||||
local periods = { }
|
||||
|
||||
if fd then
|
||||
while true do
|
||||
local period = fd:read("*l")
|
||||
|
||||
if not period then
|
||||
break
|
||||
end
|
||||
|
||||
periods[#periods+1] = period
|
||||
end
|
||||
|
||||
fd:close()
|
||||
end
|
||||
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(periods)
|
||||
end
|
||||
|
||||
function action_update(surl)
|
||||
local tmp = "/tmp/dnscrypt-proxy_bin.tar.gz"
|
||||
local dir = "/tmp"
|
||||
local stype = luci.util.exec("uname"):lower()
|
||||
local sarch = luci.util.exec("uname -m")
|
||||
|
||||
exec("/usr/bin/wget-ssl", {"--no-check-certificate", "-O", tmp, surl})
|
||||
|
||||
exec("/usr/sbin/dnscrypt-proxy", {"-service", "stop" })
|
||||
local files = { }
|
||||
local tar = io.popen("/bin/tar -tzf %s" % tmp, "r")
|
||||
if tar then
|
||||
while true do
|
||||
local file = tar:read("*l")
|
||||
if not file then
|
||||
break
|
||||
elseif file:match("^(.*\/dnscrypt.proxy)$") then
|
||||
files[#files+1] = file
|
||||
end
|
||||
end
|
||||
tar:close()
|
||||
end
|
||||
|
||||
if #files == 0 then
|
||||
return {500, "Internal Server Error", stype, sarch}
|
||||
end
|
||||
|
||||
|
||||
local output = { }
|
||||
|
||||
exec("/usr/sbin/dnscrypt-proxy", {"-service", "stop" })
|
||||
exec("/bin/mkdir", { "-p", dir })
|
||||
|
||||
exec("/bin/tar", { "-C", dir, "-vxzf", tmp, unpack(files) },
|
||||
function(chunk) output[#output+1] = chunk:match("%S+") end)
|
||||
|
||||
exec("/bin/cp", { "-f", dir .. "/" .. files[1], "/usr/sbin/dnscrypt-proxy"})
|
||||
exec("/bin/rm", { "-f", "%s/%s-%s/dnscrypt-proxy" % {dir, stype, sarch}})
|
||||
exec("/bin/rm", { "-f", tmp })
|
||||
exec("/usr/sbin/dnscrypt-proxy", {"-service", "start" })
|
||||
return out
|
||||
end
|
||||
|
||||
function exec(cmd, args, writer)
|
||||
local os = require "os"
|
||||
local nixio = require "nixio"
|
||||
|
||||
local fdi, fdo = nixio.pipe()
|
||||
local pid = nixio.fork()
|
||||
|
||||
if pid > 0 then
|
||||
fdo:close()
|
||||
|
||||
while true do
|
||||
local buffer = fdi:read(2048)
|
||||
|
||||
if not buffer or #buffer == 0 then
|
||||
break
|
||||
end
|
||||
|
||||
if writer then
|
||||
writer(buffer)
|
||||
end
|
||||
end
|
||||
|
||||
nixio.waitpid(pid)
|
||||
elseif pid == 0 then
|
||||
nixio.dup(fdo, nixio.stdout)
|
||||
fdi:close()
|
||||
fdo:close()
|
||||
nixio.exece(cmd, args, nil)
|
||||
nixio.stdout:close()
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,454 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "Enable"
|
||||
msgstr "启用"
|
||||
|
||||
msgid "Disable"
|
||||
msgstr "停用"
|
||||
|
||||
msgid "Log"
|
||||
msgstr "日志"
|
||||
|
||||
msgid "Servers Setting"
|
||||
msgstr "服务器配置"
|
||||
|
||||
msgid "Alias(optional)"
|
||||
msgstr "别名(可选)"
|
||||
|
||||
msgid "Server Address"
|
||||
msgstr "服务器地址"
|
||||
|
||||
msgid "Server Port"
|
||||
msgstr "服务器端口"
|
||||
|
||||
msgid "Local Port"
|
||||
msgstr "本地端口"
|
||||
|
||||
msgid "Protocol"
|
||||
msgstr "传输协议"
|
||||
|
||||
msgid "Access Control"
|
||||
msgstr "访问控制"
|
||||
|
||||
msgid "Enable Server"
|
||||
msgstr "启动服务端"
|
||||
|
||||
msgid "Server Setting"
|
||||
msgstr "服务端配置"
|
||||
|
||||
msgid "Edit DNSCrypt Server"
|
||||
msgstr "编辑服务器配置"
|
||||
|
||||
msgid "Alias"
|
||||
msgstr "别名"
|
||||
|
||||
msgid "Server"
|
||||
msgstr "服务器"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
msgid "Running Status"
|
||||
msgstr "运行状态"
|
||||
|
||||
msgid "Not exist"
|
||||
msgstr "未安装可执行文件"
|
||||
|
||||
msgid "Not Running"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "No Check"
|
||||
msgstr "未检查"
|
||||
|
||||
msgid "Check"
|
||||
msgstr "检查"
|
||||
|
||||
msgid "Connect OK"
|
||||
msgstr "连接正常"
|
||||
|
||||
msgid "Connect Error"
|
||||
msgstr "连接错误"
|
||||
|
||||
msgid "Check..."
|
||||
msgstr "正在检查.."
|
||||
|
||||
msgid "Proxy Check"
|
||||
msgstr "代理检查"
|
||||
|
||||
msgid "Records"
|
||||
msgstr "条记录"
|
||||
|
||||
msgid "Refresh Data"
|
||||
msgstr "更新数据库"
|
||||
|
||||
msgid "Refresh..."
|
||||
msgstr "正在更新,请稍候.."
|
||||
|
||||
msgid "Refresh OK!"
|
||||
msgstr "更新成功!"
|
||||
|
||||
msgid "Refresh Error!"
|
||||
msgstr "更新失败!"
|
||||
|
||||
msgid "No new data!"
|
||||
msgstr "你已经是最新数据,无需更新!"
|
||||
|
||||
msgid "Total Records:"
|
||||
msgstr "新的总纪录数:"
|
||||
|
||||
msgid "Check Server"
|
||||
msgstr "检查服务器"
|
||||
|
||||
msgid "Servers Manage"
|
||||
msgstr "服务器管理"
|
||||
|
||||
msgid "Update"
|
||||
msgstr "更新"
|
||||
|
||||
msgid "Server Count"
|
||||
msgstr "服务器节点数量"
|
||||
|
||||
msgid "Severs Nodes"
|
||||
msgstr "服务器节点"
|
||||
|
||||
msgid "Server Node Type"
|
||||
msgstr "服务器节点类型"
|
||||
|
||||
msgid "DNSCrypt Resolvers"
|
||||
msgstr "订阅列表"
|
||||
|
||||
msgid "DNSCrypt Proxy Settings"
|
||||
msgstr "DNSCrypt代理设置"
|
||||
|
||||
msgid "Proxy Setting"
|
||||
msgstr "代理设置"
|
||||
|
||||
msgid "DNSCrypt Proxy"
|
||||
msgstr "DNSCrypt代理"
|
||||
|
||||
msgid "DNSCrypt Proxy binary not found."
|
||||
msgstr "未发现DNSCrypt代理应用。"
|
||||
|
||||
msgid "Binary Management"
|
||||
msgstr "应用管理"
|
||||
|
||||
msgid "Binary update"
|
||||
msgstr "应用更新 "
|
||||
|
||||
msgid "Current version:"
|
||||
msgstr "当前版本:"
|
||||
|
||||
msgid "Version2 atleast:"
|
||||
msgstr "至少应为第2版:"
|
||||
|
||||
msgid "Update to final release from:"
|
||||
msgstr "更新到最新正式版本:"
|
||||
|
||||
msgid "Force Reload"
|
||||
msgstr "强制重启"
|
||||
|
||||
msgid "Proxy force reload,"
|
||||
msgstr "强制重启代理:"
|
||||
|
||||
msgid "DNS resolve test"
|
||||
msgstr "DNS解析测试"
|
||||
|
||||
msgid "Cache Management"
|
||||
msgstr "缓存文件"
|
||||
|
||||
msgid "Running resolver details and offline caches manipulating."
|
||||
msgstr "节点详情和订阅的离线缓存文件控制。"
|
||||
|
||||
msgid "Dump Details"
|
||||
msgstr "调取详情"
|
||||
|
||||
msgid "Dump DNSCrypt resolver details to cache file:"
|
||||
msgstr "从代理实例调取节点详情到文件缓存:"
|
||||
|
||||
msgid "JSON dumped"
|
||||
msgstr "详情JSON已保存 "
|
||||
|
||||
msgid "Remove cache files"
|
||||
msgstr "删除缓存文件"
|
||||
|
||||
msgid "files"
|
||||
msgstr "文件"
|
||||
|
||||
msgid "Remove cached resolvers info from:"
|
||||
msgstr "删除所有订阅的缓存:"
|
||||
|
||||
msgid "Resolver cache"
|
||||
msgstr "订阅缓存 "
|
||||
|
||||
msgid "Listening address"
|
||||
msgstr "监听地址"
|
||||
|
||||
msgid "Enabled Resolvers"
|
||||
msgstr "订阅列表"
|
||||
|
||||
msgid "Fallback resolvers"
|
||||
msgstr "备用DNS"
|
||||
|
||||
msgid "DNS resolver on query fails or for forced forwarding domain list."
|
||||
msgstr "用于解析DNSCrypt解析失败时,及强制转发名单里的域名。"
|
||||
|
||||
msgid "Resolver White List"
|
||||
msgstr "节点白名单"
|
||||
|
||||
msgid "Resolver white list by name, Allow *ALL* in default."
|
||||
msgstr "默认允许所有订阅内任意节点名的节点。"
|
||||
|
||||
msgid "Resolver Black List"
|
||||
msgstr "节点黑名单"
|
||||
|
||||
msgid "Resolver black list by name, disable specified resolver."
|
||||
msgstr "不连接节点名在此名单内的节点。"
|
||||
|
||||
msgid "Forwarding2Fallback"
|
||||
msgstr "强制转发名单"
|
||||
|
||||
msgid "Domains forced to fallback resolver, [.conf] file treat like dnsmasq configure."
|
||||
msgstr "强制由备用DNS解析的名单,可处理dnsmasq的配置文件[.conf]。"
|
||||
|
||||
msgid "Domain Black List"
|
||||
msgstr "域名黑名单"
|
||||
|
||||
msgid "Domains to blacklist, [.conf|.adblock] file treat like dnsmasq configure:"
|
||||
msgstr "拒绝解析的域名表,可处理dnsmasq及adbyby的配置文件[.conf|.adblock]:"
|
||||
|
||||
msgid "IP Address List"
|
||||
msgstr "IP黑名单"
|
||||
|
||||
msgid "IP Address to blacklist, [.conf] file treat like dnsmasq configure:"
|
||||
msgstr "拒绝解析的IP名单,可处理dnsmasq的配置文件[.conf]:"
|
||||
|
||||
msgid "Net probe address"
|
||||
msgstr "找网DNS"
|
||||
|
||||
msgid "Resolver on downloading resolver lists file."
|
||||
msgstr "用于解析订阅地址的DNS。"
|
||||
|
||||
msgid "Force Options"
|
||||
msgstr "强制选项"
|
||||
|
||||
msgid "ignore_system_dns"
|
||||
msgstr "忽略系统DNS"
|
||||
|
||||
msgid "ipv4_servers"
|
||||
msgstr "连IPv4类型"
|
||||
|
||||
msgid "ipv6_servers"
|
||||
msgstr "连IPv6类型"
|
||||
|
||||
msgid "block_ipv6"
|
||||
msgstr "立即空答IPv6"
|
||||
|
||||
msgid "dnscrypt_servers"
|
||||
msgstr "连DNSCrypt类型"
|
||||
|
||||
msgid "doh_servers"
|
||||
msgstr "连DoH类型"
|
||||
|
||||
msgid "require_dnssec"
|
||||
msgstr "DNSSEC验证"
|
||||
|
||||
msgid "force_tcp"
|
||||
msgstr "只用TCP查询"
|
||||
|
||||
msgid "require_nolog"
|
||||
msgstr "无记录验证"
|
||||
|
||||
msgid "require_nofilter"
|
||||
msgstr "无过滤验证"
|
||||
|
||||
msgid "cache"
|
||||
msgstr "缓存结果"
|
||||
|
||||
msgid "offline_mode"
|
||||
msgstr "离线模式"
|
||||
|
||||
msgid "use_syslog"
|
||||
msgstr "系统LOG"
|
||||
|
||||
msgid "dnscrypt_ephemeral_keys"
|
||||
msgstr "不停刷新钥匙"
|
||||
|
||||
msgid "cert_ignore_timestamp"
|
||||
msgstr "忽略证书时间戳"
|
||||
|
||||
msgid "tls_disable_session_tickets"
|
||||
msgstr "TLS握手不缓存"
|
||||
|
||||
msgid "lb_estimator"
|
||||
msgstr "节点监测"
|
||||
|
||||
msgid "Response for blocked queries."
|
||||
msgstr "拒绝时回应"
|
||||
|
||||
msgid "Load-balancing strategy"
|
||||
msgstr "负载均衡模式"
|
||||
|
||||
msgid "Items forced for checking, will show your the defaults when unchecked all."
|
||||
msgstr "DNSCrypt节点过滤和其它设置项,清空后会显示为默认。"
|
||||
|
||||
msgid "Static Stamp"
|
||||
msgstr "静态戳记"
|
||||
|
||||
msgid "Mostly useful for testing your own servers."
|
||||
msgstr "主要用来测试自建DNSCrypt服务器。"
|
||||
|
||||
msgid "One or more requred configure is missing!"
|
||||
msgstr "至少需要1个正确配置并更新的订阅!"
|
||||
|
||||
msgid "Address filter list(ipset)"
|
||||
msgstr "节点地址过滤(ipset)"
|
||||
|
||||
msgid "The ipset list name that DNSCrypt server addresses try appending to if any."
|
||||
msgstr "向使用中的 ipset 列表追加过滤出来的DNSCrypt 节点地址。"
|
||||
|
||||
msgid "Follwing available one (auto)"
|
||||
msgstr "检测已知 (auto)"
|
||||
|
||||
msgid "PassWall direct (vpsiplist)"
|
||||
msgstr "PassWall 直走(vpsiplist)"
|
||||
|
||||
msgid "Clash direct (localnetwork)"
|
||||
msgstr "Clash 直走(localnetwork)"
|
||||
|
||||
msgid "SSR-Plus direct (ss_spec_wan_ac)"
|
||||
msgstr "SSR+ 直走(ss_spec_wan_ac)"
|
||||
|
||||
msgid "Total %d records."
|
||||
msgstr "总计 %d 条记录。"
|
||||
|
||||
msgid "Resolvers"
|
||||
msgstr "订阅"
|
||||
|
||||
msgid "Available Resolvers:"
|
||||
msgstr "已知节点:"
|
||||
|
||||
msgid "DNSCrypt Resolver Info"
|
||||
msgstr "DNSCrypt节点信息"
|
||||
|
||||
msgid "Trash Resolver Info"
|
||||
msgstr "清空节点信息"
|
||||
|
||||
msgid "DNS Forward"
|
||||
msgstr " DNS转发"
|
||||
|
||||
msgid "DNS Forward resolve test"
|
||||
msgstr "DNS转发检查"
|
||||
|
||||
msgid "Check DNSCrypt resolver:"
|
||||
msgstr "检测DNS服务器:"
|
||||
|
||||
msgid "Resolver ACL"
|
||||
msgstr "节点流控"
|
||||
|
||||
msgid "ACL Setting"
|
||||
msgstr "流控设置"
|
||||
|
||||
msgid "DNSCrypt Resolver ACL"
|
||||
msgstr "DNSCrypt节点流控"
|
||||
|
||||
msgid "DNSCrypt will automatically pick the fastest, working servers from the list<br />All or filtered out addresses are prepared for 'Address filter list(ipset)'.<br />Resolver with detailed addresses is a must."
|
||||
msgstr "DNSCrypt 会自动选择最快的有效服务器。<br />所有已知或过滤出来的地址将用于 '节点地址过滤(ipset)' <br />只有存在详细地址的节点才能添加进来。"
|
||||
|
||||
msgid "DNS Resolver Filter"
|
||||
msgstr "节点篩选器"
|
||||
|
||||
msgid "Resolver"
|
||||
msgstr "解析服务器"
|
||||
|
||||
msgid "Stamp"
|
||||
msgstr "戳记"
|
||||
|
||||
msgid "more than 100, try filter out to show details..."
|
||||
msgstr "多于100条,请进一步篩选以显示节点详情。"
|
||||
|
||||
msgid "Choose a resolver to configure"
|
||||
msgstr "请选择一个订阅来配置"
|
||||
|
||||
msgid "Input the name to re-configure, if your resolvers not updated correctly and not showns up."
|
||||
msgstr "如果你的订阅没有出现在列表里(或未能正确更新),请手动输入订阅名字新增(或重新)订阅。"
|
||||
|
||||
msgid "Update the resolvers here by a new apply. Permently cover your modifications on specific resolve, if the source resolved successfully."
|
||||
msgstr "在此应用借以更新订阅。如订阅成功,将重建此订阅中所有节点信息。"
|
||||
|
||||
msgid "Not a typical dnscrypt-proxy resolvers configure!"
|
||||
msgstr "非典型的DNSCrypt代理订阅配置!"
|
||||
|
||||
msgid "Additional changes on apply:"
|
||||
msgstr "点应用后,将会产生如下附加配置的修改:"
|
||||
|
||||
msgid "Change this only on duplicating this resolver to another source when retrieving:"
|
||||
msgstr "修改此值并更新,借以新增自定订阅:"
|
||||
|
||||
msgid "Cache File"
|
||||
msgstr "缓存"
|
||||
|
||||
msgid "Details File URL"
|
||||
msgstr "节点详情"
|
||||
|
||||
msgid "Detailed resolvers JSON file `dnscrypt-proxy -json --list-all` or:"
|
||||
msgstr "有关节点情细情况的JSON文件,可在启动后手动执行`dnscrypt-proxy -json --list-all`来抓取,或:"
|
||||
|
||||
msgid "DNSCrypt Resolvers Manage"
|
||||
msgstr "DNSCrypt订阅管理"
|
||||
|
||||
msgid "Update the resolvers here by a new apply."
|
||||
msgstr "应用时会自动检查并更新订阅。"
|
||||
|
||||
msgid "DNSCrypt Resolver Editing -"
|
||||
msgstr "DNSCrypt节点编辑 - "
|
||||
|
||||
msgid "Source URL"
|
||||
msgstr "订阅地址"
|
||||
|
||||
msgid "Split MultiValues by a comma"
|
||||
msgstr "多个值以英文逗号分隔"
|
||||
|
||||
msgid "MiniSign Key"
|
||||
msgstr "Mini验证"
|
||||
|
||||
msgid "Resolvers singed by:"
|
||||
msgstr "订阅源签名公钥:"
|
||||
|
||||
msgid "No resolvers update."
|
||||
msgstr "离线模式"
|
||||
|
||||
msgid "Force cached resolvers only:"
|
||||
msgstr "使用缓存文件,主要用来解决在订阅源无法正常获取时,DNSCrypt代理启动失败的状况:"
|
||||
|
||||
msgid "Selfsign Resolvers"
|
||||
msgstr "自签订阅"
|
||||
|
||||
msgid "Mostly useful for build your own resolvers list on net probe fails. minisign binary needed:"
|
||||
msgstr "主要用于自定义的服务器订阅,需要安装minisign应用:"
|
||||
|
||||
msgid "Choose a file from the list to read."
|
||||
msgstr "请从列表选择文件来查看。"
|
||||
|
||||
msgid "File Viewer"
|
||||
msgstr "文件查看器"
|
||||
|
||||
msgid "Read / Reread log file"
|
||||
msgstr "读取/重新读取"
|
||||
|
||||
msgid "Please press [Read] button"
|
||||
msgstr "请点读取按钮"
|
||||
|
||||
msgid "File not found or empty"
|
||||
msgstr "文件未找到或为空"
|
||||
|
||||
msgid "No files found"
|
||||
msgstr "文件未找到"
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
-- Copyright (C) 2019 github.com/peter-tank
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local disp = require "luci.dispatcher"
|
||||
local m, _, s, o
|
||||
local cfg="dnscrypt-proxy"
|
||||
|
||||
m = Map(cfg, "%s - %s" %{translate("DNSCrypt Proxy"),
|
||||
translate("ACL Setting")})
|
||||
|
||||
-- [[ ACL Setting ]]--
|
||||
s = m:section(TypedSection, "server_addr", translate("DNSCrypt Resolver ACL"), translate("DNSCrypt will automatically pick the fastest, working servers from the list<br />All or filtered out addresses are prepared for 'Address filter list(ipset)'.<br />Resolver with detailed addresses is a must.") .. " https://dnscrypt.info/stamps/")
|
||||
s.sectionhead = translate("Alias")
|
||||
s.template = "cbi/tblsection"
|
||||
s.addremove = true
|
||||
s.anonymous = true
|
||||
s.sortable = false
|
||||
s.template_addremove = "dnscrypt-proxy/cbi_addserver"
|
||||
|
||||
function s.create(self, section)
|
||||
local a = m:formvalue("_newsrv.alias")
|
||||
local c = m:formvalue("_newsrv.country")
|
||||
local n = m:formvalue("_newsrv.name")
|
||||
local ad = m:formvalue("_newsrv.addrs")
|
||||
local po = m:formvalue("_newsrv.ports")
|
||||
local pr = m:formvalue("_newsrv.proto")
|
||||
local st = m:formvalue("_newsrv.stamp")
|
||||
|
||||
created = nil
|
||||
if a ~= "" and n ~= "" and ad ~= "" and st ~= "" then
|
||||
created = TypedSection.create(self, section)
|
||||
|
||||
self.map:set(created, "alias", a)
|
||||
self.map:set(created, "country", c or "Unknown")
|
||||
self.map:set(created, "name", n or "Custom")
|
||||
self.map:set(created, "addrs", ad)
|
||||
self.map:set(created, "ports", po or "ALL")
|
||||
self.map:set(created, "proto", pr or "Unknown")
|
||||
self.map:set(created, "stamp", st or "Error")
|
||||
end
|
||||
end
|
||||
|
||||
function s.parse(self, ...)
|
||||
TypedSection.parse(self, ...)
|
||||
if created then
|
||||
m.uci:save("dnscrypt-proxy")
|
||||
luci.http.redirect(disp.build_url("admin", "services", "dnscrypt-proxy", "dnscrypt-proxy-acl"))
|
||||
end
|
||||
end
|
||||
|
||||
s:option(DummyValue,"alias",translate("Alias"))
|
||||
s:option(DummyValue,"country",translate("Country"))
|
||||
s:option(DummyValue,"proto",translate("Protocol"))
|
||||
s:option(DummyValue,"name",translate("Resolver"))
|
||||
s:option(DummyValue,"addrs",translate("Address"))
|
||||
s:option(DummyValue,"ports",translate("Server Port"))
|
||||
s:option(DummyValue,"stamp",translate("Stamp"))
|
||||
|
||||
return m
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
-- Copyright (C) 2019 github.com/peter-tank
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local m, _, s, o
|
||||
local dc = require "luci.tools.dnscrypt".init()
|
||||
local resolvers = dc:resolvers_list(true)
|
||||
local cfg = "dnscrypt-proxy"
|
||||
|
||||
m = Map(cfg, "%s - %s" %{translate("DNSCrypt Proxy"), translate("Proxy Setting")})
|
||||
|
||||
-- [[ Proxy Setting ]]--
|
||||
local type = "dnscrypt-proxy"
|
||||
s = m:section(TypedSection, type)
|
||||
s.anonymous = false
|
||||
-- section might not exist
|
||||
function s.cfgvalue(self, section)
|
||||
if not self.map:get(section) then
|
||||
self.map:set(section, nil, self.sectiontype)
|
||||
self.map:set(section, "resolvers", {"public-resolvers", "opennic"})
|
||||
end
|
||||
return self.map:get(section)
|
||||
end
|
||||
|
||||
o = s:option(Flag, "enable", translate("Enable"))
|
||||
o.default = false
|
||||
o.optional = false
|
||||
|
||||
o = s:option(Value, "listen_addresses", translate("Listening address"), translate("Split MultiValues by a comma"))
|
||||
o.default = "127.0.0.1:5335"
|
||||
o.placeholder = o.default
|
||||
o.optional = false
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "netprobe_address", translate("Net probe address"), translate("Resolver on downloading resolver lists file."))
|
||||
o.default = "114.114.114.114:53"
|
||||
o.placeholder = o.default
|
||||
o.optional = false
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "bootstrap_resolvers", translate("Fallback resolvers"), translate("DNS resolver on query fails or for forced forwarding domain list.") .. translate("Split MultiValues by a comma"))
|
||||
o.default = "114.114.114.114:53"
|
||||
o.placeholder = o.default
|
||||
o.optional = false
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(DynamicList, "resolvers", translate("Enabled Resolvers"), translate("Available Resolvers: ") .. "https://download.dnscrypt.info/dnscrypt-resolvers/v2/{*}.md")
|
||||
local opt, val
|
||||
for _, val in ipairs(resolvers) do
|
||||
opt = luci.util.split(val, "|")[1]
|
||||
o:value(opt, translate(opt))
|
||||
end
|
||||
o.optional = false
|
||||
o.rmempty = false
|
||||
o.placeholder = "onion-services"
|
||||
|
||||
o = s:option(MultiValue, "force", translate("Force Options"), translate("Items forced for checking, will show your the defaults when unchecked all."))
|
||||
o.optional = false
|
||||
o.widget = "select"
|
||||
o.force_defaults = {
|
||||
["lb_estimator"] = "true",
|
||||
["ignore_system_dns"] = "true",
|
||||
["block_unqualified"] = "true",
|
||||
["block_undelegated"] = "true",
|
||||
["ipv4_servers"] = "true",
|
||||
["ipv6_servers"] = "false",
|
||||
["block_ipv6"] = "true",
|
||||
["dnscrypt_servers"] = "true",
|
||||
["doh_servers"] = "true",
|
||||
["require_dnssec"] = "false",
|
||||
["force_tcp"] = "false",
|
||||
["require_nolog"] = "true",
|
||||
["require_nofilter"] = "true",
|
||||
["cache"] = "true",
|
||||
["offline_mode"] = "false",
|
||||
["dnscrypt_ephemeral_keys"] = "false",
|
||||
["tls_disable_session_tickets"] = "false",
|
||||
["cert_ignore_timestamp"] = "true",
|
||||
["use_syslog"] = "false",
|
||||
}
|
||||
for k, v in pairs(o.force_defaults) do o:value(k, translate(k)) end
|
||||
o.cfgvalue = function (self, section)
|
||||
local ret, k, d
|
||||
ret = Value.cfgvalue(self, section)
|
||||
if ret then return ret end
|
||||
ret = ""
|
||||
for k, d in pairs(self.force_defaults) do
|
||||
if d == "true" then
|
||||
ret = ret .. self.delimiter .. k
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
o = s:option(ListValue, "log_level", translate("Log output level"))
|
||||
o:value(0, translate("Debug"))
|
||||
o:value(1, translate("Info"))
|
||||
o:value(2, translate("Notice"))
|
||||
o:value(3, translate("Warning"))
|
||||
o:value(4, translate("Error"))
|
||||
o:value(5, translate("Critical"))
|
||||
o:value(6, translate("Fatal"))
|
||||
o.default = 2
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(ListValue, "blocked_query_response", translate("Response for blocked queries."))
|
||||
o:value("refused", translate("refused"))
|
||||
o:value("hinfo", translate("hinfo"))
|
||||
o.default = "hinfo"
|
||||
o.placeholder = "eg: a:<IPv4>,aaaa:<IPv6>"
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(ListValue, "lb_strategy", translate("Load-balancing strategy"))
|
||||
o:value("p2", translate("p2"))
|
||||
o:value("ph", translate("ph"))
|
||||
o:value("first", translate("first"))
|
||||
o:value("random", translate("random"))
|
||||
o.default = "p2"
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(DynamicList, "forwarding_rules", translate("Forwarding2Fallback"), translate("Domains forced to fallback resolver, [.conf] file treat like dnsmasq configure."))
|
||||
o.default = "/etc/dnsmasq.oversea/oversea_list.conf"
|
||||
o.placeholder = "/etc/dnsmasq.oversea/oversea_list.conf"
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(DynamicList, "blocked_named", translate("Domain Black List"), translate("Domains to blacklist, [.conf|.adblock] file treat like dnsmasq configure: ") .. "https://download.dnscrypt.info/blacklists/domains/mybase.txt")
|
||||
o.default = "/etc/dnsmasq.ssr/ad.conf"
|
||||
o.placeholder = "/usr/share/adbyby/dnsmasq.adblock"
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(DynamicList, "blocked_ips", translate("IP Address List"), translate("IP Address to blacklist, [.conf] file treat like dnsmasq configure: ") .. "https://download.dnscrypt.info/blacklists/ips/mybase.txt")
|
||||
o.default = "https://download.dnscrypt.info/blacklists/domains/mybase.txt"
|
||||
o.placeholder = "/etc/dnsmasq.ssr/ad.conf"
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(DynamicList, "static", translate("Static Stamp"), translate("Mostly useful for testing your own servers."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.placeholder = "eg: sdns:AQcAAAAAAAAAAAAQMi5kbnNjcnlwdC1jZXJ0Lg"
|
||||
|
||||
o = s:option(Value, "server_names", translate("Resolver White List"), "%s %s" % {translate("Resolver white list by name, Allow *ALL* in default."), translate("Split MultiValues by a comma")})
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.placeholder = "eg: goodguy1,goodguy2"
|
||||
|
||||
o = s:option(Value, "disabled_server_names", translate("Resolver Black List"), "%s %s" % {translate("Resolver black list by name, disable specified resolver."), translate("Split MultiValues by a comma")})
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.placeholder = "eg: badguy1,badguy2"
|
||||
|
||||
o = s:option(Value, "max_clients", translate("Simulaneous"), translate("Maximum number of simultaneous client connections to accept."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.datatype = "uinteger"
|
||||
o.default = 500
|
||||
o.placeholder = o.default
|
||||
|
||||
o = s:option(Value, "keepalive", translate("Keep Alive"), translate("Keepalive for HTTP (HTTPS, HTTP/2) queries, in seconds."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.datatype = "uinteger"
|
||||
o.default = 30
|
||||
o.placeholder = o.default
|
||||
|
||||
o = s:option(Value, "cert_refresh_delay", translate("Cert refresh delay"), translate("Delay, in minutes, after which certificates are reloaded."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.datatype = "uinteger"
|
||||
o.default = 240
|
||||
o.placeholder = o.default
|
||||
|
||||
o = s:option(Value, "netprobe_timeout", translate("Net probe timer"), translate("Maximum time (in seconds) to wait for network connectivity before initializing the proxy."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.datatype = "uinteger"
|
||||
o.default = 60
|
||||
o.placeholder = o.default
|
||||
|
||||
o = s:option(Value, "reject_ttl", translate("Reject TTL"), translate("TTL for synthetic responses sent when a request has been blocked (due to IPv6 or blacklists)."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.datatype = "uinteger"
|
||||
o.default = 60
|
||||
o.placeholder = o.default
|
||||
|
||||
o = s:option(Value, "cache_size", translate("Cache size"), translate("Cache size for queries."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.datatype = "uinteger"
|
||||
o.default = 512
|
||||
o.placeholder = o.default
|
||||
|
||||
o = s:option(Value, "query_meta", translate("Additional TXT records"), translate("Additional data to attach to outgoing queries.") .. [[<br />]] .. translate("Split MultiValues by a comma"))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.placeholder = "eg: key1:value1,key2:value2"
|
||||
|
||||
o = s:option(Value, "proxy", translate("SOCKS proxy"), translate("Tor doesn't support UDP, so set `force_tcp` to `true` as well."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.placeholder = "eg: socks5://127.0.0.1:9050"
|
||||
|
||||
o = s:option(Value, "http_proxy", translate("HTTP/HTTPS proxy"), translate("Only for DoH servers."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.placeholder = "eg: http://127.0.0.1:8888"
|
||||
|
||||
o = s:option(DynamicList, "cloaking_rules", translate("Cloaking rules"), translate("Cloaking returns a predefined address for a specific name."))
|
||||
o.optional = true
|
||||
o.rmempty = true
|
||||
o.placeholder = "eg: /usr/share/dnscrypt-proxy/cloaking-rules.txt"
|
||||
|
||||
o = s:option(Value, "addr_filter", translate("Address filter list(ipset)"), translate("The ipset list name that DNSCrypt server addresses try appending to if any."))
|
||||
o:value("auto", translate("Follwing available one (auto)"))
|
||||
o:value("vpsiplist", translate("PassWall direct (vpsiplist)"))
|
||||
o:value("localnetwork", translate("Clash direct (localnetwork)"))
|
||||
o:value("ss_spec_wan_ac", translate("SSR-Plus direct (ss_spec_wan_ac)"))
|
||||
o.optional = false
|
||||
o.rmempty = true
|
||||
o.default = "auto"
|
||||
o.placeholder = "e.g.: gfwlist"
|
||||
|
||||
return m
|
||||
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
-- Copyright (C) 2019 github.com/peter-tank
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local m, s, o, _, v, created
|
||||
local fs = require "nixio.fs"
|
||||
local sys = require "luci.sys"
|
||||
local ds = require "luci.tools.dnscrypt".init()
|
||||
local cfg, sid = arg[1], arg[2]
|
||||
|
||||
local protocol = {
|
||||
"DNSCrypt",
|
||||
"DoH",
|
||||
}
|
||||
|
||||
function typicalmsg(self)
|
||||
if not ds:typicalcfg(cfg) then
|
||||
local c, init, exec = luci.model.uci.cursor()
|
||||
c:load("ucitrack")
|
||||
init = c:get_first("ucitrack", self.config, "init", "null")
|
||||
exec = c:get_first("ucitrack", self.config, "exec", "null")
|
||||
c:unload("ucitrack")
|
||||
local error = {}
|
||||
table.insert(error, translate("Not a typical dnscrypt-proxy resolvers configure!") .. " Original for: [%s]" % init)
|
||||
table.insert(error, translate("Additional changes on apply:"))
|
||||
table.insert(error, "init script: %s --> %s" % {init, "null"})
|
||||
table.insert(error, "exec script: %s --> %s %s" % {exec, "/etc/init.d/dnscrypt-proxy_resolvers", self.config})
|
||||
self.error = self.error and self.error or {}
|
||||
self.error["global"] = self.error["global"] and table(self.error["global"], error) or error
|
||||
end
|
||||
end
|
||||
|
||||
function list_dns(m, cfg)
|
||||
-- [[ Source Setting ]]--
|
||||
s = m:section(NamedSection, "global", "source", translate("Configuration -: ") .. cfg)
|
||||
s.description = translate("Update the resolvers here by a new apply. Permently cover your modifications on specific resolve, if the source resolved successfully.")
|
||||
s.anonymous = false
|
||||
s.addremove = true
|
||||
typicalmsg(s)
|
||||
-- section might not exist
|
||||
function s.cfgvalue(self, section)
|
||||
if not self.map:get(section) then
|
||||
self.map:set(section, nil, self.sectiontype)
|
||||
end
|
||||
return self.map:get(section)
|
||||
end
|
||||
function s.remove(self, section)
|
||||
self.map:del(section)
|
||||
self.map.proceed = true
|
||||
return self.map.uci:delete_all(self.config, "dnscrypt", function(section) return true end)
|
||||
end
|
||||
|
||||
o = s:option(Value, "urls", translate("Source URL"), translate("Split MultiValues by a comma"))
|
||||
o.rmempty = true
|
||||
o.default = "https://download.dnscrypt.info/dnscrypt-resolvers/v3/public-resolvers.md"
|
||||
o.placeholder = "https://xxx.xxx.xxx/public-resolvers.md"
|
||||
|
||||
--o = s:option(Value, "cache_file", translate("Cache File"), translate("Change this only on duplicating this resolver to another source when retrieving: ") .. "/usr/share/dnscrypt-proxy/{*}.md")
|
||||
--o.default = "public-resolvers.md"
|
||||
--o.placeholder = "eg: custom.md"
|
||||
--o.rmempty = false
|
||||
|
||||
o = s:option(Value, "details_json", translate("Details File URL"), translate("Detailed resolvers JSON file `dnscrypt-proxy -json --list-all` or: ") .. "https://download.dnscrypt.info/dnscrypt-resolvers/json/{*}.json")
|
||||
o.default = "https://download.dnscrypt.info/dnscrypt-resolvers/json/public-resolvers.json"
|
||||
o.placeholder = "eg: custom.json"
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Flag, "cache_mode", translate("No resolvers update."), translate("Force cached resolvers only: ").. "/usr/share/dnscrypt-proxy/{.*}[.md|.minisig|.json]")
|
||||
o.default = true
|
||||
o.optional = false
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "selfsign", translate("Selfsign Resolvers"), translate("Mostly useful for build your own resolvers list on net probe fails. minisign binary needed: ") .. "https://github.com/peter-tank/openwrt-minisign")
|
||||
o.default = false
|
||||
o.optional = false
|
||||
o.rmempty = true
|
||||
o:depends("cache_mode", true)
|
||||
|
||||
o = s:option(Value, "minisign_key", translate("MiniSign Key"), translate("Resolvers singed by: ") .. "https://download.dnscrypt.info/dnscrypt-resolvers/v3/minisign.pub")
|
||||
o.default = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3"
|
||||
o.optional = false
|
||||
o.placeholder = o.default
|
||||
o.rmempty = false
|
||||
o:depends("selfsign", false)
|
||||
|
||||
o = s:option(Value, "prefix", translate("Prefix"), translate("Change this only on filtering the resolvers: "))
|
||||
o.optional = true
|
||||
o.placeholder = "eg: quad9-"
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "format", translate("Version"), translate("Configure file version."))
|
||||
o.optional = true
|
||||
o.default = "v3"
|
||||
o.rmempty = true
|
||||
|
||||
s = m:section(TypedSection, 'dnscrypt', translate("DNSCrypt Resolver Info"))
|
||||
s.anonymous = false
|
||||
s.addremove = true
|
||||
s.sortable = false
|
||||
s.template = "cbi/tblsection"
|
||||
s.extedit = luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers", cfg, "%s")
|
||||
function s.create(self, name)
|
||||
AbstractSection.create(self, name)
|
||||
luci.http.redirect( self.extedit:format(name) )
|
||||
end
|
||||
|
||||
s:option(DummyValue, "country", translate("Country"))
|
||||
s:option(DummyValue, "proto", translate("Protocol"))
|
||||
s:option(DummyValue, "name", translate("Resolver"))
|
||||
s:option(DummyValue, "description", translate("Description"))
|
||||
s:option(Flag, "ipv6", translate("IPv6"))
|
||||
s:option(Flag, "dnssec", translate("DNSSec Validation"))
|
||||
s:option(Flag, "nolog", translate("NoLog"))
|
||||
s:option(Flag, "nofilter", translate("NoFilter"))
|
||||
s:option(DummyValue, "addrs", translate("Address"))
|
||||
s:option(DummyValue, "ports", translate("Port"))
|
||||
-- s:option(DummyValue, "stamp", translate("Stamp"))
|
||||
end
|
||||
|
||||
|
||||
-- [[ Servers Setting ]]--
|
||||
function edit_list(m)
|
||||
s = m:section(NamedSection, sid, "dnscrypt", translate("DNSCrypt Resolver Editing - ") .. sid)
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
|
||||
o = s:option(Value, "name", translate("Resolver"))
|
||||
o.default = sid
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "country", translate("Country"))
|
||||
o.default = "China"
|
||||
|
||||
o = s:option(Value, "proto", translate("Protocol"))
|
||||
for _, v in ipairs(protocol) do o:value(v) end
|
||||
o.default = "DNSCrypt"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "description", translate("Description"))
|
||||
o.default = "Dns-over-HTTPS protocol . Non-logging, supports DNSSEC. By https://www.google.com"
|
||||
|
||||
o = s:option(Flag, "dnssec", translate("DNSSec Validation"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "ipv6", translate("IPv6"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "nolog", translate("NoLog"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "nofilter", translate("NoFilter"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "addrs", translate("Resolver Address"), translate("Split MultiValues by a comma"))
|
||||
o.placeholder = "eg: 8.8.8.8,8.8.4.4"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "ports", translate("Port"), translate("Split MultiValues by a comma"))
|
||||
o.placeholder = "eg: 443,5353"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "location", translate("Geography Coordinates"))
|
||||
o.placeholder = "eg: 33.032501, 83.895699"
|
||||
|
||||
o = s:option(Value, "stamp", translate("Stamp"))
|
||||
o.placeholder = "eg: sdns://AgcAAAAAAAAADjExNi4yMDMuNzAuMTU2ID4aGg9sU_PpekktVwhLW5gHBZ7gV6sVBYdv2D_aPbg4EWRvaC5kbnN3YXJkZW4uY29tCy91bmNlbnNvcmVk"
|
||||
o.rmempty = false
|
||||
end
|
||||
|
||||
m = Map(cfg, translate("DNSCrypt Resolvers Manage"))
|
||||
m.on_before_commit = function (self)
|
||||
local exec = "/etc/init.d/dnscrypt-proxy_resolvers"
|
||||
local section, stype, on_remove = "global", "source", false
|
||||
local sec = "DNSCrypt_resolvers_" .. self.config:gsub("[^%w_]", "_")
|
||||
local c = luci.model.uci.cursor()
|
||||
local changes = c:changes()
|
||||
self.redirect = luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers", self.config)
|
||||
for r, tbl in pairs(changes or next(changes)) do
|
||||
for s, os in pairs(tbl) do
|
||||
if os['.type'] and os['.type'] == "" and r == self.config and s == section then on_remove = true end
|
||||
end
|
||||
end
|
||||
c:load("ucitrack")
|
||||
if self:get(section, "urls") and not on_remove then
|
||||
if not c:get_first("ucitrack", self.config, "exec", nil) then
|
||||
c:delete_all("ucitrack", self.config, function(section) return true end)
|
||||
sec = c:section("ucitrack", self.config, sec)
|
||||
c:set("ucitrack", sec, "init", "null")
|
||||
c:set("ucitrack", sec, "test", "0")
|
||||
c:set("ucitrack", sec, "exec", "%s %s" % {exec, self.config})
|
||||
c:save("ucitrack"); c:commit("ucitrack");
|
||||
end
|
||||
else
|
||||
if c:get_first("ucitrack", self.config, "exec", nil) == ("%s %s" %{exec, self.config}) then
|
||||
c:delete_all("ucitrack", self.config, function(section) return true end)
|
||||
c:save("ucitrack"); c:commit("ucitrack");
|
||||
end
|
||||
self.redirect = luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers")
|
||||
end
|
||||
c:unload("ucitrack")
|
||||
luci.util.exec("/etc/init.d/ucitrack reload")
|
||||
end
|
||||
|
||||
if cfg then
|
||||
if sid == nil then list_dns(m, cfg) else edit_list(m, cfg) end
|
||||
else
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers"))
|
||||
return
|
||||
end
|
||||
|
||||
return m
|
||||
@@ -0,0 +1,55 @@
|
||||
-- Copyright (C) 2019 github.com/peter-tank
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local m, _, s, o, id, cfg, src, val, k, v
|
||||
local uci = luci.model.uci.cursor()
|
||||
local dc = require "luci.tools.dnscrypt".init()
|
||||
local resolvers = dc:resolvers_list(true)
|
||||
local disp = require "luci.dispatcher"
|
||||
|
||||
cfg = "dnscrypt-proxy"
|
||||
|
||||
local dnslist_table = {}
|
||||
for _, s in pairs(dc:dns_list()) do
|
||||
if s.addrs ~= nil then
|
||||
dnslist_table[#dnslist_table+1] = "%s.%s:%s@%s://%s:%s" %{s.resolver, s.country, s.name, s.proto, s.addrs, s.ports}
|
||||
end
|
||||
end
|
||||
|
||||
-- [[ Servers Setting ]]--
|
||||
m = Map(cfg, translate("DNSCrypt Resolvers"))
|
||||
m.anonymous = true
|
||||
m.addremove = false
|
||||
m.pageaction = false
|
||||
|
||||
local type = "dnscrypt-proxy"
|
||||
s = m:section(NamedSection, 'ns1', type, translate("Choose a resolver to configure"), translate("Input the name to re-configure, if your resolvers not updated correctly and not showns up."))
|
||||
s.cfgvalue = function(self, section) return resolvers end
|
||||
s.template = "dnscrypt-proxy/cfgselection"
|
||||
s.extedit = luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers", "%s")
|
||||
|
||||
--s = m:section(NamedSection, 'ns1', type, translate("DNSCrypt Resolvers update"))
|
||||
|
||||
o = s:option(TextValue, "_Dummy", translate("DNSCrypt Resolver Info"), translate("Total %d records.") % #dnslist_table)
|
||||
o.rows = 7
|
||||
o.readonly = true
|
||||
o.wrap = "soft"
|
||||
o.cfgvalue = function (self, sec)
|
||||
local ret = translate("Available Resolvers:")
|
||||
for k, v in pairs(dnslist_table) do ret = "%s\n%03d) %s" % {ret, k, v} end
|
||||
return ret
|
||||
end
|
||||
o.write = function (...) end
|
||||
|
||||
o = s:option(Button,"trash", translate("Trash Resolver Info"))
|
||||
o.inputstyle = "reset"
|
||||
o.write = function()
|
||||
local resolver
|
||||
for _, val in pairs(resolvers) do
|
||||
resolver = luci.util.split(val, "|")[1]
|
||||
uci:delete_all(resolver, "dnscrypt", function(s) return true end)
|
||||
uci:save(resolver)
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
||||
@@ -0,0 +1,86 @@
|
||||
-- Copyright (C) 2019 github.com/peter-tank
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local m, _, s, o, id, cfg, src, val, k, v
|
||||
local cfg="dnscrypt-proxy"
|
||||
|
||||
local sys = require "luci.sys"
|
||||
local http = require "luci.http"
|
||||
local disp = require "luci.dispatcher"
|
||||
local fs = require "nixio.fs"
|
||||
local dc = require "luci.tools.dnscrypt".init()
|
||||
local resolvers = dc:resolvers_list(true)
|
||||
|
||||
local caches_list = {}
|
||||
local caches="/usr/share/dnscrypt-proxy/*"
|
||||
for name in (fs.glob(caches) or function() end) do
|
||||
caches_list[#caches_list+1] = name
|
||||
end
|
||||
|
||||
local function has_bin(name)
|
||||
return sys.call("command -v %s >/dev/null" %{name}) == 0
|
||||
end
|
||||
local has_dnscrypt = has_bin("dnscrypt-proxy")
|
||||
|
||||
local bin_version
|
||||
local bin_file="/usr/sbin/dnscrypt-proxy"
|
||||
if not fs.access(bin_file) then
|
||||
bin_version=translate("Not exist")
|
||||
else
|
||||
if not fs.access(bin_file, "rwx", "rx", "rx") then
|
||||
fs.chmod(bin_file, 755)
|
||||
end
|
||||
bin_version=luci.util.trim(luci.sys.exec(bin_file .. " -version"))
|
||||
if not bin_version or bin_version == "" then
|
||||
bin_version = translate("Unknown")
|
||||
end
|
||||
end
|
||||
|
||||
m = Map(cfg, "%s - %s" %{translate("DNSCrypt Proxy"),
|
||||
translate("Overview")})
|
||||
m.pageaction = false
|
||||
|
||||
-- [[ Binary ]]--
|
||||
s = m:section(TypedSection, cfg, translate("Binary Management"), has_dnscrypt and "" or ('<b style="color:red">%s</b>' % translate("DNSCrypt Proxy binary not found.")))
|
||||
s.anonymous = true
|
||||
o = s:option(DummyValue,"dnscrypt_bin", translate("Binary update"))
|
||||
o.rawhtml = true
|
||||
o.template = "dnscrypt-proxy/refresh"
|
||||
o.name = translate("Update")
|
||||
o.ret = bin_version:match('^1%..*') and translate("Version2 atleast: ") or translate("Current version: ")
|
||||
o.value = o.ret .. bin_version
|
||||
o.description = translate("Update to final release from: ") .. "https://github.com/dnscrypt/dnscrypt-proxy/releases"
|
||||
o.write = function (self, ...) end
|
||||
|
||||
o = s:option(Button, "Force Reload", translate("Force Reload"), translate("Proxy force reload, ") .. "/etc/init.d/dnscrypt-proxy reload")
|
||||
o.inputstyle = "reset"
|
||||
o.write = function (self, ...)
|
||||
sys.call("/etc/init.d/dnscrypt-proxy reload >/dev/null 2>&1 &")
|
||||
http.redirect(disp.build_url("admin", "services", "dnscrypt-proxy"))
|
||||
end
|
||||
|
||||
o = s:option(Button, "dnscrypt_ck", translate("DNS resolve test"))
|
||||
o.rawhtml = true
|
||||
o.template = "dnscrypt-proxy/resolve"
|
||||
o.description = translate("Check DNSCrypt resolver: ") .. "/usr/sbin/dnscrypt-proxy -resolve www.google.com,127.0.0.1:7915 -config /var/etc/dnscrypt-proxy-ns1.conf"
|
||||
|
||||
-- [[ Caches ]]--
|
||||
s = m:section(TypedSection, cfg, translate("Cache Management"), translate("Running resolver details and offline caches manipulating."))
|
||||
s.anonymous = true
|
||||
o = s:option(Button,"dump_resolver", translate("Dump Details"))
|
||||
o.rawhtml = true
|
||||
o.template = "dnscrypt-proxy/refresh"
|
||||
o.ret = translate("JSON dumped ")
|
||||
o.value = " %d %s" % {#resolvers, translate("Records")}
|
||||
o.description = translate("Dump DNSCrypt resolver details to cache file: ") .. "dnscrypt-proxy -json --list-all > /usr/share/dnscrypt-proxy/running.json"
|
||||
|
||||
o = s:option(Button, "remove_caches", translate("Remove cache files"))
|
||||
o.rawhtml = true
|
||||
o.template = "dnscrypt-proxy/refresh"
|
||||
o.name = translate("Remove")
|
||||
o.ret = translate("Resolver cache ")
|
||||
o.value = " %d %s" % {#caches_list, translate("files")}
|
||||
o.description = translate("Remove cached resolvers info from: ") .. "/usr/share/dnscrypt-proxy/*"
|
||||
|
||||
return m
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local NXFS = require "nixio.fs"
|
||||
local DISP = require "luci.dispatcher"
|
||||
local HTTP = require "luci.http"
|
||||
local UCI = luci.model.uci.cursor()
|
||||
|
||||
local m = Map("dnscrypt-proxy")
|
||||
m.pageaction=false
|
||||
-- log directory
|
||||
log_dir = UCI:get_first(m.config, "global", "log_dir") or "/tmp"
|
||||
run_dir = UCI:get_first(m.config, "global", "run_dir") or "/var/etc"
|
||||
local logfile_list = {}
|
||||
|
||||
local logfs = {
|
||||
"%s/dnscrypt*" % run_dir,
|
||||
"%s/dnsmasq.*/*.*" % log_dir,
|
||||
"%s/*" % "/usr/share/dnscrypt-proxy",
|
||||
"%s/dnscrypt_*" % log_dir,
|
||||
"%s/*.ld" % log_dir,
|
||||
}
|
||||
local _, dir, ns, lv, lfile
|
||||
for _, dir in pairs(logfs) do
|
||||
for path in (NXFS.glob(dir) or function() end) do
|
||||
logfile_list[#logfile_list+1] = path
|
||||
end
|
||||
end
|
||||
|
||||
ns = m:section(TypedSection, "_dummy", translate("File Viewer"))
|
||||
ns.addremove = false
|
||||
ns.anonymous = true
|
||||
function ns.cfgsections()
|
||||
return{"_exrules"}
|
||||
end
|
||||
|
||||
lv = ns:option(DynamicList, "logfiles")
|
||||
lv.template = "dnscrypt-proxy/logsview"
|
||||
lv.inputtitle = translate("Read / Reread log file")
|
||||
lv.rows = 25
|
||||
lv.default = ""
|
||||
for _, lfile in ipairs(logfile_list) do lv:value(lfile, lfile) end
|
||||
function lv.cfgvalue(self, section)
|
||||
if logfile_list[1] then
|
||||
local lfile=logfile_list[1]
|
||||
if NXFS.access(lfile) then
|
||||
return lfile .. "\n" .. translate("Please press [Read] button")
|
||||
end
|
||||
return lfile .. "\n" .. translate("File not found or empty")
|
||||
else
|
||||
return log_dir .. "\/\n" .. translate("No files found")
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
||||
@@ -0,0 +1,126 @@
|
||||
|
||||
local type, pairs, ipairs, table, luci, math
|
||||
= type, pairs, ipairs, table, luci, math
|
||||
|
||||
local tpl = require "luci.template.parser"
|
||||
local utl = require "luci.util"
|
||||
local uci = require "luci.model.uci"
|
||||
local fs = require "nixio.fs"
|
||||
module "luci.tools.dnscrypt"
|
||||
|
||||
local uci_r, uci_s
|
||||
local dsec, dlst = "dnscrypt", "resolvers"
|
||||
local dglb, dsrc = "source", "urls"
|
||||
|
||||
function _valid_id(x)
|
||||
return (x and #x > 0 and x:match("^[a-zA-Z0-9_]+$"))
|
||||
end
|
||||
|
||||
function _get(c, s, o)
|
||||
return uci_r:get(c, s, o)
|
||||
end
|
||||
|
||||
function _set(c, s, o, v)
|
||||
if v ~= nil then
|
||||
if type(v) == "boolean" then v = v and "1" or "0" end
|
||||
return uci_r:set(c, s, o, v)
|
||||
else
|
||||
return uci_r:delete(c, s, o)
|
||||
end
|
||||
end
|
||||
|
||||
function typicalcfg(self, cfg)
|
||||
local dnscrypt_types, all_val, k, t = {"source", "dnscrypt"}, uci_r:get_all(cfg)
|
||||
if not all_val then return true end
|
||||
for k, t in pairs(all_val) do
|
||||
if not luci.util.contains(dnscrypt_types, t[".type"]) then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function resolvers_list(self, with_src)
|
||||
local _, cfg, r = nil, nil, { }
|
||||
for cfg in (fs.glob(uci_r:get_confdir() .. "/*")) do
|
||||
cfg=fs.basename(cfg)
|
||||
uci_r:foreach(cfg, dsec,
|
||||
function(s)
|
||||
if s.name and s.stamp and s.proto and s.country then
|
||||
local src = uci_r:get_first(cfg, dglb, dsrc)
|
||||
r[#r+1] = with_src and "%s|%s" %{cfg, src or "Unknown"} or cfg
|
||||
end
|
||||
return false
|
||||
end)
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function country_list(self)
|
||||
local _, cfg, r = nil, nil, { }
|
||||
for _, cfg in pairs(self:resolvers_list(false)) do
|
||||
uci_r:foreach(cfg, dsec,
|
||||
function(s)
|
||||
if s.country then
|
||||
r[s.country] = s.country
|
||||
end
|
||||
end)
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function proto_list(self)
|
||||
local _, cfg, r = nil, nil, { }
|
||||
for _, cfg in pairs(self:resolvers_list(false)) do
|
||||
uci_r:foreach(cfg, dsec,
|
||||
function(s)
|
||||
if s.proto then
|
||||
r[s.proto] = s.proto
|
||||
end
|
||||
end)
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function dns_list(self, rf, cf, prf)
|
||||
local _, cfg, r = nil, nil, { }
|
||||
for _, cfg in pairs(self:resolvers_list(false)) do
|
||||
uci_r:foreach(cfg, dsec,
|
||||
function(s)
|
||||
if rf and cfg ~= rf then return false end
|
||||
if s.name and s.stamp and s.proto then
|
||||
if cf and cf ~= s.country then return true end
|
||||
if prf and prf ~= s.proto then return true end
|
||||
r[#r+1] = {
|
||||
['resolver'] = cfg,
|
||||
['proto'] = s.proto,
|
||||
['country'] = s.country,
|
||||
['name'] = s.name,
|
||||
['stamp'] = s.stamp,
|
||||
['addrs'] = s.addrs,
|
||||
['ports'] = s.ports,
|
||||
}
|
||||
end
|
||||
end)
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function init(cursor)
|
||||
uci_r = cursor or uci_r or uci.cursor()
|
||||
uci_s = uci_r:substate()
|
||||
|
||||
return _M
|
||||
end
|
||||
|
||||
function save(self, ...)
|
||||
uci_r:save(...)
|
||||
uci_r:load(...)
|
||||
end
|
||||
|
||||
function commit(self, ...)
|
||||
uci_r:commit(...)
|
||||
uci_r:load(...)
|
||||
end
|
||||
|
||||
function get_defaults()
|
||||
return defaults()
|
||||
end
|
||||
@@ -0,0 +1,180 @@
|
||||
<%-
|
||||
local dc = require "luci.tools.dnscrypt".init()
|
||||
local rsl = dc:resolvers_list(false)
|
||||
local ctl = dc:country_list()
|
||||
local prl = dc:proto_list()
|
||||
local dnss = dc:dns_list()
|
||||
local _, z
|
||||
-%>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var dnslist = <%= luci.http.write_json(dnss) %>;
|
||||
function find_in_object(my_object, my_criteria){
|
||||
|
||||
return my_object.filter(function(obj) {
|
||||
return Object.keys(my_criteria).every(function(c) {
|
||||
return obj[c] == my_criteria[c];
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
function unique_list(data, id) {
|
||||
if (data.length > 0) {
|
||||
var result = ["ALL"];
|
||||
|
||||
data.forEach(function (elem) {
|
||||
if (result.indexOf(elem[id]) === -1) {
|
||||
result.push(elem[id]);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
function cbi_set_values(id, vals) {
|
||||
while (id.options[0])
|
||||
id.remove(0);
|
||||
|
||||
for (var i = 0; vals && i < vals.length; i += 1)
|
||||
{
|
||||
// if (!vals[i+2])
|
||||
// continue;
|
||||
var opt = document.createElement('option');
|
||||
opt.value = vals[i];
|
||||
opt.text = vals[i];
|
||||
id.add(opt);
|
||||
}
|
||||
id.vals = vals;
|
||||
}
|
||||
function cbi_init_dnslist(self, reset = false) {
|
||||
id = "_newsrv";
|
||||
var oproto = document.getElementById(id + '.proto');
|
||||
var oresolvers = document.getElementById(id + '.resolvers');
|
||||
var ocountry = document.getElementById(id + '.country');
|
||||
var oname = document.getElementById(id + '.name');
|
||||
var oaddrs = document.getElementById(id + '.addrs');
|
||||
var oports = document.getElementById(id + '.ports');
|
||||
var ohints = document.getElementById(id + '.hints');
|
||||
var oaddbt = document.getElementById("cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>");
|
||||
|
||||
filter = {};
|
||||
vproto = reset ? "ALL" : oproto.value;
|
||||
vresolvers = reset ? "ALL" : oresolvers.value;
|
||||
vcountry = reset ? "ALL" : ocountry.value;
|
||||
vname = reset ? "ALL" : oname.value;
|
||||
vaddrs = reset ? "ALL" : oaddrs.value;
|
||||
vports = reset ? "ALL" : oports.value;
|
||||
if (vproto != "ALL" && vproto != "") filter["proto"] = vproto;
|
||||
if (vresolvers != "ALL" && vresolvers != "") filter["resolver"] = vresolvers;
|
||||
if (vcountry != "ALL" && vcountry != "") filter["country"] = vcountry;
|
||||
if (vname != "ALL" && vname != "") filter["name"] = vname;
|
||||
if (vaddrs != "ALL" && vaddrs != "") filter["addrs"] = vaddrs;
|
||||
if (vports != "ALL" && vports != "") filter["ports"] = vports;
|
||||
|
||||
var dst = find_in_object(dnslist, filter);
|
||||
cbi_set_values(oproto, unique_list(dst, "proto"));
|
||||
cbi_set_values(oresolvers, unique_list(dst, "resolver"));
|
||||
cbi_set_values(ocountry, unique_list(dst, "country"));
|
||||
cbi_set_values(oname, unique_list(dst, "name"));
|
||||
cbi_set_values(oaddrs, unique_list(dst, "addrs"));
|
||||
cbi_set_values(oports, unique_list(dst, "ports"));
|
||||
|
||||
if (dst.length === 1) {
|
||||
vproto = dst[0]["proto"];
|
||||
vresolvers = dst[0]["resolver"];
|
||||
vcountry = dst[0]["country"];
|
||||
vname = dst[0]["name"];
|
||||
vaddrs = dst[0]["addrs"];
|
||||
document.getElementById(id + '.alias').value = vname + "." + vcountry + "@" + vproto;
|
||||
document.getElementById(id + '.stamp').value = dst[0]['stamp'];
|
||||
}
|
||||
oproto.value = vproto;
|
||||
oresolvers.value = vresolvers;
|
||||
ocountry.value = vcountry;
|
||||
oname.value = vname;
|
||||
oaddrs.value = vaddrs;
|
||||
oports.value = vports;
|
||||
|
||||
oaddbt.disabled = ( dst.length !== 1);
|
||||
ohints.innerHTML = "Filter: (" + String(dst.length) + ")" + JSON.stringify(filter) + '\n' + ((dst.length < 80) ? JSON.stringify(dst) : "<%:more than 100, try filter out to show details...%>");
|
||||
}
|
||||
//]]></script>
|
||||
<div class="cbi-section cbi-tblsection">
|
||||
<h3><%:DNS Resolver Filter%></h3>
|
||||
<div class="table cbi-section-table">
|
||||
<div class="tr cbi-section-table-titles">
|
||||
<div class="th cbi-section-table-cell"><%:Resolvers%></div>
|
||||
<div class="th cbi-section-table-cell"><%:Country%></div>
|
||||
<div class="th cbi-section-table-cell"><%:Protocol%></div>
|
||||
<div class="th cbi-section-table-cell"><%:Resolver%></div>
|
||||
<div class="th cbi-section-table-cell"><%:Address%></div>
|
||||
<div class="th cbi-section-table-cell"><%:Port%></div>
|
||||
<div class="th cbi-section-table-cell cbi-section-actions"></div>
|
||||
</div>
|
||||
<div class="tr cbi-section-table-row">
|
||||
<div class="td cbi-section-table-cell">
|
||||
<select class="cbi-input-select" id="_newsrv.resolvers" name="_newsrv.resolvers">
|
||||
<option value="ALL"><%:ALL%></option>
|
||||
<% for _, z in ipairs(rsl) do -%><option value="<%=z%>"><%=z%></option><%- end %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="td cbi-section-table-cell">
|
||||
<select class="cbi-input-select" id="_newsrv.country" name="_newsrv.country">
|
||||
<option value="ALL"><%:ALL%></option>
|
||||
<% for _, z in pairs(ctl) do -%><option value="<%=z%>"><%=z%></option><%- end %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="td cbi-section-table-cell">
|
||||
<select class="cbi-input-select" id="_newsrv.proto" name="_newsrv.proto">
|
||||
<option value="ALL"><%:ALL%></option>
|
||||
<% for _, z in pairs(prl) do -%><option value="<%=z%>"><%=z%></option><%- end %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="td cbi-section-table-cell">
|
||||
<select class="cbi-input-select" id="_newsrv.name" name="_newsrv.name">
|
||||
<option value="ALL"><%:ALL%></option>
|
||||
<% for _, z in pairs(dnss) do -%><option value="<%=z['name']%>"><%=z['name']%></option><%- end %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="td cbi-section-table-cell">
|
||||
<select class="cbi-input-select" id="_newsrv.addrs" name="_newsrv.addrs">
|
||||
<option value="ALL"><%:ALL%></option>
|
||||
<% for _, z in pairs(dnss) do -%><option value="<%=z['addrs']%>"><%=z['addrs']%></option><%- end %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="td cbi-section-table-cell">
|
||||
<select class="cbi-input-select" id="_newsrv.ports" name="_newsrv.ports">
|
||||
<option value="ALL"><%:ALL%></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="td cbi-section-table-cell nowrap cbi-section-actions"><div>
|
||||
<input type="reset" class="cbi-button cbi-button-reset" name="_newsrv.reset" id="_newsrv.reset" value="<%:Reset%>" />
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table cbi-section-table">
|
||||
<div class="tr cbi-section-table-row">
|
||||
<div class="td cbi-section-table-cell">
|
||||
<input type="text" class="cbi-input-text" id="_newsrv.alias" name="_newsrv.alias" placeholder="<%:Alias%>" />
|
||||
</div>
|
||||
<div class="td cbi-section-table-cell">
|
||||
<input type="text" class="cbi-input-text" id="_newsrv.stamp" name="_newsrv.stamp" data-optional="false" placeholder="<%:Stamp%>" />
|
||||
</div>
|
||||
<div class="td cbi-section-table-cell nowrap cbi-section-actions"><div>
|
||||
<input type="submit" class="cbi-button cbi-button-add" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" value="<%:Add%>" />
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea class="cbi-input-textarea" style="width: 100%" id="_newsrv.hints" name="_newsrv.hints" data-update="change" rows="10" wrap="soft" readonly="true">sample</textarea>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
cbi_init_dnslist();
|
||||
document.getElementById('_newsrv.country').addEventListener('change', function() {try{cbi_init_dnslist();}catch(e){}});
|
||||
document.getElementById('_newsrv.resolvers').addEventListener('change', function() {try{cbi_init_dnslist();}catch(e){}});
|
||||
document.getElementById('_newsrv.proto').addEventListener('change', function() {try{cbi_init_dnslist();}catch(e){}});
|
||||
document.getElementById('_newsrv.name').addEventListener('change', function() {try{cbi_init_dnslist();}catch(e){}});
|
||||
document.getElementById('_newsrv.addrs').addEventListener('change', function() {try{cbi_init_dnslist();}catch(e){}});
|
||||
document.getElementById('_newsrv.ports').addEventListener('change', function() {try{cbi_init_dnslist();}catch(e){}});
|
||||
document.getElementById('_newsrv.reset').addEventListener('click', function() {try{cbi_init_dnslist(true);}catch(e){};});
|
||||
//]]></script>
|
||||
@@ -0,0 +1,61 @@
|
||||
<% if self:cfgvalue(self.section) then section = self.section; cfgs = self:cfgvalue(self.section)%>
|
||||
<fieldset class="cbi-section">
|
||||
<% if self.title and #self.title > 0 then -%>
|
||||
<legend><%=self.title%></legend>
|
||||
<%- end %>
|
||||
<div class="cbi-section-node" id="cbi-<%=self.config%>-<%=section%>">
|
||||
<% local isempty = true for i, val in ipairs(cfgs) do -%>
|
||||
<% local cfg = luci.util.split(val, "|")[1]; local src = luci.util.split(val, "|")[2] -%>
|
||||
<div class="cbi-value<% if i > #cfgs then -%> cbi-value-last<%- end%>" id="cbi-<%=cfg.."-source-urls"%>" data-index="<%=i%>" data-depends="[]">
|
||||
<label class="cbi-value-title"<%= attr("for", "source") %>>
|
||||
<a title="<%=translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=self.extedit % cfg%>">
|
||||
<%-='%d) %s' % {i, cfg}-%>
|
||||
</a>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<%
|
||||
write('Source: <a href="%s">%s</a>' % {src, src})
|
||||
%>
|
||||
</div>
|
||||
</div>
|
||||
<% isempty = false -%>
|
||||
<%- end %>
|
||||
<br />
|
||||
<% if isempty then i = 1 -%>
|
||||
<em><%:One or more requred configure is missing!%><br /><br /></em>
|
||||
<%- end %>
|
||||
<% if self.description and #self.description > 0 then -%>
|
||||
<div class="cbi-section-descr"><%=self.description%></div>
|
||||
<%- end %>
|
||||
<div class="cbi-section-create">
|
||||
<input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.new.source" name="cbi.cts.<%=self.config%>.new.source" data-type="uciname" data-optional="true" />
|
||||
<input type="submit" class="cbi-button cbi-button-add" onclick="window.location.href='<%=self.extedit%>'.format(document.getElementById('cbi.cts.<%=self.config%>.new.source').value); return false" value="<%:Add%>/<%:Edit%><%:Resolvers%>" />
|
||||
<% if self.invalid_cts then -%>
|
||||
<br /><%:Invalid%></div>
|
||||
<%- end %>
|
||||
</div>
|
||||
<br />
|
||||
<% self:render_children(section, scope or {}) %>
|
||||
</div>
|
||||
<br />
|
||||
<% if self.error and self.error[1] then -%>
|
||||
<div class="cbi-section-error">
|
||||
<ul><% for _, e in ipairs(self.error[1]) do -%>
|
||||
<li>
|
||||
<%- if e == "invalid" then -%>
|
||||
<%:One or more configure contain invalid values!%>
|
||||
<%- elseif e == "missing" then -%>
|
||||
<%:One or more required configure is missing!%>
|
||||
<%- else -%>
|
||||
<%=pcdata(e)%>
|
||||
<%- end -%>
|
||||
</li>
|
||||
<%- end %></ul>
|
||||
</div>
|
||||
<%- end %>
|
||||
<% if message then %>
|
||||
<div class="alert-message"><%=message%></div>
|
||||
<% end %>
|
||||
<br />
|
||||
</fieldset>
|
||||
<% end %>
|
||||
@@ -0,0 +1,107 @@
|
||||
<!-- ++ BEGIN ++ DNSCrypt Proxy ++ logsview.htm ++ -->
|
||||
<%-
|
||||
local values = self:formvalue(section)
|
||||
if not values then
|
||||
values = self:cfgvalue(section) or {self.default}
|
||||
end
|
||||
|
||||
local function serialize_json(x, cb)
|
||||
local rv, push = nil, cb
|
||||
if not push then
|
||||
rv = { }
|
||||
push = function(tok) rv[#rv+1] = tok end
|
||||
end
|
||||
|
||||
if x == nil then
|
||||
push("null")
|
||||
elseif type(x) == "table" then
|
||||
push("[")
|
||||
for k = 1, #x do
|
||||
if k > 1 then
|
||||
push(",")
|
||||
end
|
||||
serialize_json(x[k], push)
|
||||
end
|
||||
push("]")
|
||||
else
|
||||
push('"%s"' % tostring(x):gsub('["%z\1-\31\\]',
|
||||
function(c) return '\\u%04x' % c:byte(1) end))
|
||||
end
|
||||
|
||||
if not cb then
|
||||
return table.concat(rv, "")
|
||||
end
|
||||
end
|
||||
-%>
|
||||
<%+cbi/valueheader%>
|
||||
<select class="cbi-input-select" onchange="onclick_logview(this, false)"
|
||||
<%=
|
||||
attr("name", cbid) .. attr("id", cbid) .. attr("value", self.default) .. ifattr(self.size, "size")
|
||||
%>
|
||||
></select>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
(function() {
|
||||
//var values = <%=serialize_json(values)%>;
|
||||
var keylist = <%=serialize_json(self.keylist)%>;
|
||||
var vallist = <%=serialize_json(self.vallist)%>;
|
||||
var parent = document.getElementById("<%=cbid%>");
|
||||
for (var j = 0; j < keylist.length; j++) {
|
||||
var opt = document.createElement("option");
|
||||
opt.value = keylist[j];
|
||||
if (j == 0) {
|
||||
opt.selected = "selected";
|
||||
}
|
||||
opt.appendChild(document.createTextNode(vallist[j]));
|
||||
parent.appendChild(opt);
|
||||
}
|
||||
}());
|
||||
//]]></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
function onclick_logview(id, bottom) {
|
||||
// get elements
|
||||
var txt = document.getElementById("<%=cbid%>.txt"); // TextArea
|
||||
if ( !txt ) { return; } // security check
|
||||
txt.value= "Reading: " + document.getElementById("<%=cbid%>").value
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy", "fileread")%>', {lfile: document.getElementById("<%=cbid%>").value} ,
|
||||
function(x, rv) {
|
||||
if(x.readyState === 4 ) {
|
||||
if(x.status === 200) {try{res = JSON.parse(x.responseText);}catch(e){res=null;}
|
||||
if(res !==null && typeof(res) === "object") txt.value = res[0]; if (bottom) txt.scrollTop = txt.scrollHeight; else txt.scrollTop = 0; txt.scrollLeft = 0;
|
||||
} else {
|
||||
txt.value = "XHR.get(<%=luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy", "fileread")%>) Failed!";
|
||||
}}});
|
||||
return false;
|
||||
}
|
||||
//]]></script>
|
||||
|
||||
<%
|
||||
-- one button on top, one at the buttom
|
||||
%>
|
||||
<br /><br />
|
||||
<input class="cbi-button cbi-input-button" style="align: center; width: 100%" type="button" onclick='onclick_logview(this, false)'
|
||||
<%=
|
||||
attr("name", section) .. attr("id", cbid .. ".btn1") .. attr("value", self.inputtitle)
|
||||
%> />
|
||||
|
||||
<br /><br />
|
||||
|
||||
<%
|
||||
-- set a readable style taken from openwrt theme for textarea#syslog
|
||||
-- in openwrt theme there are problems with a width of 100 so we check for theme and set to lower value
|
||||
%>
|
||||
<textarea style="width: <%if media == "/luci-static/openwrt.org" then%>98.7%<%else%>100%<%end%> ; min-height: 200px; border: 3px solid #cccccc; padding: 5px; font-family: monospace; resize: none;" wrap="off" readonly="readonly"
|
||||
<%=
|
||||
attr("name", cbid .. ".txt") .. attr("id", cbid .. ".txt") .. ifattr(self.rows, "rows")
|
||||
%> >
|
||||
<%-=pcdata(self:cfgvalue(section))-%>
|
||||
</textarea>
|
||||
<br /><br />
|
||||
|
||||
<%
|
||||
-- one button on top, one at the buttom
|
||||
%>
|
||||
<input class="cbi-button cbi-input-button" style="align: center; width: 100%" type="button" onclick='onclick_logview(this, true)'
|
||||
<%= attr("name", section) .. attr("id", cbid .. ".btn2") .. attr("value", self.inputtitle) %> />
|
||||
<br /><br />
|
||||
<%+cbi/valuefooter%>
|
||||
<!-- ++ END ++ DNSCrypt Proxy ++ logsview.htm ++ -->
|
||||
@@ -0,0 +1,103 @@
|
||||
<%+cbi/valueheader%>
|
||||
<%-
|
||||
local util = require "luci.util"
|
||||
local sys = require "luci.sys"
|
||||
-%>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
<% if self.option == "dnscrypt_bin" then -%>
|
||||
function update_bin(obtn, dataname, surl)
|
||||
{
|
||||
obtn.disabled = true;
|
||||
ret = false;
|
||||
alert(dataname+":\n" + surl);
|
||||
murl = dataname;
|
||||
var osta = document.getElementById(dataname+'-status'); XHR.get('<%=luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy","update_c")%>',
|
||||
{ set:"dnscrypt_bin", url:surl },
|
||||
function(x, rv) {
|
||||
if(x.readyState === 4 ) {
|
||||
if(x.status === 200) {try{res = JSON.parse(x.responseText);}catch(e){res=null;}
|
||||
if(res !==null && typeof(res) === "object") {osta.innerText = res.status; obtn.disabled = false; obtn.value = '<%= self.name or translate("Refresh Data")%>';obtn.onclick = function (){alert("<%:No new data!%>");}; return (rv.err === 0);}
|
||||
}}});
|
||||
return false;
|
||||
}
|
||||
|
||||
function parse_gittag(gtag, obtn, osta, sprefix, scver)
|
||||
{
|
||||
ret = true;
|
||||
tagv = gtag.name;
|
||||
dlfile = 'dnscrypt-proxy-%s-%s.tar.gz'.format(sprefix, tagv);
|
||||
obtn.title = "";
|
||||
osta.innerHTML = '<font color="red">%s</font><br /><div class="cbi-section-descr"><pre>%s</pre></div>'.format(dlfile, gtag.body);
|
||||
if(scver === tagv) {obtn.value = '<%:No new data!%>';}
|
||||
else if(! gtag.assets) {osta.innerText = '<%:Refresh Error!%>'; ret = false;}
|
||||
else {
|
||||
_assets = gtag.assets;
|
||||
osta.innerText = dlfile;
|
||||
for (var idx = 0; idx < _assets.length; idx++) {
|
||||
var dls=_assets[idx];
|
||||
if(dls.name === dlfile) {
|
||||
obtn.value = '<%:Update%> ' + tagv;
|
||||
obtn.title = dls.browser_download_url;
|
||||
obtn.onclick = function() { update_bin(this,'<%=self.option%>',this.title); };
|
||||
obtn.disabled = false;
|
||||
osta.innerHTML = '<a href="%s">%s</a>(%00.1fMB)<br /><div class="cbi-section-descr"><pre>%s</pre></div>'.format(dls.browser_download_url, dlfile, dls.size/1024/1024, gtag.body);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
<%- end %>
|
||||
function refresh_data_<%=self.option%>(btn,dataname)
|
||||
{
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Refresh...%> ';
|
||||
murl=dataname;
|
||||
var s = document.getElementById(dataname+'-status');
|
||||
if (dataname === "dnscrypt_bin") {
|
||||
os = '<%=util.trim(sys.exec("uname")):lower()%>';
|
||||
arch = '<%=util.trim(sys.exec("uname -m"))%>';
|
||||
prefix = '%s_%s'.format(os, arch);
|
||||
cver = '<%=util.trim(sys.exec("/usr/sbin/dnscrypt-proxy -version"))%>';
|
||||
tag_url = 'https://api.github.com/repos/dnscrypt/dnscrypt-proxy/releases/latest';
|
||||
s.innerHTML = ' current: dnscrypt-proxy %s-%s.tar.gz <a href="%s">release checking...</a>'.format(prefix, cver, tag_url);
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy","refresh_c")%>',null, function(x,rv) {
|
||||
s.innerText = 'Test, %s readyState: %d, status: %d'.format(x.statusText, x.readyState, x.status);
|
||||
x.open('GET', tag_url, true);
|
||||
x.onreadystatechange = function() {
|
||||
if(x.readyState === 4 && x.status === 200) {
|
||||
try{res = JSON.parse(x.responseText);}catch(e){res=null;}
|
||||
if(res !==null && typeof(res) === "object") {parse_gittag(res, btn, s, prefix, cver);}
|
||||
} else {
|
||||
s.innerHTML = '<font color="red">ReleaseTag, %s readyState: %d, status: %d</font>'.format(x.statusText, x.readyState, x.status);
|
||||
btn.disabled = false;
|
||||
btn.value = '<%= self.name or translate("Refresh Data")%>';
|
||||
}};
|
||||
x.send(null);
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy","refresh_c")%>',
|
||||
{ set:murl },
|
||||
function(x, rv) {
|
||||
if(x.readyState === 4 ) {
|
||||
if(x.status === 200) {try{res = JSON.parse(x.responseText);}catch(e){res=null;}
|
||||
if(res !==null && typeof(res) === "object") {
|
||||
var s = document.getElementById(dataname+'-status');
|
||||
if (s) {
|
||||
if (res.ret=="0") s.innerHTML ="<font color='green'>"+"<%:No new data!%> "+"</font>";
|
||||
else if(res.ret=="-1") s.innerHTML ="<font color='red'>"+"<%:Refresh Error!%> "+"</font>";
|
||||
else s.innerHTML ="<font color='green'>"+"<%:Refresh OK!%> "+"<%= self.ret or translate('Total Records:')%>"+res.ret+"</font>";
|
||||
btn.disabled = false;
|
||||
btn.value = '<%= self.name or translate('Refresh Data')%>';}}
|
||||
}}});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//]]></script>
|
||||
|
||||
|
||||
<input type="button" class="cbi-button cbi-input-reload" value="<%= self.name or translate('Refresh Data')%> " onclick="return refresh_data_<%=self.option%>(this,'<%=self.option%>')" />
|
||||
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
|
||||
|
||||
<%+cbi/valuefooter%>
|
||||
@@ -0,0 +1,22 @@
|
||||
<%+cbi/valueheader%>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
|
||||
function check_port(btn, func)
|
||||
{
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Check...%>';
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy","resolve_c")%>',
|
||||
{ set:func },
|
||||
function(x, rv) {
|
||||
if(x.readyState === 4 ) {
|
||||
if(x.status === 200) {try{res = JSON.parse(x.responseText);}catch(e){res=null;}
|
||||
if(res !==null && typeof(res) === "object") {var s = document.getElementById(func + '-status'); if (s) s.innerHTML =res.ret; btn.disabled = false; btn.value = '<%:Check Server%>';}
|
||||
}}});
|
||||
return false;
|
||||
}
|
||||
//]]></script>
|
||||
<input type="button" class="cbi-button cbi-button-apply" value="<%:Check Server%>" onclick="return check_port(this,'<%=self.option%>')" />
|
||||
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
|
||||
|
||||
<%+cbi/valuefooter%>
|
||||
Reference in new issue
Block a user