smartdns.js 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. /*************************************************************************
  2. *
  3. * Copyright (C) 2018-2020 Ruilin Peng (Nick) <[email protected]>.
  4. *
  5. * smartdns is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * smartdns is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. 'use strict';
  19. 'require fs';
  20. 'require uci';
  21. 'require form';
  22. 'require view';
  23. 'require poll';
  24. 'require rpc';
  25. 'require ui';
  26. var conf = 'smartdns';
  27. var callServiceList = rpc.declare({
  28. object: 'service',
  29. method: 'list',
  30. params: ['name'],
  31. expect: { '': {} }
  32. });
  33. var pollAdded = false;
  34. function getServiceStatus() {
  35. return L.resolveDefault(callServiceList(conf), {})
  36. .then(function (res) {
  37. var isrunning = false;
  38. try {
  39. isrunning = res[conf]['instances']['smartdns']['running'];
  40. } catch (e) { }
  41. return isrunning;
  42. });
  43. }
  44. function smartdnsServiceStatus() {
  45. return Promise.all([
  46. getServiceStatus()
  47. ]);
  48. }
  49. function smartdnsRenderStatus(res) {
  50. var renderHTML = "";
  51. var isRunning = res[0];
  52. var autoSetDnsmasq = uci.get_first('smartdns', 'smartdns', 'auto_set_dnsmasq');
  53. var smartdnsPort = uci.get_first('smartdns', 'smartdns', 'port');
  54. var dnsmasqServer = uci.get_first('dhcp', 'dnsmasq', 'server');
  55. if (isRunning) {
  56. renderHTML += "<span style=\"color:green;font-weight:bold\">SmartDNS - " + _("RUNNING") + "</span>";
  57. } else {
  58. renderHTML += "<span style=\"color:red;font-weight:bold\">SmartDNS - " + _("NOT RUNNING") + "</span>";
  59. return renderHTML;
  60. }
  61. if (autoSetDnsmasq === '1' && smartdnsPort != '53') {
  62. var matchLine = "127.0.0.1#" + smartdnsPort;
  63. uci.unload('dhcp');
  64. uci.load('dhcp');
  65. if (dnsmasqServer == undefined || dnsmasqServer.indexOf(matchLine) < 0) {
  66. renderHTML += "<br /><span style=\"color:red;font-weight:bold\">" + _("Dnsmasq Forwared To Smartdns Failure") + "</span>";
  67. }
  68. }
  69. return renderHTML;
  70. }
  71. return view.extend({
  72. load: function () {
  73. return Promise.all([
  74. uci.load('dhcp'),
  75. uci.load('smartdns'),
  76. ]);
  77. },
  78. render: function (stats) {
  79. var m, s, o;
  80. var ss, so;
  81. var servers, downlfiles;
  82. m = new form.Map('smartdns', _('SmartDNS'));
  83. m.title = _("SmartDNS Server");
  84. m.description = _("SmartDNS is a local high-performance DNS server, supports finding fastest IP, "
  85. + "supports ad filtering, and supports avoiding DNS poisoning.");
  86. s = m.section(form.NamedSection, '_status');
  87. s.anonymous = true;
  88. s.render = function (section_id) {
  89. var renderStatus = function () {
  90. return L.resolveDefault(smartdnsServiceStatus()).then(function (res) {
  91. var view = document.getElementById("service_status");
  92. if (view == null) {
  93. return;
  94. }
  95. view.innerHTML = smartdnsRenderStatus(res);
  96. });
  97. }
  98. if (pollAdded == false) {
  99. poll.add(renderStatus, 1);
  100. pollAdded = true;
  101. }
  102. return E('div', { class: 'cbi-section' }, [
  103. E('div', { id: 'service_status' },
  104. _('Collecting data ...'))
  105. ]);
  106. }
  107. ////////////////
  108. // Basic;
  109. ////////////////
  110. s = m.section(form.TypedSection, "smartdns", _("Settings"), _("General Settings"));
  111. s.anonymous = true;
  112. s.tab("settings", _("General Settings"));
  113. s.tab("advanced", _('Advanced Settings'));
  114. s.tab("seconddns", _("Second Server Settings"));
  115. s.tab("files", _("Download Files Setting"), _("Download domain list files for domain-rule and include config files, please refresh the page after download to take effect."));
  116. s.tab("proxy", _("Proxy Server Settings"));
  117. s.tab("custom", _("Custom Settings"));
  118. ///////////////////////////////////////
  119. // Basic Settings
  120. ///////////////////////////////////////
  121. o = s.taboption("settings", form.Flag, "enabled", _("Enable"), _("Enable or disable smartdns server"));
  122. o.rmempty = false;
  123. o.default = o.disabled;
  124. // server name;
  125. o = s.taboption("settings", form.Value, "server_name", _("Server Name"), _("Smartdns server name"));
  126. o.default = "smartdns";
  127. o.datatype = "hostname";
  128. o.rempty = false;
  129. // Port;
  130. o = s.taboption("settings", form.Value, "port", _("Local Port"),
  131. _("Smartdns local server port, smartdns will be automatically set as main dns when the port is 53."));
  132. o.placeholder = 53;
  133. o.default = 53;
  134. o.datatype = "port";
  135. o.rempty = false;
  136. ///////////////////////////////////////
  137. // advanced settings;
  138. ///////////////////////////////////////
  139. // Speed check mode;
  140. o = s.taboption("advanced", form.Value, "speed_check_mode", _("Speed Check Mode"), _("Smartdns speed check mode."));
  141. o.rmempty = true;
  142. o.placeholder = "default";
  143. o.value("", _("default"));
  144. o.value("ping,tcp:80,tcp:443");
  145. o.value("ping,tcp:443,tcp:80");
  146. o.value("tcp:80,tcp:443,ping");
  147. o.value("tcp:443,tcp:80,ping");
  148. o.value("none", _("None"));
  149. o.validate = function (section_id, value) {
  150. if (value == "") {
  151. return true;
  152. }
  153. if (value == "none") {
  154. return true;
  155. }
  156. var check_mode = value.split(",")
  157. for (var i = 0; i < check_mode.length; i++) {
  158. if (check_mode[i] == "ping") {
  159. continue;
  160. }
  161. if (check_mode[i].indexOf("tcp:") == 0) {
  162. var port = check_mode[i].split(":")[1];
  163. if (port == "") {
  164. return _("TCP port is empty");
  165. }
  166. continue;
  167. }
  168. return _("Speed check mode is invalid.");
  169. }
  170. return true;
  171. }
  172. // Enable TCP server;
  173. o = s.taboption("advanced", form.Flag, "tcp_server", _("TCP Server"), _("Enable TCP DNS Server"));
  174. o.rmempty = false;
  175. o.default = o.enabled;
  176. // Support IPV6;
  177. o = s.taboption("advanced", form.Flag, "ipv6_server", _("IPV6 Server"), _("Enable IPV6 DNS Server"));
  178. o.rmempty = false;
  179. o.default = o.enabled;
  180. // bind to device;
  181. o = s.taboption("advanced", form.Flag, "bind_device", _("Bind Device"), _("Listen only on the specified interfaces."));
  182. o.rmempty = false;
  183. o.default = o.enabled;
  184. // bind device name;
  185. o = s.taboption("advanced", form.Value, "bind_device_name", _("Bind Device Name"), _("Name of device name listen on."));
  186. o.placeholder = "default";
  187. o.rempty = true;
  188. o.datatype = "string";
  189. // Support DualStack ip selection;
  190. o = s.taboption("advanced", form.Flag, "dualstack_ip_selection", _("Dual-stack IP Selection"),
  191. _("Enable IP selection between IPV4 and IPV6"));
  192. o.rmempty = false;
  193. o.default = o.enabled;
  194. // Domain prefetch load ;
  195. o = s.taboption("advanced", form.Flag, "prefetch_domain", _("Domain prefetch"),
  196. _("Enable domain prefetch, accelerate domain response speed."));
  197. o.rmempty = false;
  198. o.default = o.disabled;
  199. // Domain Serve expired
  200. o = s.taboption("advanced", form.Flag, "serve_expired", _("Serve expired"),
  201. _("Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."));
  202. o.rmempty = false;
  203. o.default = o.enabled;
  204. // cache-size;
  205. o = s.taboption("advanced", form.Value, "cache_size", _("Cache Size"), _("DNS domain result cache size"));
  206. o.rempty = true;
  207. // cache-size;
  208. o = s.taboption("advanced", form.Flag, "resolve_local_hostnames", _("Resolve Local Hostnames"), _("Resolve local hostnames by reading Dnsmasq lease file."));
  209. o.rmempty = false;
  210. o.default = o.enabled;
  211. // auto-conf-dnsmasq;
  212. o = s.taboption("advanced", form.Flag, "auto_set_dnsmasq", _("Automatically Set Dnsmasq"), _("Automatically set as upstream of dnsmasq when port changes."));
  213. o.rmempty = false;
  214. o.default = o.enabled;
  215. // Force AAAA SOA
  216. o = s.taboption("advanced", form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
  217. o.rmempty = false;
  218. o.default = o.disabled;
  219. // Force HTTPS SOA
  220. o = s.taboption("advanced", form.Flag, "force_https_soa", _("Force HTTPS SOA"), _("Force HTTPS SOA."));
  221. o.rmempty = false;
  222. o.default = o.enabled;
  223. // rr-ttl;
  224. o = s.taboption("advanced", form.Value, "rr_ttl", _("Domain TTL"), _("TTL for all domain result."));
  225. o.rempty = true;
  226. // rr-ttl-min;
  227. o = s.taboption("advanced", form.Value, "rr_ttl_min", _("Domain TTL Min"),
  228. _("Minimum TTL for all domain result."));
  229. o.rempty = true;
  230. o.placeholder = "600";
  231. o.default = 600;
  232. o.optional = true;
  233. // rr-ttl-max;
  234. o = s.taboption("advanced", form.Value, "rr_ttl_max", _("Domain TTL Max"),
  235. _("Maximum TTL for all domain result."));
  236. o.rempty = true;
  237. // rr-ttl-reply-max;
  238. o = s.taboption("advanced", form.Value, "rr_ttl_reply_max", _("Reply Domain TTL Max"),
  239. _("Reply maximum TTL for all domain result."));
  240. o.rempty = true;
  241. // include config
  242. downlfiles = uci.sections('smartdns', 'download-file');
  243. o = s.taboption("advanced", form.DynamicList, "conf_files", _("Include Config Files<br>/etc/smartdns/conf.d"),
  244. _("Include other config files from /etc/smartdns/conf.d or custom path, can be downloaded from the download page."));
  245. for (var i = 0; i < downlfiles.length; i++) {
  246. if (downlfiles[i].type == undefined) {
  247. continue;
  248. }
  249. if (downlfiles[i].type != 'config') {
  250. continue
  251. }
  252. o.value(downlfiles[i].name);
  253. }
  254. ///////////////////////////////////////
  255. // second dns server;
  256. ///////////////////////////////////////
  257. // Eanble;
  258. o = s.taboption("seconddns", form.Flag, "seconddns_enabled", _("Enable"),
  259. _("Enable or disable second DNS server."));
  260. o.default = o.disabled;
  261. o.rempty = false;
  262. // Port;
  263. o = s.taboption("seconddns", form.Value, "seconddns_port", _("Local Port"), _("Smartdns local server port"));
  264. o.placeholder = 6553;
  265. o.default = 6553;
  266. o.datatype = "port";
  267. o.rempty = false;
  268. // Enable TCP server;
  269. o = s.taboption("seconddns", form.Flag, "seconddns_tcp_server", _("TCP Server"), _("Enable TCP DNS Server"));
  270. o.rmempty = false;
  271. o.default = o.enabled;
  272. // dns server group;
  273. o = s.taboption("seconddns", form.Value, "seconddns_server_group", _("Server Group"),
  274. _("Query DNS through specific dns server group, such as office, home."));
  275. o.rmempty = true;
  276. o.placeholder = "default";
  277. o.datatype = "hostname";
  278. o.rempty = true;
  279. o = s.taboption("seconddns", form.Flag, "seconddns_no_speed_check", _("Skip Speed Check"),
  280. _("Do not check speed."));
  281. o.rmempty = false;
  282. o.default = o.disabled;
  283. // skip address rules;
  284. o = s.taboption("seconddns", form.Flag, "seconddns_no_rule_addr", _("Skip Address Rules"),
  285. _("Skip address rules."));
  286. o.rmempty = false;
  287. o.default = o.disabled;
  288. // skip name server rules;
  289. o = s.taboption("seconddns", form.Flag, "seconddns_no_rule_nameserver", _("Skip Nameserver Rule"),
  290. _("Skip nameserver rules."));
  291. o.rmempty = false;
  292. o.default = o.disabled;
  293. // skip ipset rules;
  294. o = s.taboption("seconddns", form.Flag, "seconddns_no_rule_ipset", _("Skip Ipset Rule"),
  295. _("Skip ipset rules."));
  296. o.rmempty = false;
  297. o.default = o.disabled;
  298. // skip soa address rule;
  299. o = s.taboption("seconddns", form.Flag, "seconddns_no_rule_soa", _("Skip SOA Address Rule"),
  300. _("Skip SOA address rules."));
  301. o.rmempty = false;
  302. o.default = o.disabled;
  303. o = s.taboption("seconddns", form.Flag, "seconddns_no_dualstack_selection", _("Skip Dualstack Selection"),
  304. _("Skip Dualstack Selection."));
  305. o.rmempty = false;
  306. o.default = o.disabled;
  307. // skip cache;
  308. o = s.taboption("seconddns", form.Flag, "seconddns_no_cache", _("Skip Cache"), _("Skip Cache."));
  309. o.rmempty = false;
  310. o.default = o.disabled;
  311. // Force AAAA SOA
  312. o = s.taboption("seconddns", form.Flag, "seconddns_force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
  313. o.rmempty = false;
  314. o.default = o.disabled;
  315. ///////////////////////////////////////
  316. // download Files Settings
  317. ///////////////////////////////////////
  318. o = s.taboption("files", form.Flag, "enable_auto_update", _("Enable Auto Update"), _("Enable daily auto update."));
  319. o.rmempty = false;
  320. o.default = o.disabled;
  321. o.rempty = true;
  322. o = s.taboption("files", form.FileUpload, "upload_conf_file", _("Upload Config File"),
  323. _("Upload smartdns config file to /etc/smartdns/conf.d"));
  324. o.rmempty = true
  325. o.datatype = "file"
  326. o.rempty = true
  327. o.root_directory = "/etc/smartdns/conf.d"
  328. o = s.taboption("files", form.FileUpload, "upload_list_file", _("Upload Domain List File"),
  329. _("Upload domain list file to /etc/smartdns/domain-set"));
  330. o.rmempty = true
  331. o.datatype = "file"
  332. o.rempty = true
  333. o.root_directory = "/etc/smartdns/domain-set"
  334. o = s.taboption('files', form.DummyValue, "_update", _("Update Files"));
  335. o.renderWidget = function () {
  336. return E('button', {
  337. 'class': 'btn cbi-button cbi-button-apply',
  338. 'id': 'btn_update',
  339. 'click': ui.createHandlerFn(this, function () {
  340. return fs.exec('/etc/init.d/smartdns', ['updatefiles'])
  341. .catch(function (e) { ui.addNotification(null, E('p', e.message), 'error') });
  342. })
  343. }, [_("Update")]);
  344. }
  345. o = s.taboption('files', form.SectionValue, '__files__', form.GridSection, 'download-file', _('Download Files'),
  346. _('List of files to download.'));
  347. ss = o.subsection;
  348. ss.addremove = true;
  349. ss.anonymous = true;
  350. ss.sortable = true;
  351. so = ss.option(form.Value, 'name', _('File Name'), _('File Name'));
  352. so.rmempty = false;
  353. so.datatype = 'file';
  354. so = ss.option(form.Value, 'url', _('URL'), _('URL'));
  355. so.rmempty = false;
  356. so.datatype = 'string';
  357. so.validate = function (section_id, value) {
  358. if (value == "") {
  359. return true;
  360. }
  361. if (!value.match(/^(http|https|ftp|sftp):\/\//)) {
  362. return _("URL format error, format: http:// or https://");
  363. }
  364. return true;
  365. }
  366. so = ss.option(form.ListValue, "type", _("type"), _("File Type"));
  367. so.value("list", _("domain list (/etc/smartdns/domain-set)"));
  368. so.value("config", _("smartdns config (/etc/smartdns/conf.d)"));
  369. so.default = "list";
  370. so.rempty = false;
  371. so = ss.option(form.Value, 'desc', _('Description'), _('Description'));
  372. so.rmempty = true;
  373. so.datatype = 'string';
  374. ///////////////////////////////////////
  375. // Proxy server settings;
  376. ///////////////////////////////////////
  377. o = s.taboption("proxy", form.Value, "proxy_server", _("Proxy Server"), _("Proxy Server URL, format: [socks5|http]://user:pass@ip:port."));
  378. o.datatype = 'string';
  379. o.validate = function (section_id, value) {
  380. if (value == "") {
  381. return true;
  382. }
  383. if (!value.match(/^(socks5|http):\/\//)) {
  384. return _("Proxy server URL format error, format: [socks5|http]://user:pass@ip:port.");
  385. }
  386. return true;
  387. }
  388. ///////////////////////////////////////
  389. // custom settings;
  390. ///////////////////////////////////////
  391. o = s.taboption("custom", form.TextValue, "custom_conf",
  392. "", _("smartdns custom settings"));
  393. o.rows = 20;
  394. o.cfgvalue = function (section_id) {
  395. return fs.trimmed('/etc/smartdns/custom.conf');
  396. };
  397. o.write = function (section_id, formvalue) {
  398. return this.cfgvalue(section_id).then(function (value) {
  399. if (value == formvalue) {
  400. return
  401. }
  402. return fs.write('/etc/smartdns/custom.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
  403. });
  404. };
  405. o = s.taboption("custom", form.Flag, "coredump", _("Generate Coredump"),
  406. _("Generate Coredump file when smartdns crash, coredump file is located at /tmp/smartdns.xxx.core."));
  407. o.rmempty = false;
  408. o.default = o.disabled;
  409. ////////////////
  410. // Upstream servers;
  411. ////////////////
  412. s = m.section(form.GridSection, "server", _("Upstream Servers"),
  413. _("Upstream Servers, support UDP, TCP protocol. Please configure multiple DNS servers, "
  414. + "including multiple foreign DNS servers."));
  415. s.anonymous = true;
  416. s.addremove = true;
  417. s.sortable = true;
  418. s.tab('general', _('General Settings'));
  419. s.tab('advanced', _('Advanced Settings'));
  420. // enable flag;
  421. o = s.taboption("general", form.Flag, "enabled", _("Enable"), _("Enable"));
  422. o.rmempty = false;
  423. o.default = o.enabled;
  424. o.editable = true;
  425. // name;
  426. o = s.taboption("general", form.Value, "name", _("DNS Server Name"), _("DNS Server Name"));
  427. // IP address;
  428. o = s.taboption("general", form.Value, "ip", _("ip"), _("DNS Server ip"));
  429. o.datatype = "or(ipaddr, string)";
  430. o.rmempty = false;
  431. // port;
  432. o = s.taboption("general", form.Value, "port", _("port"), _("DNS Server port"));
  433. o.placeholder = "default";
  434. o.datatype = "port";
  435. o.rempty = true;
  436. o.depends("type", "udp");
  437. o.depends("type", "tcp");
  438. o.depends("type", "tls");
  439. // type;
  440. o = s.taboption("general", form.ListValue, "type", _("type"), _("DNS Server type"));
  441. o.placeholder = "udp";
  442. o.value("udp", _("udp"));
  443. o.value("tcp", _("tcp"));
  444. o.value("tls", _("tls"));
  445. o.value("https", _("https"));
  446. o.default = "udp";
  447. o.rempty = false;
  448. // server group
  449. o = s.taboption("general", form.Value, "server_group", _("Server Group"), _("DNS Server group"))
  450. o.rmempty = true;
  451. o.placeholder = "default";
  452. o.datatype = "hostname";
  453. o.rempty = true;
  454. servers = uci.sections('smartdns', 'server');
  455. var groupnames = new Set();
  456. for (var i = 0; i < servers.length; i++) {
  457. if (servers[i].server_group == undefined) {
  458. continue;
  459. }
  460. groupnames.add(servers[i].server_group);
  461. }
  462. for (const groupname of groupnames) {
  463. o.value(groupname);
  464. }
  465. // Advanced Options
  466. o = s.taboption("advanced", form.Flag, "exclude_default_group", _("Exclude Default Group"), _("Exclude DNS Server from default group."))
  467. o.rmempty = false;
  468. o.default = o.disabled;
  469. o.editable = true;
  470. o.modalonly = true;
  471. // blacklist_ip
  472. o = s.taboption("advanced", form.Flag, "blacklist_ip", _("IP Blacklist Filtering"),
  473. _("Filtering IP with blacklist"))
  474. o.rmempty = false
  475. o.default = o.disabled
  476. o.modalonly = true;
  477. // TLS host verify
  478. o = s.taboption("advanced", form.Value, "tls_host_verify", _("TLS Hostname Verify"),
  479. _("Set TLS hostname to verify."))
  480. o.default = ""
  481. o.datatype = "string"
  482. o.rempty = true
  483. o.modalonly = true;
  484. o.depends("type", "tls")
  485. o.depends("type", "https")
  486. // certificate verify
  487. o = s.taboption("advanced", form.Flag, "no_check_certificate", _("No check certificate"),
  488. _("Do not check certificate."))
  489. o.rmempty = false
  490. o.default = o.disabled
  491. o.modalonly = true;
  492. o.depends("type", "tls")
  493. o.depends("type", "https")
  494. // SNI host name
  495. o = s.taboption("advanced", form.Value, "host_name", _("TLS SNI name"),
  496. _("Sets the server name indication for query. '-' for disable SNI name."))
  497. o.default = ""
  498. o.datatype = "hostname"
  499. o.rempty = true
  500. o.modalonly = true;
  501. o.depends("type", "tls")
  502. o.depends("type", "https")
  503. // http host
  504. o = s.taboption("advanced", form.Value, "http_host", _("HTTP Host"),
  505. _("Set the HTTP host used for the query. Use this parameter when the host of the URL address is an IP address."))
  506. o.default = ""
  507. o.datatype = "hostname"
  508. o.rempty = true
  509. o.modalonly = true;
  510. o.depends("type", "https")
  511. // SPKI pin
  512. o = s.taboption("advanced", form.Value, "spki_pin", _("TLS SPKI Pinning"),
  513. _("Used to verify the validity of the TLS server, The value is Base64 encoded SPKI fingerprint, "
  514. + "leaving blank to indicate that the validity of TLS is not verified."))
  515. o.default = ""
  516. o.datatype = "string"
  517. o.rempty = true
  518. o.modalonly = true;
  519. o.depends("type", "tls")
  520. o.depends("type", "https")
  521. // mark
  522. o = s.taboption("advanced", form.Value, "set_mark", _("Marking Packets"),
  523. _("Set mark on packets."))
  524. o.default = ""
  525. o.rempty = true
  526. o.datatype = "uinteger"
  527. o.modalonly = true;
  528. // use proxy
  529. o = s.taboption("advanced", form.Flag, "use_proxy", _("Use Proxy"),
  530. _("Use proxy to connect to upstream DNS server."))
  531. o.default = o.disabled
  532. o.modalonly = true;
  533. o.optional = true;
  534. o.rempty = true;
  535. o.validate = function(section_id, value) {
  536. var flag = this.formvalue(section_id);
  537. if (flag == "0") {
  538. return true;
  539. }
  540. var proxy_server = uci.sections("smartdns", "smartdns")[0].proxy_server;
  541. var server_type = this.section.formvalue(section_id, "type");
  542. if (proxy_server == "" || proxy_server == undefined) {
  543. return _("Please set proxy server first.");
  544. }
  545. if (server_type == "udp" && !proxy_server.match(/^(socks5):\/\//)) {
  546. return _("Only socks5 proxy support udp server.");
  547. }
  548. return true;
  549. }
  550. // other args
  551. o = s.taboption("advanced", form.Value, "addition_arg", _("Additional Server Args"),
  552. _("Additional Args for upstream dns servers"))
  553. o.default = ""
  554. o.rempty = true
  555. o.modalonly = true;
  556. ////////////////
  557. // domain rules;
  558. ////////////////
  559. s = m.section(form.TypedSection, "domain-rule", _("Domain Rules"), _("Domain Rules Settings"));
  560. s.anonymous = true;
  561. s.nodescriptions = true;
  562. s.tab("forwarding", _('DNS Forwarding Setting'));
  563. s.tab("block", _("DNS Block Setting"));
  564. s.tab("domain-rule-list", _("Domain Rule List"), _("Set Specific domain rule list."));
  565. s.tab("domain-address", _("Domain Address"), _("Set Specific domain ip address."));
  566. s.tab("blackip-list", _("IP Blacklist"), _("Set Specific ip blacklist."));
  567. ///////////////////////////////////////
  568. // domain forwarding;
  569. ///////////////////////////////////////
  570. o = s.taboption("forwarding", form.Value, "server_group", _("Server Group"), _("DNS Server group belongs to, such as office, home."))
  571. o.rmempty = true
  572. o.placeholder = "default"
  573. o.datatype = "hostname"
  574. o.rempty = true
  575. for (const groupname of groupnames) {
  576. o.value(groupname);
  577. }
  578. o.validate = function (section_id, value) {
  579. if (value == "") {
  580. return true;
  581. }
  582. var val = uci.sections('smartdns', 'server');
  583. for (var i = 0; i < val.length; i++) {
  584. if (value == val[i].server_group) {
  585. return true;
  586. }
  587. }
  588. return _('Server Group %s not exists').format(value);
  589. }
  590. o = s.taboption("forwarding", form.Flag, "no_speed_check", _("Skip Speed Check"),
  591. _("Do not check speed."));
  592. o.rmempty = false;
  593. o.default = o.disabled;
  594. o = s.taboption("forwarding", form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
  595. o.rmempty = false;
  596. o.default = o.disabled;
  597. o = s.taboption("forwarding", form.Value, "ipset_name", _("IPset Name"), _("IPset name."));
  598. o.rmempty = true;
  599. o.datatype = "hostname";
  600. o.rempty = true;
  601. o = s.taboption("forwarding", form.Value, "nftset_name", _("NFTset Name"), _("NFTset name, format: [#[4|6]:[family#table#set]]"));
  602. o.rmempty = true;
  603. o.datatype = "string";
  604. o.rempty = true;
  605. o.validate = function (section_id, value) {
  606. if (value == "") {
  607. return true;
  608. }
  609. var nftset = value.split(",")
  610. for (var i = 0; i < nftset.length; i++) {
  611. if (!nftset[i].match(/#[4|6]:[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+$/)) {
  612. return _("NFTset name format error, format: [#[4|6]:[family#table#set]]");
  613. }
  614. }
  615. return true;
  616. }
  617. // other args
  618. o = s.taboption("forwarding", form.Value, "addition_flag", _("Additional Rule Flag"),
  619. _("Additional Flags for rules, read help on domain-rule for more information."))
  620. o.default = ""
  621. o.rempty = true
  622. o.modalonly = true;
  623. o = s.taboption("forwarding", form.FileUpload, "forwarding_domain_set_file", _("Domain List File"),
  624. _("Upload domain list file, or configure auto download from Download File Setting page."));
  625. o.rmempty = true
  626. o.datatype = "file"
  627. o.rempty = true
  628. o.editable = true
  629. o.root_directory = "/etc/smartdns/domain-set"
  630. o = s.taboption("forwarding", form.TextValue, "domain_forwarding_list",
  631. _("Domain List"), _("Configure forwarding domain name list."));
  632. o.rows = 10;
  633. o.cols = 64;
  634. o.monospace = true;
  635. o.cfgvalue = function (section_id) {
  636. return fs.trimmed('/etc/smartdns/domain-forwarding.list').catch(function (e) {
  637. return "";
  638. });
  639. };
  640. o.write = function (section_id, formvalue) {
  641. return this.cfgvalue(section_id).then(function (value) {
  642. if (value == formvalue) {
  643. return
  644. }
  645. return fs.write('/etc/smartdns/domain-forwarding.list', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
  646. });
  647. };
  648. ///////////////////////////////////////
  649. // domain block;
  650. ///////////////////////////////////////
  651. o = s.taboption("block", form.FileUpload, "block_domain_set_file", _("Domain List File"), _("Upload domain list file."));
  652. o.rmempty = true
  653. o.datatype = "file"
  654. o.rempty = true
  655. o.editable = true
  656. o.root_directory = "/etc/smartdns/domain-set"
  657. o = s.taboption("block", form.TextValue, "domain_block_list",
  658. _("Domain List"), _("Configure block domain list."));
  659. o.rows = 10;
  660. o.cols = 64;
  661. o.cfgvalue = function (section_id) {
  662. return fs.trimmed('/etc/smartdns/domain-block.list').catch(function (e) {
  663. return "";
  664. });
  665. };
  666. o.write = function (section_id, formvalue) {
  667. return this.cfgvalue(section_id).then(function (value) {
  668. if (value == formvalue) {
  669. return
  670. }
  671. return fs.write('/etc/smartdns/domain-block.list', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
  672. });
  673. };
  674. ///////////////////////////////////////
  675. // domain rule list;
  676. ///////////////////////////////////////
  677. o = s.taboption('domain-rule-list', form.SectionValue, '__domain-rule-list__', form.GridSection, 'domain-rule-list', _('Domain Rule List'),
  678. _('Configure domain rule list.'));
  679. ss = o.subsection;
  680. ss.addremove = true;
  681. ss.anonymous = true;
  682. ss.sortable = true;
  683. // enable flag;
  684. so = ss.option(form.Flag, "enabled", _("Enable"), _("Enable"));
  685. so.rmempty = false;
  686. so.default = so.enabled;
  687. so.editable = true;
  688. // name;
  689. so = ss.option(form.Value, "name", _("Domain Rule Name"), _("Domain Rule Name"));
  690. so = ss.option(form.Value, "server_group", _("Server Group"), _("DNS Server group belongs to, such as office, home."))
  691. so.rmempty = true
  692. so.placeholder = "default"
  693. so.datatype = "hostname"
  694. so.rempty = true
  695. for (const groupname of groupnames) {
  696. so.value(groupname);
  697. }
  698. so.validate = function (section_id, value) {
  699. if (value == "") {
  700. return true;
  701. }
  702. var val = uci.sections('smartdns', 'server');
  703. for (var i = 0; i < val.length; i++) {
  704. if (value == val[i].server_group) {
  705. return true;
  706. }
  707. }
  708. return _('Server Group %s not exists').format(value);
  709. }
  710. so = ss.option(form.FileUpload, "domain_list_file", _("Domain List File"),
  711. _("Upload domain list file, or configure auto download from Download File Setting page."));
  712. so.rmempty = false
  713. so.datatype = "file"
  714. so.rempty = true
  715. so.root_directory = "/etc/smartdns/domain-set"
  716. so = ss.option(form.ListValue, "block_domain_type", _("Block domain"), _("Block domain."));
  717. so.rmempty = true;
  718. so.value("none", _("None"));
  719. so.value("all", "IPv4/IPv6");
  720. so.value("ipv4", "IPv4");
  721. so.value("ipv6", "IPv6");
  722. so.modalonly = true;
  723. // Support DualStack ip selection;
  724. so = ss.option(form.ListValue, "dualstack_ip_selection", _("Dual-stack IP Selection"),
  725. _("Enable IP selection between IPV4 and IPV6"));
  726. so.rmempty = true;
  727. so.default = "default";
  728. so.modalonly = true;
  729. so.value("", _("default"));
  730. so.value("yes", _("Yes"));
  731. so.value("no", _("No"));
  732. so = ss.option(form.Value, "speed_check_mode", _("Speed Check Mode"), _("Smartdns speed check mode."));
  733. so.rmempty = true;
  734. so.placeholder = "default";
  735. so.modalonly = true;
  736. so.value("", _("default"));
  737. so.value("ping,tcp:80,tcp:443");
  738. so.value("ping,tcp:443,tcp:80");
  739. so.value("tcp:80,tcp:443,ping");
  740. so.value("tcp:443,tcp:80,ping");
  741. so.value("none", _("None"));
  742. so.validate = function (section_id, value) {
  743. if (value == "") {
  744. return true;
  745. }
  746. if (value == "none") {
  747. return true;
  748. }
  749. var check_mode = value.split(",")
  750. for (var i = 0; i < check_mode.length; i++) {
  751. if (check_mode[i] == "ping") {
  752. continue;
  753. }
  754. if (check_mode[i].indexOf("tcp:") == 0) {
  755. var port = check_mode[i].split(":")[1];
  756. if (port == "") {
  757. return _("TCP port is empty");
  758. }
  759. continue;
  760. }
  761. return _("Speed check mode is invalid.");
  762. }
  763. return true;
  764. }
  765. so = ss.option(form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
  766. so.rmempty = true;
  767. so.default = so.disabled;
  768. so.modalonly = true;
  769. so = ss.option(form.Value, "ipset_name", _("IPset Name"), _("IPset name."));
  770. so.rmempty = true;
  771. so.datatype = "hostname";
  772. so.rempty = true;
  773. so.modalonly = true;
  774. so = ss.option(form.Value, "nftset_name", _("NFTset Name"), _("NFTset name, format: [#[4|6]:[family#table#set]]"));
  775. so.rmempty = true;
  776. so.datatype = "string";
  777. so.rempty = true;
  778. so.modalonly = true;
  779. so.validate = function (section_id, value) {
  780. if (value == "") {
  781. return true;
  782. }
  783. var nftset = value.split(",")
  784. for (var i = 0; i < nftset.length; i++) {
  785. if (!nftset[i].match(/#[4|6]:[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+$/)) {
  786. return _("NFTset name format error, format: [#[4|6]:[family#table#set]]");
  787. }
  788. }
  789. return true;
  790. }
  791. // other args
  792. so = ss.option(form.Value, "addition_flag", _("Additional Rule Flag"),
  793. _("Additional Flags for rules, read help on domain-rule for more information."))
  794. so.default = ""
  795. so.rempty = true
  796. so.modalonly = true;
  797. ///////////////////////////////////////
  798. // IP Blacklist;
  799. ///////////////////////////////////////
  800. // blacklist;
  801. o = s.taboption("blackip-list", form.TextValue, "blackip_ip_conf",
  802. "", _("Configure IP blacklists that will be filtered from the results of specific DNS server."));
  803. o.rows = 20;
  804. o.cfgvalue = function (section_id) {
  805. return fs.trimmed('/etc/smartdns/blacklist-ip.conf');
  806. };
  807. o.write = function (section_id, formvalue) {
  808. return this.cfgvalue(section_id).then(function (value) {
  809. if (value == formvalue) {
  810. return
  811. }
  812. return fs.write('/etc/smartdns/blacklist-ip.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
  813. });
  814. };
  815. ///////////////////////////////////////
  816. // domain address
  817. ///////////////////////////////////////
  818. o = s.taboption("domain-address", form.TextValue, "address_conf",
  819. "",
  820. _("Specify an IP address to return for any host in the given domains, Queries in the domains are never "
  821. + "forwarded and always replied to with the specified IP address which may be IPv4 or IPv6."));
  822. o.rows = 20;
  823. o.cfgvalue = function (section_id) {
  824. return fs.trimmed('/etc/smartdns/address.conf');
  825. };
  826. o.write = function (section_id, formvalue) {
  827. return this.cfgvalue(section_id).then(function (value) {
  828. if (value == formvalue) {
  829. return
  830. }
  831. return fs.write('/etc/smartdns/address.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
  832. });
  833. };
  834. ////////////////
  835. // Support
  836. ////////////////
  837. s = m.section(form.TypedSection, "smartdns", _("Technical Support"),
  838. _("If you like this software, please buy me a cup of coffee."));
  839. s.anonymous = true;
  840. o = s.option(form.Button, "web");
  841. o.title = _("SmartDNS official website");
  842. o.inputtitle = _("open website");
  843. o.inputstyle = "apply";
  844. o.onclick = function () {
  845. window.open("https://pymumu.github.io/smartdns", '_blank');
  846. };
  847. o = s.option(form.Button, "report");
  848. o.title = _("Report bugs");
  849. o.inputtitle = _("Report bugs");
  850. o.inputstyle = "apply";
  851. o.onclick = function () {
  852. window.open("https://github.com/pymumu/smartdns/issues", '_blank');
  853. };
  854. o = s.option(form.Button, "Donate");
  855. o.title = _("Donate to smartdns");
  856. o.inputtitle = _("Donate");
  857. o.inputstyle = "apply";
  858. o.onclick = function () {
  859. window.open("https://pymumu.github.io/smartdns/#donate", '_blank');
  860. };
  861. o = s.option(form.DummyValue, "_restart", _("Restart Service"));
  862. o.renderWidget = function () {
  863. return E('button', {
  864. 'class': 'btn cbi-button cbi-button-apply',
  865. 'id': 'btn_restart',
  866. 'click': ui.createHandlerFn(this, function () {
  867. return fs.exec('/etc/init.d/smartdns', ['restart'])
  868. .catch(function (e) { ui.addNotification(null, E('p', e.message), 'error') });
  869. })
  870. }, [_("Restart")]);
  871. }
  872. return m.render();
  873. }
  874. });