smartdns.lua 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. --
  2. -- Copyright (C) 2018-2020 Ruilin Peng (Nick) <[email protected]>.
  3. --
  4. -- smartdns is free software: you can redistribute it and/or modify
  5. -- it under the terms of the GNU General Public License as published by
  6. -- the Free Software Foundation, either version 3 of the License, or
  7. -- (at your option) any later version.
  8. --
  9. -- smartdns is distributed in the hope that it will be useful,
  10. -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. -- GNU General Public License for more details.
  13. --
  14. -- You should have received a copy of the GNU General Public License
  15. -- along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. require ("nixio.fs")
  17. require ("luci.http")
  18. require ("luci.dispatcher")
  19. require ("nixio.fs")
  20. local uci = require "luci.model.uci".cursor()
  21. m = Map("smartdns")
  22. m.title = translate("SmartDNS Server")
  23. m.description = translate("SmartDNS is a local high-performance DNS server, supports finding fastest IP, supports ad filtering, and supports avoiding DNS poisoning.")
  24. m:section(SimpleSection).template = "smartdns/smartdns_status"
  25. -- Basic
  26. s = m:section(TypedSection, "smartdns", translate("Settings"), translate("General Settings"))
  27. s.anonymous = true
  28. s:tab("settings", translate("General Settings"))
  29. s:tab("advanced", translate('Advanced Settings'))
  30. s:tab("seconddns", translate("Second Server Settings"))
  31. s:tab("custom", translate("Custom Settings"))
  32. ---- Eanble
  33. o = s:taboption("settings", Flag, "enabled", translate("Enable"), translate("Enable or disable smartdns server"))
  34. o.default = o.disabled
  35. o.rempty = false
  36. ---- server name
  37. o = s:taboption("settings", Value, "server_name", translate("Server Name"), translate("Smartdns server name"))
  38. o.default = "smartdns"
  39. o.datatype = "hostname"
  40. o.rempty = false
  41. ---- Port
  42. o = s:taboption("settings", Value, "port", translate("Local Port"),
  43. translate("Smartdns local server port, smartdns will be automatically set as main dns when the port is 53."))
  44. o.placeholder = 53
  45. o.default = 53
  46. o.datatype = "port"
  47. o.rempty = false
  48. ---- Enable TCP server
  49. o = s:taboption("settings", Flag, "tcp_server", translate("TCP Server"), translate("Enable TCP DNS Server"))
  50. o.rmempty = false
  51. o.default = o.enabled
  52. o.cfgvalue = function(...)
  53. return Flag.cfgvalue(...) or "1"
  54. end
  55. ---- Support IPV6
  56. o = s:taboption("settings", Flag, "ipv6_server", translate("IPV6 Server"), translate("Enable IPV6 DNS Server"))
  57. o.rmempty = false
  58. o.default = o.enabled
  59. o.cfgvalue = function(...)
  60. return Flag.cfgvalue(...) or "1"
  61. end
  62. ---- Support DualStack ip selection
  63. o = s:taboption("advanced", Flag, "dualstack_ip_selection", translate("Dual-stack IP Selection"), translate("Enable IP selection between IPV4 and IPV6"))
  64. o.rmempty = false
  65. o.default = o.enabled
  66. o.cfgvalue = function(...)
  67. return Flag.cfgvalue(...) or "0"
  68. end
  69. ---- Domain prefetch load
  70. o = s:taboption("advanced", Flag, "prefetch_domain", translate("Domain prefetch"), translate("Enable domain prefetch, accelerate domain response speed."))
  71. o.rmempty = false
  72. o.default = o.disabled
  73. o.cfgvalue = function(...)
  74. return Flag.cfgvalue(...) or "0"
  75. end
  76. ---- Domain Serve expired
  77. o = s:taboption("advanced", Flag, "serve_expired", translate("Serve expired"),
  78. translate("Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."))
  79. o.rmempty = false
  80. o.default = o.enabled
  81. o.cfgvalue = function(...)
  82. return Flag.cfgvalue(...) or "0"
  83. end
  84. ---- cache-size
  85. o = s:taboption("advanced", Value, "cache_size", translate("Cache Size"), translate("DNS domain result cache size"))
  86. o.rempty = true
  87. -- cache-size
  88. o = s:taboption("advanced", Flag, "resolve_local_hostnames", translate("Resolve Local Hostnames"), translate("Resolve local hostnames by reading Dnsmasq lease file."))
  89. o.rmempty = false
  90. o.default = o.enabled
  91. o.cfgvalue = function(...)
  92. return Flag.cfgvalue(...) or "1"
  93. end
  94. -- Automatically Set Dnsmasq
  95. o = s:taboption("advanced", Flag, "auto_set_dnsmasq", translate("Automatically Set Dnsmasq"), translate("Automatically set as upstream of dnsmasq when port changes."))
  96. o.rmempty = false
  97. o.default = o.enabled
  98. o.cfgvalue = function(...)
  99. return Flag.cfgvalue(...) or "0"
  100. end
  101. -- Force AAAA SOA
  102. o = s:taboption("advanced", Flag, "force_aaaa_soa", translate("Force AAAA SOA"), translate("Force AAAA SOA."))
  103. o.rmempty = false
  104. o.default = o.enabled
  105. o.cfgvalue = function(...)
  106. return Flag.cfgvalue(...) or "0"
  107. end
  108. -- Force HTTPS SOA
  109. o = s:taboption("advanced", Flag, "force_https_soa", translate("Force HTTPS SOA"), translate("Force HTTPS SOA."))
  110. o.rmempty = false
  111. o.default = o.enabled
  112. o.cfgvalue = function(...)
  113. return Flag.cfgvalue(...) or "1"
  114. end
  115. ---- rr-ttl
  116. o = s:taboption("advanced", Value, "rr_ttl", translate("Domain TTL"), translate("TTL for all domain result."))
  117. o.rempty = true
  118. ---- rr-ttl-min
  119. o = s:taboption("advanced", Value, "rr_ttl_min", translate("Domain TTL Min"), translate("Minimum TTL for all domain result."))
  120. o.rempty = true
  121. o.placeholder = "600"
  122. o.default = 600
  123. o.optional = true
  124. ---- rr-ttl-max
  125. o = s:taboption("advanced", Value, "rr_ttl_max", translate("Domain TTL Max"), translate("Maximum TTL for all domain result."))
  126. o.rempty = true
  127. ---- rr-ttl-reply-max
  128. o = s:taboption("advanced", Value, "rr_ttl_reply_max", translate("Reply Domain TTL Max"), translate("Reply maximum TTL for all domain result."))
  129. o.rempty = true
  130. o = s:taboption("advanced", DynamicList, "conf_files", translate("Include Config Files<br>/etc/smartdns/conf.d"),
  131. translate("Include other config files from /etc/smartdns/conf.d or custom path, can be downloaded from the download page."));
  132. uci:foreach("smartdns", "download-file", function(section)
  133. local filetype = section.type
  134. if (filetype ~= 'config') then
  135. return
  136. end
  137. o:value(section.name);
  138. end)
  139. ---- second dns server
  140. ---- Eanble
  141. o = s:taboption("seconddns", Flag, "seconddns_enabled", translate("Enable"), translate("Enable or disable second DNS server."))
  142. o.default = o.disabled
  143. o.rempty = false
  144. ---- Port
  145. o = s:taboption("seconddns", Value, "seconddns_port", translate("Local Port"), translate("Smartdns local server port"))
  146. o.placeholder = 6553
  147. o.default = 6553
  148. o.datatype = "port"
  149. o.rempty = false
  150. ---- Enable TCP server
  151. o = s:taboption("seconddns", Flag, "seconddns_tcp_server", translate("TCP Server"), translate("Enable TCP DNS Server"))
  152. o.rmempty = false
  153. o.default = o.enabled
  154. o.cfgvalue = function(...)
  155. return Flag.cfgvalue(...) or "1"
  156. end
  157. ---- dns server group
  158. o = s:taboption("seconddns", Value, "seconddns_server_group", translate("Server Group"), translate("Query DNS through specific dns server group, such as office, home."))
  159. o.rmempty = true
  160. o.placeholder = "default"
  161. o.datatype = "hostname"
  162. o.rempty = true
  163. o = s:taboption("seconddns", Flag, "seconddns_no_speed_check", translate("Skip Speed Check"), translate("Do not check speed."))
  164. o.rmempty = false
  165. o.default = o.disabled
  166. o.cfgvalue = function(...)
  167. return Flag.cfgvalue(...) or "0"
  168. end
  169. ---- skip address rules
  170. o = s:taboption("seconddns", Flag, "seconddns_no_rule_addr", translate("Skip Address Rules"), translate("Skip address rules."))
  171. o.rmempty = false
  172. o.default = o.disabled
  173. o.cfgvalue = function(...)
  174. return Flag.cfgvalue(...) or "0"
  175. end
  176. ---- skip name server rules
  177. o = s:taboption("seconddns", Flag, "seconddns_no_rule_nameserver", translate("Skip Nameserver Rule"), translate("Skip nameserver rules."))
  178. o.rmempty = false
  179. o.default = o.disabled
  180. o.cfgvalue = function(...)
  181. return Flag.cfgvalue(...) or "0"
  182. end
  183. ---- skip ipset rules
  184. o = s:taboption("seconddns", Flag, "seconddns_no_rule_ipset", translate("Skip Ipset Rule"), translate("Skip ipset rules."))
  185. o.rmempty = false
  186. o.default = o.disabled
  187. o.cfgvalue = function(...)
  188. return Flag.cfgvalue(...) or "0"
  189. end
  190. ---- skip soa address rule
  191. o = s:taboption("seconddns", Flag, "seconddns_no_rule_soa", translate("Skip SOA Address Rule"), translate("Skip SOA address rules."))
  192. o.rmempty = false
  193. o.default = o.disabled
  194. o.cfgvalue = function(...)
  195. return Flag.cfgvalue(...) or "0"
  196. end
  197. o = s:taboption("seconddns", Flag, "seconddns_no_dualstack_selection", translate("Skip Dualstack Selection"), translate("Skip Dualstack Selection."))
  198. o.rmempty = false
  199. o.default = o.disabled
  200. o.cfgvalue = function(...)
  201. return Flag.cfgvalue(...) or "0"
  202. end
  203. ---- skip cache
  204. o = s:taboption("seconddns", Flag, "seconddns_no_cache", translate("Skip Cache"), translate("Skip Cache."))
  205. o.rmempty = false
  206. o.default = o.disabled
  207. o.cfgvalue = function(...)
  208. return Flag.cfgvalue(...) or "0"
  209. end
  210. ---- Force AAAA SOA
  211. o = s:taboption("seconddns", Flag, "seconddns_force_aaaa_soa", translate("Force AAAA SOA"), translate("Force AAAA SOA."))
  212. o.rmempty = false
  213. o.default = o.disabled
  214. o.cfgvalue = function(...)
  215. return Flag.cfgvalue(...) or "0"
  216. end
  217. ----- custom settings
  218. custom = s:taboption("custom", Value, "Custom Settings",
  219. translate(""),
  220. translate("smartdns custom settings"))
  221. custom.template = "cbi/tvalue"
  222. custom.rows = 20
  223. function custom.cfgvalue(self, section)
  224. return nixio.fs.readfile("/etc/smartdns/custom.conf")
  225. end
  226. function custom.write(self, section, value)
  227. value = value:gsub("\r\n?", "\n")
  228. nixio.fs.writefile("/etc/smartdns/custom.conf", value)
  229. end
  230. o = s:taboption("custom", Flag, "coredump", translate("Generate Coredump"), translate("Generate Coredump file when smartdns crash, coredump file is located at /tmp/smartdns.xxx.core."))
  231. o.rmempty = false
  232. o.default = o.disabled
  233. o.cfgvalue = function(...)
  234. return Flag.cfgvalue(...) or "0"
  235. end
  236. -- Upstream servers
  237. s = m:section(TypedSection, "server", translate("Upstream Servers"), translate("Upstream Servers, support UDP, TCP protocol. " ..
  238. "Please configure multiple DNS servers, including multiple foreign DNS servers."))
  239. s.anonymous = true
  240. s.addremove = true
  241. s.template = "cbi/tblsection"
  242. s.extedit = luci.dispatcher.build_url("admin/services/smartdns/upstream/%s")
  243. ---- enable flag
  244. o = s:option(Flag, "enabled", translate("Enable"), translate("Enable"))
  245. o.rmempty = false
  246. o.default = o.enabled
  247. o.cfgvalue = function(...)
  248. return Flag.cfgvalue(...) or "1"
  249. end
  250. ---- name
  251. s:option(Value, "name", translate("DNS Server Name"), translate("DNS Server Name"))
  252. ---- IP address
  253. o = s:option(Value, "ip", translate("ip"), translate("DNS Server ip"))
  254. o.datatype = "or(ipaddr, string)"
  255. o.rmempty = false
  256. ---- port
  257. o = s:option(Value, "port", translate("port"), translate("DNS Server port"))
  258. o.placeholder = "default"
  259. o.datatype = "port"
  260. o.rempty = true
  261. o:depends("type", "udp")
  262. o:depends("type", "tcp")
  263. o:depends("type", "tls")
  264. ---- type
  265. o = s:option(ListValue, "type", translate("type"), translate("DNS Server type"))
  266. o.placeholder = "udp"
  267. o:value("udp", translate("udp"))
  268. o:value("tcp", translate("tcp"))
  269. o:value("tls", translate("tls"))
  270. o:value("https", translate("https"))
  271. o.default = "udp"
  272. o.rempty = false
  273. ---- domain rules;
  274. s = m:section(TypedSection, "domain-rule", translate("Domain Rules"), translate("Domain Rules Settings"))
  275. s.anonymous = true
  276. s.nodescriptions = true
  277. s:tab("forwarding", translate('DNS Forwarding Setting'))
  278. s:tab("block", translate("DNS Block Setting"))
  279. s:tab("domain-address", translate("Domain Address"), translate("Set Specific domain ip address."))
  280. s:tab("blackip-list", translate("IP Blacklist"), translate("Set Specific ip blacklist."))
  281. ---- domain forwarding;
  282. o = s:taboption("forwarding", Value, "server_group", translate("Server Group"), translate("DNS Server group belongs to, such as office, home."))
  283. o.rmempty = true
  284. o.placeholder = "default"
  285. o.datatype = "hostname"
  286. o.rempty = true
  287. uci:foreach("smartdns", "server", function(section)
  288. local server_group = section.server_group
  289. o:value(server_group);
  290. end)
  291. function o.validate (section_id, value)
  292. if (value == "") then
  293. return value
  294. end
  295. local exists = false
  296. uci:foreach("smartdns", "server", function(section)
  297. local server_group = section.server_group
  298. if (exists == true) then
  299. return
  300. end
  301. if (value == server_group) then
  302. exists = true
  303. end
  304. end)
  305. if (exists == false) then
  306. return nil, translate('Server Group not exists')
  307. end
  308. return value;
  309. end
  310. o = s:taboption("forwarding", Flag, "no_speed_check", translate("Skip Speed Check"),
  311. translate("Do not check speed."))
  312. o.rmempty = false
  313. o.default = o.disabled
  314. o = s:taboption("forwarding", Flag, "force_aaaa_soa", translate("Force AAAA SOA"), translate("Force AAAA SOA."))
  315. o.rmempty = false
  316. o.default = o.disabled
  317. o = s:taboption("forwarding", Value, "ipset_name", translate("IPset Name"), translate("IPset name."))
  318. o.rmempty = true
  319. o.datatype = "hostname"
  320. o.rempty = true
  321. o = s:taboption("forwarding", Value, "nftset_name", translate("NFTset Name"), translate("NFTset name, format: [#[4|6]:[family#table#set]]"))
  322. o.rmempty = true
  323. o.datatype = "string"
  324. o.rempty = true
  325. function o.validate(self, value)
  326. if (value == "") then
  327. return value
  328. end
  329. if (value:match("#[4|6]:[a-zA-Z0-9%-_]+#[a-zA-Z0-9%-_]+#[a-zA-Z0-9%-_]+$")) then
  330. return value
  331. end
  332. return nil, translate("NFTset name format error, format: [#[4|6]:[family#table#set]]")
  333. end
  334. o = s:taboption("forwarding", FileUpload, "forwarding_domain_set_file", translate("Domain List File"),
  335. translate("Upload domain list file, or configure auto download from Download File Setting page."))
  336. o.rmempty = true
  337. o.datatype = "file"
  338. o.rempty = true
  339. o.editable = true
  340. o.root_directory = "/etc/smartdns/domain-set"
  341. o = s:taboption("forwarding", TextValue, "domain_forwarding_list",
  342. translate("Domain List"), translate("Configure forwarding domain name list."))
  343. o.rows = 10
  344. o.cols = 64
  345. o.monospace = true
  346. function o.cfgvalue(self, section)
  347. return nixio.fs.readfile("/etc/smartdns/domain-forwarding.list")
  348. end
  349. function o.write(self, section, value)
  350. value = value:gsub("\r\n?", "\n")
  351. nixio.fs.writefile("/etc/smartdns/domain-forwarding.list", value)
  352. end
  353. ---- domain block;
  354. o = s:taboption("block", FileUpload, "block_domain_set_file", translate("Domain List File"), translate("Upload domain list file."))
  355. o.rmempty = true
  356. o.datatype = "file"
  357. o.rempty = true
  358. o.editable = true
  359. o.root_directory = "/etc/smartdns/domain-set"
  360. o = s:taboption("block", TextValue, "domain_block_list",
  361. translate("Domain List"), translate("Configure block domain list."))
  362. o.rows = 10
  363. o.cols = 64
  364. function o.cfgvalue(self, section)
  365. return nixio.fs.readfile("/etc/smartdns/domain-block.list")
  366. end
  367. function o.write(self, section, value)
  368. value = value:gsub("\r\n?", "\n")
  369. nixio.fs.writefile("/etc/smartdns/domain-block.list", value)
  370. end
  371. -- Doman addresss
  372. addr = s:taboption("domain-address", Value, "address",
  373. translate(""),
  374. translate("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."))
  375. addr.template = "cbi/tvalue"
  376. addr.rows = 20
  377. function addr.cfgvalue(self, section)
  378. return nixio.fs.readfile("/etc/smartdns/address.conf")
  379. end
  380. function addr.write(self, section, value)
  381. value = value:gsub("\r\n?", "\n")
  382. nixio.fs.writefile("/etc/smartdns/address.conf", value)
  383. end
  384. -- IP Blacklist
  385. addr = s:taboption("blackip-list", Value, "blacklist_ip",
  386. translate(""),
  387. translate("Configure IP blacklists that will be filtered from the results of specific DNS server."))
  388. addr.template = "cbi/tvalue"
  389. addr.rows = 20
  390. function addr.cfgvalue(self, section)
  391. return nixio.fs.readfile("/etc/smartdns/blacklist-ip.conf")
  392. end
  393. function addr.write(self, section, value)
  394. value = value:gsub("\r\n?", "\n")
  395. nixio.fs.writefile("/etc/smartdns/blacklist-ip.conf", value)
  396. end
  397. s = m:section(TypedSection, "smartdns", translate("Download Files Setting"), translate("Download domain list files for domain-rule and include config files, please refresh the page after download to take effect."))
  398. s.anonymous = true
  399. ---- download Files Settings
  400. o = s:option(Flag, "enable_auto_update", translate("Enable Auto Update"), translate("Enable daily auto update."))
  401. o.rmempty = false
  402. o.default = o.disabled
  403. o.rempty = true
  404. o = s:option(FileUpload, "upload_conf_file", translate("Upload Config File"),
  405. translate("Upload smartdns config file to /etc/smartdns/conf.d"))
  406. o.rmempty = true
  407. o.datatype = "file"
  408. o.rempty = true
  409. o.editable = true
  410. o.root_directory = "/etc/smartdns/conf.d"
  411. o = s:option(FileUpload, "upload_list_file", translate("Upload Domain List File"),
  412. translate("Upload domain list file to /etc/smartdns/domain-set"))
  413. o.rmempty = true
  414. o.datatype = "file"
  415. o.rempty = true
  416. o.editable = true
  417. o.root_directory = "/etc/smartdns/domain-set"
  418. o = s:option(Button, "_updateate")
  419. o.title = translate("Update Files")
  420. o.inputtitle = translate("update domain list files")
  421. o.inputstyle = "apply"
  422. o.write = function()
  423. luci.sys.call("/etc/init.d/smartdns updatefiles >/dev/null 2>&1")
  424. end
  425. s = m:section(TypedSection, "download-file", translate("Download Files"), translate("List of files to download."))
  426. s.anonymous = true
  427. s.addremove = true
  428. s.template = "cbi/tblsection"
  429. o = s:option(Value, 'name', translate('File Name'), translate('File Name'))
  430. o.rmempty = false
  431. o.datatype = 'string'
  432. o = s:option(Value, 'url', translate('URL'), translate('URL'))
  433. o.rmempty = false
  434. o.datatype = 'string'
  435. function o.validate(self, value, section)
  436. if value == "" then
  437. return nil
  438. end
  439. if value.find(value, "http://") then
  440. return value
  441. end
  442. if value.find(value, "https://") then
  443. return value
  444. end
  445. return nil, translate("URL format error, format: http:// or https://")
  446. end
  447. o = s:option(ListValue, "type", translate("type"), translate("File Type"))
  448. o:value("list", translate("domain list (/etc/smartdns/domain-set)"))
  449. o:value("config", translate("smartdns config (/etc/smartdns/conf.d)"))
  450. o.default = "list"
  451. o.rempty = false
  452. o = s:option(Value, 'desc', translate('Description'), translate('Description'))
  453. o.rmempty = true
  454. o.datatype = 'string'
  455. -- Technical Support
  456. s = m:section(TypedSection, "smartdns", translate("Technical Support"),
  457. translate("If you like this software, please buy me a cup of coffee."))
  458. s.anonymous = true
  459. o = s:option(Button, "web")
  460. o.title = translate("SmartDNS official website")
  461. o.inputtitle = translate("open website")
  462. o.inputstyle = "apply"
  463. o.write = function()
  464. luci.http.redirect("https://pymumu.github.io/smartdns")
  465. end
  466. o = s:option(Button, "Donate")
  467. o.title = translate("Donate to smartdns")
  468. o.inputtitle = translate("Donate")
  469. o.inputstyle = "apply"
  470. o.write = function()
  471. luci.http.redirect("https://pymumu.github.io/smartdns/#donate")
  472. end
  473. o = s:option(Button, "Restart")
  474. o.title = translate("Restart smartdns")
  475. o.inputtitle = translate("Restart")
  476. o.inputstyle = "apply"
  477. o.write = function()
  478. luci.sys.call("/etc/init.d/smartdns restart >/dev/null 2>&1")
  479. end
  480. return m