summaryrefslogtreecommitdiffhomepage
path: root/applications
diff options
context:
space:
mode:
authorFlorian Eckert <fe@dev.tdt.de>2020-07-02 18:39:21 +0200
committerGitHub <noreply@github.com>2020-07-02 18:39:21 +0200
commit9f95d43b6708b5760a6854c18c043e58f1c3ff83 (patch)
tree0c4052cc4cfdab38da0c280680890675918fe0cc /applications
parent2e2ab59eafc3673b1710260d3754e79f46ccd309 (diff)
parent7aad18cbac961f6ec75580c107e91d476fd4284a (diff)
Merge pull request #3413 from pymumu/master
luci-app-smartdns: add new package
Diffstat (limited to 'applications')
-rw-r--r--applications/luci-app-smartdns/Makefile26
-rw-r--r--applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js483
-rw-r--r--applications/luci-app-smartdns/po/zh-cn/smartdns.po305
-rw-r--r--applications/luci-app-smartdns/root/usr/share/luci/menu.d/luci-app-smartdns.json12
-rw-r--r--applications/luci-app-smartdns/root/usr/share/rpcd/acl.d/luci-app-smartdns.json21
5 files changed, 847 insertions, 0 deletions
diff --git a/applications/luci-app-smartdns/Makefile b/applications/luci-app-smartdns/Makefile
new file mode 100644
index 000000000..878fbf739
--- /dev/null
+++ b/applications/luci-app-smartdns/Makefile
@@ -0,0 +1,26 @@
+#
+# Copyright 2018-2020 Nick Peng <pymumu@gmail.com>
+# Licensed to the public under the GPL V3 License.
+
+include $(TOPDIR)/rules.mk
+
+PKG_LICENSE:=GPL-3.0-or-later
+PKG_MAINTAINER:=Nick Peng <pymumu@gmail.com>
+PKG_VERSION:=1.2020.30
+PKG_RELEASE:=1
+
+LUCI_TITLE:=LuCI for smartdns
+LUCI_DESCRIPTION:=Provides Luci for smartdns
+LUCI_DEPENDS:=+smartdns
+LUCI_PKGARCH:=all
+
+define Package/$(PKG_NAME)/config
+# shown in make menuconfig <Help>
+help
+ $(LUCI_TITLE)
+ Version: $(PKG_VERSION)-$(PKG_RELEASE)
+endef
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js b/applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js
new file mode 100644
index 000000000..549482b46
--- /dev/null
+++ b/applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js
@@ -0,0 +1,483 @@
+/*************************************************************************
+ *
+ * Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
+ *
+ * smartdns is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * smartdns is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+'use strict';
+'require fs';
+'require uci';
+'require form';
+'require rpc';
+
+var conf = 'smartdns';
+var callServiceList = rpc.declare({
+ object: 'service',
+ method: 'list',
+ params: ['name'],
+ expect: { '': {} }
+});
+
+function getPidOfSmartdns() {
+ return L.resolveDefault(callServiceList(conf), {})
+ .then(function (res) {
+ var isrunning = false;
+ try {
+ isrunning = res[conf]['instances']['smartdns']['running'];
+ } catch (e) { }
+ return isrunning;
+ });
+}
+
+function getIPTablesRedirect() {
+ return fs.exec('/usr/sbin/iptables', ['-t', 'nat', '-nL', 'PREROUTING']).then(function (res) {
+ if (res.code === 0) {
+ return res.stdout.trim();
+ } else {
+ return "";
+ }
+ });
+}
+
+function getIP6TablesRedirect() {
+ return fs.exec('/usr/sbin/ip6tables', ['-t', 'nat', '-nL', 'PREROUTING']).then(function (res) {
+ if (res.code === 0) {
+ return res.stdout.trim();
+ } else {
+ return "";
+ }
+ });
+}
+
+function smartdnsServiceStatus() {
+ return Promise.all([
+ getPidOfSmartdns(),
+ getIPTablesRedirect(),
+ getIP6TablesRedirect()
+ ]);
+}
+
+function smartdnsRenderStatus(res) {
+ var renderHTML = "";
+ var isRunning = res[0];
+ var ipt = res[1];
+ var ip6t = res[2];
+
+ var serverPort = uci.get_first('smartdns', 'smartdns', 'port');
+ var redirectMode = uci.get_first('smartdns', 'smartdns', 'redirect');
+ var ipv6Enabled = uci.get_first('smartdns', 'smartdns', 'ipv6_server');
+
+ if (isRunning) {
+ renderHTML += "<span style=\"color:green;font-weight:bold\">SmartDNS - " + _("RUNNING") + "</span>";
+ } else {
+ renderHTML += "<span style=\"color:red;font-weight:bold\">SmartDNS - " + _("NOT RUNNING") + "</span>";
+ return renderHTML;
+ }
+
+ if (redirectMode === "dnsmasq-upstream") {
+ var matchLine = "127.0.0.1#" + serverPort;
+ var dnsmasqServer = uci.get_first('dhcp', 'dnsmasq', 'server') || "";
+
+ if (dnsmasqServer.indexOf(matchLine) < 0) {
+ renderHTML += "<br /><span style=\"color:red;font-weight:bold\">" + _("Dnsmasq Forwared To Smartdns Failure") + "</span>";
+ }
+ } else if (redirectMode === "redirect") {
+ var redirectRules = (ipt || '').split(/\n/).filter(function (rule) {
+ return rule.match(/REDIRECT/) && rule.match(/dpt:53/) && rule.match("ports " + serverPort);
+ });
+
+ if (redirectRules.length <= 0) {
+ renderHTML += "<br /><span style=\"color:red;font-weight:bold\">" + _("IPV4 53 Port Redirect Failure") + "</span>";
+ if (ipv6Enabled) {
+ var redirectRules = (ip6t || '').split(/\n/).filter(function (rule) {
+ return rule.match(/REDIRECT/) && rule.match(/dpt:53/) && rule.match("ports " + serverPort);
+ });
+ if (redirectRules.length <= 0) {
+ renderHTML += "<br /><span style=\"color:red;font-weight:bold\">" + _("IPV6 53 Port Redirect Failure") + "</span>";
+ }
+ }
+ }
+ }
+
+ return renderHTML;
+}
+
+return L.view.extend({
+ load: function () {
+ return Promise.all([
+ uci.load('smartdns'),
+ uci.load('dhcp')
+ ]);
+ },
+ render: function (stats) {
+ var m, s, o;
+
+ m = new form.Map('smartdns', _('SmartDNS'));
+ m.title = _("SmartDNS Server");
+ m.description = _("SmartDNS is a local high-performance DNS server, supports finding fastest IP, "
+ + "supports ad filtering, and supports avoiding DNS poisoning.");
+
+ s = m.section(form.NamedSection, '_status');
+ s.anonymous = true;
+ s.render = function (section_id) {
+ L.Poll.add(function () {
+ return L.resolveDefault(smartdnsServiceStatus()).then(function (res) {
+ var view = document.getElementById("service_status");
+ view.innerHTML = smartdnsRenderStatus(res);
+ });
+ });
+
+ return E('div', { class: 'cbi-map' },
+ E('div', { class: 'cbi-section' }, [
+ E('div', { id: 'service_status' },
+ _('Collecting data ...'))
+ ])
+ );
+ }
+
+ // Basic;
+ s = m.section(form.TypedSection, "smartdns", _("Settings"), _("General Settings"));
+ s.anonymous = true;
+
+ s.tab("settings", _("General Settings"));
+ s.tab("seconddns", _("Second Server Settings"));
+ s.tab("custom", _("Custom Settings"));
+
+ // Eanble;
+ o = s.taboption("settings", form.Flag, "enabled", _("Enable"), _("Enable or disable smartdns server"));
+ o.default = o.disabled;
+ o.rempty = false;
+
+ // server name;
+ o = s.taboption("settings", form.Value, "server_name", _("Server Name"), _("Smartdns server name"));
+ o.default = "smartdns";
+ o.datatype = "hostname";
+ o.rempty = false;
+
+ // Port;
+ o = s.taboption("settings", form.Value, "port", _("Local Port"), _("Smartdns local server port"));
+ o.placeholder = 6053;
+ o.default = 6053;
+ o.datatype = "port";
+ o.rempty = false;
+
+ // Enable TCP server;
+ o = s.taboption("settings", form.Flag, "tcp_server", _("TCP Server"), _("Enable TCP DNS Server"));
+ o.rmempty = false;
+ o.default = o.enabled;
+
+ // Support IPV6;
+ o = s.taboption("settings", form.Flag, "ipv6_server", _("IPV6 Server"), _("Enable IPV6 DNS Server"));
+ o.rmempty = false;
+ o.default = o.enabled;
+
+ // Support DualStack ip selection;
+ o = s.taboption("settings", form.Flag, "dualstack_ip_selection", _("Dual-stack IP Selection"),
+ _("Enable IP selection between IPV4 and IPV6"));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // Domain prefetch load ;
+ o = s.taboption("settings", form.Flag, "prefetch_domain", _("Domain prefetch"),
+ _("Enable domain prefetch, accelerate domain response speed."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // Domain Serve expired
+ o = s.taboption("settings", form.Flag, "serve_expired", _("Serve expired"),
+ _("Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // Redirect;
+ o = s.taboption("settings", form.ListValue, "redirect", _("Redirect"), _("SmartDNS redirect mode"));
+ o.placeholder = "none";
+ o.value("none", _("none"));
+ o.value("dnsmasq-upstream", _("Run as dnsmasq upstream server"));
+ o.value("redirect", _("Redirect 53 port to SmartDNS"));
+ o.default = "none";
+ o.rempty = false;
+
+ // cache-size;
+ o = s.taboption("settings", form.Value, "cache_size", _("Cache Size"), _("DNS domain result cache size"));
+ o.rempty = true;
+
+ // rr-ttl;
+ o = s.taboption("settings", form.Value, "rr_ttl", _("Domain TTL"), _("TTL for all domain result."));
+ o.rempty = true;
+
+ // rr-ttl-min;
+ o = s.taboption("settings", form.Value, "rr_ttl_min", _("Domain TTL Min"),
+ _("Minimum TTL for all domain result."));
+ o.rempty = true;
+ o.placeholder = "300";
+ o.default = 300;
+ o.optional = true;
+
+ // second dns server;
+ // rr-ttl-max;
+ o = s.taboption("settings", form.Value, "rr_ttl_max", _("Domain TTL Max"),
+ _("Maximum TTL for all domain result."));
+ o.rempty = true;
+
+ // Eanble;
+ o = s.taboption("seconddns", form.Flag, "seconddns_enabled", _("Enable"),
+ _("Enable or disable second DNS server."));
+ o.default = o.disabled;
+ o.rempty = false;
+
+ // Port;
+ o = s.taboption("seconddns", form.Value, "seconddns_port", _("Local Port"), _("Smartdns local server port"));
+ o.placeholder = 6553;
+ o.default = 6553;
+ o.datatype = "port";
+ o.rempty = false;
+
+ // Enable TCP server;
+ o = s.taboption("seconddns", form.Flag, "seconddns_tcp_server", _("TCP Server"), _("Enable TCP DNS Server"));
+ o.rmempty = false;
+ o.default = o.enabled;
+
+ // dns server group;
+ o = s.taboption("seconddns", form.Value, "seconddns_server_group", _("Server Group"),
+ _("Query DNS through specific dns server group, such as office, home."));
+ o.rmempty = true;
+ o.placeholder = "default";
+ o.datatype = "hostname";
+ o.rempty = true;
+
+ o = s.taboption("seconddns", form.Flag, "seconddns_no_speed_check", _("Skip Speed Check"),
+ _("Do not check speed."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // skip address rules;
+ o = s.taboption("seconddns", form.Flag, "seconddns_no_rule_addr", _("Skip Address Rules"),
+ _("Skip address rules."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // skip name server rules;
+ o = s.taboption("seconddns", form.Flag, "seconddns_no_rule_nameserver", _("Skip Nameserver Rule"),
+ _("Skip nameserver rules."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // skip ipset rules;
+ o = s.taboption("seconddns", form.Flag, "seconddns_no_rule_ipset", _("Skip Ipset Rule"),
+ _("Skip ipset rules."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // skip soa address rule;
+ o = s.taboption("seconddns", form.Flag, "seconddns_no_rule_soa", _("Skip SOA Address Rule"),
+ _("Skip SOA address rules."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ o = s.taboption("seconddns", form.Flag, "seconddns_no_dualstack_selection", _("Skip Dualstack Selection"),
+ _("Skip Dualstack Selection."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // skip cache;
+ o = s.taboption("seconddns", form.Flag, "seconddns_no_cache", _("Skip Cache"), _("Skip Cache."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // Force AAAA SOA
+ o = s.taboption("seconddns", form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
+ o.rmempty = false;
+ o.default = o.disabled;
+
+ // custom settings;
+ o = s.taboption("custom", form.TextValue, "custom_conf",
+ "", _("smartdns custom settings"));
+
+ o.rows = 20;
+ o.cfgvalue = function (section_id) {
+ return fs.trimmed('/etc/smartdns/custom.conf');
+ };
+ o.write = function (section_id, formvalue) {
+ return fs.write('/etc/smartdns/custom.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
+ };
+
+ o = s.taboption("custom", form.Flag, "coredump", _("Generate Coredump"),
+ _("Generate Coredump file when smartdns crash, coredump file is located at /tmp/smartdns.xxx.core."));
+ o.rmempty = false;
+ o.default = o.disabled;
+ // Upstream servers;
+ s = m.section(form.GridSection, "server", _("Upstream Servers"),
+ _("Upstream Servers, support UDP, TCP protocol. Please configure multiple DNS servers, "
+ + "including multiple foreign DNS servers."));
+ s.anonymous = true;
+ s.addremove = true;
+
+ s.tab('general', _('General Settings'));
+ s.tab('advanced', _('Advanced Settings'));
+
+ // enable flag;
+ o = s.taboption("general", form.Flag, "enabled", _("Enable"), _("Enable"));
+ o.rmempty = false;
+ o.default = o.enabled;
+ o.editable = true;
+
+ // name;
+ o = s.taboption("general", form.Value, "name", _("DNS Server Name"), _("DNS Server Name"));
+
+ // IP address;
+ o = s.taboption("general", form.Value, "ip", _("ip"), _("DNS Server ip"));
+ o.datatype = "or(ipaddr, string)";
+ o.rmempty = false;
+
+ // port;
+ o = s.taboption("general", form.Value, "port", _("port"), _("DNS Server port"));
+ o.placeholder = "default";
+ o.datatype = "port";
+ o.rempty = true;
+ o.depends("type", "udp");
+ o.depends("type", "tcp");
+ o.depends("type", "tls");
+
+ // type;
+ o = s.taboption("general", form.ListValue, "type", _("type"), _("DNS Server type"));
+ o.placeholder = "udp";
+ o.value("udp", _("udp"));
+ o.value("tcp", _("tcp"));
+ o.value("tls", _("tls"));
+ o.value("https", _("https"));
+ o.default = "udp";
+ o.rempty = false;
+
+ // Advanced Options
+ // server group
+ o = s.taboption("advanced", form.Value, "server_group", _("Server Group"), _("DNS Server group belongs to, "
+ + "used with nameserver, such as office, home."))
+ o.rmempty = true
+ o.placeholder = "default"
+ o.datatype = "hostname"
+ o.rempty = true
+ o.modalonly = true;
+
+ // blacklist_ip
+ o = s.taboption("advanced", form.Flag, "blacklist_ip", _("IP Blacklist Filtering"),
+ _("Filtering IP with blacklist"))
+ o.rmempty = false
+ o.default = o.disabled
+ o.modalonly = true;
+
+ // TLS host verify
+ o = s.taboption("advanced", form.Value, "tls_host_verify", _("TLS Hostname Verify"),
+ _("Set TLS hostname to verify."))
+ o.default = ""
+ o.datatype = "string"
+ o.rempty = true
+ o.modalonly = true;
+ o.depends("type", "tls")
+ o.depends("type", "https")
+
+ // SNI host name
+ o = s.taboption("advanced", form.Value, "host_name", _("TLS SNI name"),
+ _("Sets the server name indication for query."))
+ o.default = ""
+ o.datatype = "hostname"
+ o.rempty = true
+ o.modalonly = true;
+ o.depends("type", "tls")
+ o.depends("type", "https")
+
+ // http host
+ o = s.taboption("advanced", form.Value, "http_host", _("HTTP Host"),
+ _("Set the HTTP host used for the query. Use this parameter when the host of the URL address is an IP address."))
+ o.default = ""
+ o.datatype = "hostname"
+ o.rempty = true
+ o.modalonly = true;
+ o.depends("type", "https")
+
+ // SPKI pin
+ o = s.taboption("advanced", form.Value, "spki_pin", _("TLS SPKI Pinning"),
+ _("Used to verify the validity of the TLS server, The value is Base64 encoded SPKI fingerprint, "
+ + "leaving blank to indicate that the validity of TLS is not verified."))
+ o.default = ""
+ o.datatype = "string"
+ o.rempty = true
+ o.modalonly = true;
+ o.depends("type", "tls")
+ o.depends("type", "https")
+
+ // other args
+ o = s.taboption("advanced", form.Value, "addition_arg", _("Additional Server Args"),
+ _("Additional Args for upstream dns servers"))
+ o.default = ""
+ o.rempty = true
+ o.modalonly = true;
+
+ // Doman addresss;
+ s = m.section(form.TypedSection, "smartdns", _("Advanced Settings"), _("Advanced Settings"));
+ s.anonymous = true;
+
+ s.tab("domain-address", _("Domain Address"), _("Set Specific domain ip address."));
+ s.tab("blackip-list", _("IP Blacklist"), _("Set Specific ip blacklist."));
+
+ o = s.taboption("domain-address", form.TextValue, "address_conf",
+ "",
+ _("Specify an IP address to return for any host in the given domains, Queries in the domains are never "
+ + "forwarded and always replied to with the specified IP address which may be IPv4 or IPv6."));
+ o.rows = 20;
+ o.cfgvalue = function (section_id) {
+ return fs.trimmed('/etc/smartdns/address.conf');
+ };
+ o.write = function (section_id, formvalue) {
+ return fs.write('/etc/smartdns/address.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
+ };
+
+ // IP Blacklist;
+ // blacklist;
+ o = s.taboption("blackip-list", form.TextValue, "blackip_ip_conf",
+ "", _("Configure IP blacklists that will be filtered from the results of specific DNS server."));
+ o.rows = 20;
+ o.cfgvalue = function (section_id) {
+ return fs.trimmed('/etc/smartdns/blacklist-ip.conf');
+ };
+ o.write = function (section_id, formvalue) {
+ return fs.write('/etc/smartdns/blacklist-ip.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
+ };
+
+ // Doman addresss;
+ s = m.section(form.TypedSection, "smartdns", _("Technical Support"),
+ _("If you like this software, please buy me a cup of coffee."));
+ s.anonymous = true;
+
+ o = s.option(form.Button, "web");
+ o.title = _("SmartDNS official website");
+ o.inputtitle = _("open website");
+ o.inputstyle = "apply";
+ o.onclick = function () {
+ window.open("https://pymumu.github.io/smartdns", '_blank');
+ };
+
+ o = s.option(form.Button, "Donate");
+ o.title = _("Donate to smartdns");
+ o.inputtitle = _("Donate");
+ o.inputstyle = "apply";
+ o.onclick = function () {
+ window.open("https://pymumu.github.io/smartdns/#donate", '_blank');
+ };
+
+ return m.render();
+ }
+});
diff --git a/applications/luci-app-smartdns/po/zh-cn/smartdns.po b/applications/luci-app-smartdns/po/zh-cn/smartdns.po
new file mode 100644
index 000000000..4cab4feb2
--- /dev/null
+++ b/applications/luci-app-smartdns/po/zh-cn/smartdns.po
@@ -0,0 +1,305 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
+
+msgid "SmartDNS"
+msgstr "SmartDNS"
+
+msgid "SmartDNS is a local high-performance DNS server"
+msgstr "SmartDNS是一个本地高性能DNS服务器"
+
+msgid "SmartDNS Server"
+msgstr "SmartDNS 服务器"
+
+msgid "SmartDNS is a local high-performance DNS server, supports finding fastest IP, supports ad filtering, and supports avoiding DNS poisoning."
+msgstr "SmartDNS是一个本地高性能DNS服务器,支持返回最快IP,支持广告过滤。"
+
+msgid "Custom Settings"
+msgstr "自定义设置"
+
+msgid "General Settings"
+msgstr "基本设置"
+
+msgid "Settings"
+msgstr "设置"
+
+msgid "Advanced Settings"
+msgstr "高级设置"
+
+msgid "RUNNING"
+msgstr "运行中"
+
+msgid "NOT RUNNING"
+msgstr "未运行"
+
+msgid "Generate Coredump"
+msgstr "生成coredump"
+
+msgid "Generate Coredump file when smartdns crash, coredump file is located at /tmp/smartdns.xxx.core."
+msgstr "当smartdns异常时生成coredump文件,coredump文件在/tmp/smartdns.xxx.core."
+
+msgid "Server Name"
+msgstr "服务器名称"
+
+msgid "Smartdns server name"
+msgstr "SmartDNS的服务器名称,默认为smartdns,留空为主机名"
+
+msgid "SmartDNS is a local dns server to find fastest ip."
+msgstr "本地高性能服务器,优化网络访问性能。"
+
+msgid "Enable or disable smartdns server"
+msgstr "启用或禁用SmartDNS服务"
+
+msgid "Local Port"
+msgstr "本地端口"
+
+msgid "Smartdns local server port"
+msgstr "SmartDNS本地服务端口"
+
+msgid "IPV4 53 Port Redirect Failure"
+msgstr "IPV4 53端口重定向失败"
+
+msgid "IPV6 53 Port Redirect Failure"
+msgstr "IPV6 53端口重定向失败"
+
+msgid "Dnsmasq Forwared To Smartdns Failure"
+msgstr "重定向dnsmasq到smartdns失败"
+
+msgid "TCP Server"
+msgstr "TCP服务器"
+
+msgid "Enable TCP DNS Server"
+msgstr "启用TCP服务器"
+
+msgid "IPV6 Server"
+msgstr "IPV6服务器"
+
+msgid "Enable IPV6 DNS Server"
+msgstr "启用IPV6服务器"
+
+msgid "Dual-stack IP Selection"
+msgstr "双栈IP优选"
+
+msgid "Enable IP selection between IPV4 and IPV6"
+msgstr "启用或禁用IPV4,IPV6间的IP优选策略。"
+
+msgid "Domain prefetch"
+msgstr "域名预加载"
+
+msgid "Enable domain prefetch, accelerate domain response speed."
+msgstr "启用域名预加载,加速域名响应速度。"
+
+msgid "Serve expired"
+msgstr "缓存过期服务"
+
+msgid "Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."
+msgstr "查询性能优化,有请求时尝试回应TTL为0的过期记录,以避免查询等待。"
+
+msgid "Redirect"
+msgstr "重定向"
+
+msgid "SmartDNS redirect mode"
+msgstr "SmartDNS 重定向模式"
+
+msgid "Run as dnsmasq upstream server"
+msgstr "作为dnsmasq的上游服务器"
+
+msgid "Redirect 53 port to SmartDNS"
+msgstr "重定向53端口到SmartDNS"
+
+msgid "Cache Size"
+msgstr "缓存大小"
+
+msgid "DNS domain result cache size"
+msgstr "缓存DNS的结果,缓存大小,配置零则不缓存"
+
+msgid "Domain TTL"
+msgstr "域名TTL"
+
+msgid "TTL for all domain result."
+msgstr "设置所有域名的TTL值"
+
+msgid "Domain TTL Min"
+msgstr "域名TTL最小值"
+
+msgid "Minimum TTL for all domain result."
+msgstr "设置所有域名的TTL最小值"
+
+msgid "Domain TTL Max"
+msgstr "域名TTL最大值"
+
+msgid "Maximum TTL for all domain result."
+msgstr "设置所有域名的TTL最大值"
+
+msgid "smartdns custom settings"
+msgstr "smartdns 自定义设置,具体配置参数参考指导"
+
+msgid "Second Server Settings"
+msgstr "第二DNS服务器"
+
+msgid "Enable or disable second DNS server."
+msgstr "是否启用第二DNS服务器。"
+
+msgid "Skip Speed Check"
+msgstr "跳过测速"
+
+msgid "Do not check speed."
+msgstr "禁用测速。"
+
+msgid "Server Group"
+msgstr "服务器组"
+
+msgid "Query DNS through specific dns server group, such as office, home."
+msgstr "使用指定服务器组查询,比如office, home。"
+
+msgid "Skip Address Rules"
+msgstr "跳过address规则"
+
+msgid "Skip address rules."
+msgstr "跳过address规则。"
+
+msgid "Skip Nameserver Rule"
+msgstr "跳过Nameserver规则"
+
+msgid "Skip nameserver rules."
+msgstr "跳过Nameserver规则。"
+
+msgid "Skip Ipset Rule"
+msgstr "跳过ipset规则"
+
+msgid "Skip ipset rules."
+msgstr "跳过ipset规则。"
+
+msgid "Skip SOA Address Rule"
+msgstr "跳过address SOA(#)规则"
+
+msgid "Skip SOA address rules."
+msgstr "跳过address SOA(#)规则。"
+
+msgid "Skip Dualstack Selection"
+msgstr "跳过双栈优选"
+
+msgid "Skip Dualstack Selection."
+msgstr "跳过双栈优选。"
+
+msgid "Skip Cache"
+msgstr "跳过cache"
+
+msgid "Skip Cache."
+msgstr "跳过cache。"
+
+msgid "Force AAAA SOA"
+msgstr "停用IPV6地址解析"
+
+msgid "Force AAAA SOA."
+msgstr "停用IPV6地址解析。"
+
+msgid "Upstream Servers"
+msgstr "上游服务器"
+
+msgid "Upstream Servers, support UDP, TCP protocol. Please configure multiple DNS servers, including multiple foreign DNS servers."
+msgstr "上游DNS服务器列表,支持UDP,TCP协议,请配置多个上游DNS服务器,包括多个国内外服务器"
+
+msgid "DNS Server Name"
+msgstr "DNS服务器名称"
+
+msgid "port"
+msgstr "端口"
+
+msgid "DNS Server port"
+msgstr "DNS服务器端口"
+
+msgid "DNS Server ip"
+msgstr "DNS服务器IP"
+
+msgid "type"
+msgstr "类型"
+
+msgid "DNS Server type"
+msgstr "协议类型"
+
+msgid "Domain Address"
+msgstr "域名地址"
+
+msgid "TLS Hostname Verify"
+msgstr "校验TLS主机名"
+
+msgid "Set TLS hostname to verify."
+msgstr "设置校验TLS主机名。"
+
+msgid "TLS SNI name"
+msgstr "TLS SNI名称"
+
+msgid "HTTP Host"
+msgstr "HTTP主机"
+
+msgid "Sets the server name indication for query."
+msgstr "设置查询时使用的服务器SNI名称。"
+
+msgid "Set the HTTP host used for the query. Use this parameter when the host of the URL address is an IP address."
+msgstr "设置查询时使用的HTTP主机,当URL地址的host是IP地址时,使用此参数。"
+
+msgid "Server Group"
+msgstr "服务器组"
+
+msgid "DNS Server group belongs to, used with nameserver, such as office, home."
+msgstr "DNS服务器所属组, 配合nameserver使用,例如:office,home。"
+
+msgid "IP Blacklist Filtering"
+msgstr "IP黑名单过滤"
+
+msgid "Anti Answer Forgery"
+msgstr "反回答伪造"
+
+msgid "Anti answer forgery, if DNS does not work properly after enabling, please turn off this feature"
+msgstr "反回答伪造,如果启用后DNS工作不正常,请关闭此功能。"
+
+msgid "Filtering IP with blacklist"
+msgstr "使用IP黑名单过滤"
+
+msgid "TLS SPKI Pinning"
+msgstr "TLS SPKI 指纹"
+
+msgid "Used to verify the validity of the TLS server, The value is Base64 encoded SPKI fingerprint, leaving blank to indicate that the validity of TLS is not verified."
+msgstr "用于校验TLS服务器的有效性,数值为Base64编码的SPKI指纹, 留空表示不验证TLS的合法性"
+
+msgid "Additional Server Args"
+msgstr "额外的服务器参数"
+
+msgid "Additional Args for upstream dns servers"
+msgstr "额外的上游DNS服务器参数"
+
+msgid "Upstream DNS Server Configuration"
+msgstr "上游DNS服务器配置"
+
+msgid "Set Specific domain ip address."
+msgstr "指定特定域名的IP地址"
+
+msgid "Specify an IP address to return for any host in the given domains, Queries in the domains are never forwarded and always replied to with the specified IP address which may be IPv4 or IPv6."
+msgstr "配置特定域名返回特定的IP地址,域名查询将不到上游服务器请求,直接返回配置的IP地址,可用于广告屏蔽。"
+
+msgid "IP Blacklist"
+msgstr "IP黑名单"
+
+msgid "Set Specific ip blacklist."
+msgstr "设置IP黑名单列表"
+
+msgid "Configure IP blacklists that will be filtered from the results of specific DNS server."
+msgstr "配置需要从指定域名服务器结果过滤的IP黑名单。"
+
+msgid "Technical Support"
+msgstr "技术支持"
+
+msgid "If you like this software, please buy me a cup of coffee."
+msgstr "如果本软件对你有帮助,请给作者加个蛋。"
+
+msgid "SmartDNS official website"
+msgstr "SmartDNS官方网站"
+
+msgid "open website"
+msgstr "打开网站"
+
+msgid "Donate to smartdns"
+msgstr "捐助smartdns项目"
+
+msgid "Donate"
+msgstr "捐助"
diff --git a/applications/luci-app-smartdns/root/usr/share/luci/menu.d/luci-app-smartdns.json b/applications/luci-app-smartdns/root/usr/share/luci/menu.d/luci-app-smartdns.json
new file mode 100644
index 000000000..91b440248
--- /dev/null
+++ b/applications/luci-app-smartdns/root/usr/share/luci/menu.d/luci-app-smartdns.json
@@ -0,0 +1,12 @@
+{
+ "admin/services/smartdns": {
+ "title": "SmartDNS",
+ "action": {
+ "type": "view",
+ "path": "smartdns/smartdns"
+ },
+ "depends": {
+ "uci": { "smartdns": true }
+ }
+ }
+}
diff --git a/applications/luci-app-smartdns/root/usr/share/rpcd/acl.d/luci-app-smartdns.json b/applications/luci-app-smartdns/root/usr/share/rpcd/acl.d/luci-app-smartdns.json
new file mode 100644
index 000000000..659d6cd41
--- /dev/null
+++ b/applications/luci-app-smartdns/root/usr/share/rpcd/acl.d/luci-app-smartdns.json
@@ -0,0 +1,21 @@
+{
+ "luci-app-smartdns": {
+ "description": "Grant access to LuCI app smartdns",
+ "read": {
+ "file": {
+ "/etc/smartdns/*": [ "read" ],
+ "/usr/sbin/iptables -t nat -nL PREROUTING": [ "exec" ],
+ "/usr/sbin/ip6tables -t nat -nL PREROUTING": [ "exec" ],
+ "/usr/sbin/smartdns": [ "exec" ]
+ },
+ "ubus": {
+ "service": [ "list" ]
+ }
+ },
+ "write": {
+ "file": {
+ "/etc/smartdns/*": [ "write" ]
+ }
+ }
+ }
+}