update 2026-07-28 01:38:11

This commit is contained in:
action
2026-07-28 01:38:11 +08:00
parent 20b786ab77
commit 25d570431d
6243 changed files with 2850542 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-mosdns
PKG_VERSION:=1.7.4
PKG_RELEASE:=1
LUCI_TITLE:=LuCI Support for mosdns
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+mosdns +curl +v2ray-geoip +v2ray-geosite +v2dat
PKG_MAINTAINER:=sbwml <admin@cooluc.com>
define Package/$(PKG_NAME)/conffiles
/etc/config/mosdns
/etc/mosdns/cache.dump
/etc/mosdns/config_custom.yaml
/etc/mosdns/rule
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
@@ -0,0 +1 @@
!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(u){"use strict";function f(e,t){clearTimeout(t.timeout),u.off(window,"mouseup",t.hurry),u.off(window,"keyup",t.hurry)}u.defineOption("autoRefresh",!1,function(e,t){function o(){i.display.wrapper.offsetHeight?(f(0,r),i.display.lastWrapHeight!=i.display.wrapper.clientHeight&&i.refresh()):r.timeout=setTimeout(o,r.delay)}var i,r;e.state.autoRefresh&&(f(0,e.state.autoRefresh),e.state.autoRefresh=null),t&&0==e.display.wrapper.offsetHeight&&((r=(i=e).state.autoRefresh={delay:t.delay||250}).timeout=setTimeout(o,r.delay),r.hurry=function(){clearTimeout(r.timeout),r.timeout=setTimeout(o,50)},u.on(window,"mouseup",r.hurry),u.on(window,"keyup",r.hurry))})});
@@ -0,0 +1 @@
.CodeMirror-lint-markers{width:16px}.CodeMirror-lint-tooltip{background-color:#ffd;border:1px solid #000;border-radius:4px 4px 4px 4px;color:#000;font-family:monospace;font-size:10pt;overflow:hidden;padding:2px 5px;position:fixed;white-space:pre;white-space:pre-wrap;z-index:100;max-width:600px;opacity:0;transition:opacity .4s;-moz-transition:opacity .4s;-webkit-transition:opacity .4s;-o-transition:opacity .4s;-ms-transition:opacity .4s}.CodeMirror-lint-mark{background-position:left bottom;background-repeat:repeat-x}.CodeMirror-lint-mark-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=)}.CodeMirror-lint-mark-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==)}.CodeMirror-lint-marker{background-position:center center;background-repeat:no-repeat;cursor:pointer;display:inline-block;height:16px;width:16px;vertical-align:middle;position:relative}.CodeMirror-lint-message{padding-left:18px;background-position:top left;background-repeat:no-repeat}.CodeMirror-lint-marker-warning,.CodeMirror-lint-message-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=)}.CodeMirror-lint-marker-error,.CodeMirror-lint-message-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=)}.CodeMirror-lint-marker-multiple{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:right bottom;width:100%;height:100%}.CodeMirror-lint-line-error{background-color:rgba(183,76,81,.08)}.CodeMirror-lint-line-warning{background-color:rgba(255,211,0,.1)}
@@ -0,0 +1 @@
!function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(p){"use strict";var h="CodeMirror-lint-markers",g="CodeMirror-lint-line-";function u(t){t.parentNode&&t.parentNode.removeChild(t)}function v(t,e,n,o){t=t,e=e,n=n,(i=document.createElement("div")).className="CodeMirror-lint-tooltip cm-s-"+t.options.theme,i.appendChild(n.cloneNode(!0)),(t.state.lint.options.selfContain?t.getWrapperElement():document.body).appendChild(i),p.on(document,"mousemove",a),a(e),null!=i.style.opacity&&(i.style.opacity=1);var i,r=i;function a(t){if(!i.parentNode)return p.off(document,"mousemove",a);var e=Math.max(0,t.clientY-i.offsetHeight-5),t=Math.max(0,Math.min(t.clientX+5,i.ownerDocument.defaultView.innerWidth-i.offsetWidth));i.style.top=e+"px",i.style.left=t+"px"}function l(){var t;p.off(o,"mouseout",l),r&&((t=r).parentNode&&(null==t.style.opacity&&u(t),t.style.opacity=0,setTimeout(function(){u(t)},600)),r=null)}var s=setInterval(function(){if(r)for(var t=o;;t=t.parentNode){if((t=t&&11==t.nodeType?t.host:t)==document.body)return;if(!t){l();break}}if(!r)return clearInterval(s)},400);p.on(o,"mouseout",l)}function a(s,t,e){for(var n in this.marked=[],(t=t instanceof Function?{getAnnotations:t}:t)&&!0!==t||(t={}),this.options={},this.linterOptions=t.options||{},o)this.options[n]=o[n];for(var n in t)o.hasOwnProperty(n)?null!=t[n]&&(this.options[n]=t[n]):t.options||(this.linterOptions[n]=t[n]);this.timeout=null,this.hasGutter=e,this.onMouseOver=function(t){var e=s,n=t.target||t.srcElement;if(/\bCodeMirror-lint-mark-/.test(n.className)){for(var n=n.getBoundingClientRect(),o=(n.left+n.right)/2,n=(n.top+n.bottom)/2,i=e.findMarksAt(e.coordsChar({left:o,top:n},"client")),r=[],a=0;a<i.length;++a){var l=i[a].__annotation;l&&r.push(l)}r.length&&!function(t,e,n){for(var o=n.target||n.srcElement,i=document.createDocumentFragment(),r=0;r<e.length;r++){var a=e[r];i.appendChild(M(a))}v(t,n,i,o)}(e,r,t)}},this.waitingFor=0}var o={highlightLines:!1,tooltips:!0,delay:500,lintOnChange:!0,getAnnotations:null,async:!1,selfContain:null,formatAnnotation:null,onUpdateLinting:null};function C(t){var n,e=t.state.lint;e.hasGutter&&t.clearGutter(h),e.options.highlightLines&&(n=t).eachLine(function(t){var e=t.wrapClass&&/\bCodeMirror-lint-line-\w+\b/.exec(t.wrapClass);e&&n.removeLineClass(t,"wrap",e[0])});for(var o=0;o<e.marked.length;++o)e.marked[o].clear();e.marked.length=0}function M(t){var e=(e=t.severity)||"error",n=document.createElement("div");return n.className="CodeMirror-lint-message CodeMirror-lint-message-"+e,void 0!==t.messageHTML?n.innerHTML=t.messageHTML:n.appendChild(document.createTextNode(t.message)),n}function l(e){var t,n,o,i,r,a,l=e.state.lint;function s(){a=-1,o.off("change",s)}!l||(t=(i=l.options).getAnnotations||e.getHelper(p.Pos(0,0),"lint"))&&(i.async||t.async?(i=t,r=(o=e).state.lint,a=++r.waitingFor,o.on("change",s),i(o.getValue(),function(t,e){o.off("change",s),r.waitingFor==a&&(e&&t instanceof p&&(t=e),o.operation(function(){c(o,t)}))},r.linterOptions,o)):(n=t(e.getValue(),l.linterOptions,e))&&(n.then?n.then(function(t){e.operation(function(){c(e,t)})}):e.operation(function(){c(e,n)})))}function c(t,e){var n=t.state.lint;if(n){for(var o,i,r=n.options,a=(C(t),function(t){for(var e=[],n=0;n<t.length;++n){var o=t[n],i=o.from.line;(e[i]||(e[i]=[])).push(o)}return e}(e)),l=0;l<a.length;++l){var s=a[l];if(s){for(var u=null,c=n.hasGutter&&document.createDocumentFragment(),f=0;f<s.length;++f){var m=s[f],d=m.severity;i=d=d||"error",u="error"==(o=u)?o:i,r.formatAnnotation&&(m=r.formatAnnotation(m)),n.hasGutter&&c.appendChild(M(m)),m.to&&n.marked.push(t.markText(m.from,m.to,{className:"CodeMirror-lint-mark CodeMirror-lint-mark-"+d,__annotation:m}))}n.hasGutter&&t.setGutterMarker(l,h,function(e,n,t,o,i){var r=document.createElement("div"),a=r;return r.className="CodeMirror-lint-marker CodeMirror-lint-marker-"+t,o&&((a=r.appendChild(document.createElement("div"))).className="CodeMirror-lint-marker CodeMirror-lint-marker-multiple"),0!=i&&p.on(a,"mouseover",function(t){v(e,t,n,a)}),r}(t,c,u,1<s.length,r.tooltips)),r.highlightLines&&t.addLineClass(l,"wrap",g+u)}}r.onUpdateLinting&&r.onUpdateLinting(e,a,t)}}function s(t){var e=t.state.lint;e&&(clearTimeout(e.timeout),e.timeout=setTimeout(function(){l(t)},e.options.delay))}p.defineOption("lint",!1,function(t,e,n){if(n&&n!=p.Init&&(C(t),!1!==t.state.lint.options.lintOnChange&&t.off("change",s),p.off(t.getWrapperElement(),"mouseover",t.state.lint.onMouseOver),clearTimeout(t.state.lint.timeout),delete t.state.lint),e){for(var o=t.getOption("gutters"),i=!1,r=0;r<o.length;++r)o[r]==h&&(i=!0);n=t.state.lint=new a(t,e,i);n.options.lintOnChange&&t.on("change",s),0!=n.options.tooltips&&"gutter"!=n.options.tooltips&&p.on(t.getWrapperElement(),"mouseover",n.onMouseOver),l(t)}}),p.defineExtension("performLint",function(){l(this)})});
@@ -0,0 +1 @@
!function(o){"object"==typeof exports&&"object"==typeof module?o(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],o):o(CodeMirror)}(function(n){"use strict";n.registerHelper("lint","yaml",function(e){var r=[];if(!window.jsyaml)return window.console&&window.console.error("Error: window.jsyaml not defined, CodeMirror YAML linting cannot run."),r;try{jsyaml.loadAll(e)}catch(o){e=o.mark,e=e?n.Pos(e.line,e.column):n.Pos(0,0);r.push({from:e,to:e,message:o.message})}return r})});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("yaml",function(){var n=new RegExp("\\b(("+["true","false","on","off","yes","no"].join(")|(")+"))$","i");return{token:function(e,i){var t=e.peek(),r=i.escaped;if(i.escaped=!1,"#"==t&&(0==e.pos||/\s/.test(e.string.charAt(e.pos-1))))return e.skipToEnd(),"comment";if(e.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/))return"string";if(i.literal&&e.indentation()>i.keyCol)return e.skipToEnd(),"string";if(i.literal&&(i.literal=!1),e.sol()){if(i.keyCol=0,i.pair=!1,i.pairStart=!1,e.match("---"))return"def";if(e.match("..."))return"def";if(e.match(/\s*-\s+/))return"meta"}if(e.match(/^(\{|\}|\[|\])/))return"{"==t?i.inlinePairs++:"}"==t?i.inlinePairs--:"["==t?i.inlineList++:i.inlineList--,"meta";if(0<i.inlineList&&!r&&","==t)return e.next(),"meta";if(0<i.inlinePairs&&!r&&","==t)return i.keyCol=0,i.pair=!1,i.pairStart=!1,e.next(),"meta";if(i.pairStart){if(e.match(/^\s*(\||\>)\s*/))return i.literal=!0,"meta";if(e.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i))return"variable-2";if(0==i.inlinePairs&&e.match(/^\s*-?[0-9\.\,]+\s?$/))return"number";if(0<i.inlinePairs&&e.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/))return"number";if(e.match(n))return"keyword"}return!i.pair&&e.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^\s,\[\]{}#&*!|>'"%@`])[^#:]*(?=:($|\s))/)?(i.pair=!0,i.keyCol=e.indentation(),"atom"):i.pair&&e.match(/^:\s*/)?(i.pairStart=!0,"meta"):(i.pairStart=!1,i.escaped="\\"==t,e.next(),null)},startState:function(){return{pair:!1,pairStart:!1,keyCol:0,inlinePairs:0,inlineList:0,literal:!1,escaped:!1}},lineComment:"#",fold:"indent"}}),e.defineMIME("text/x-yaml","yaml"),e.defineMIME("text/yaml","yaml")});
@@ -0,0 +1 @@
.cm-s-dracula .CodeMirror-gutters,.cm-s-dracula.CodeMirror{background-color:#282a36!important;color:#f8f8f2!important;border:none}.cm-s-dracula .CodeMirror-gutters{color:#282a36}.cm-s-dracula .CodeMirror-cursor{border-left:solid thin #f8f8f0}.cm-s-dracula .CodeMirror-linenumber{color:#6d8a88}.cm-s-dracula .CodeMirror-selected{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-line::selection,.cm-s-dracula .CodeMirror-line>span::selection,.cm-s-dracula .CodeMirror-line>span>span::selection{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-line::-moz-selection,.cm-s-dracula .CodeMirror-line>span::-moz-selection,.cm-s-dracula .CodeMirror-line>span>span::-moz-selection{background:rgba(255,255,255,.1)}.cm-s-dracula span.cm-comment{color:#6272a4}.cm-s-dracula span.cm-string,.cm-s-dracula span.cm-string-2{color:#f1fa8c}.cm-s-dracula span.cm-number{color:#bd93f9}.cm-s-dracula span.cm-variable{color:#50fa7b}.cm-s-dracula span.cm-variable-2{color:#fff}.cm-s-dracula span.cm-def{color:#50fa7b}.cm-s-dracula span.cm-operator{color:#ff79c6}.cm-s-dracula span.cm-keyword{color:#ff79c6}.cm-s-dracula span.cm-atom{color:#bd93f9}.cm-s-dracula span.cm-meta{color:#f8f8f2}.cm-s-dracula span.cm-tag{color:#ff79c6}.cm-s-dracula span.cm-attribute{color:#50fa7b}.cm-s-dracula span.cm-qualifier{color:#50fa7b}.cm-s-dracula span.cm-property{color:#66d9ef}.cm-s-dracula span.cm-builtin{color:#50fa7b}.cm-s-dracula span.cm-type,.cm-s-dracula span.cm-variable-3{color:#ffb86c}.cm-s-dracula .CodeMirror-activeline-background{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-matchingbracket{text-decoration:underline;color:#fff!important}
@@ -0,0 +1,459 @@
'use strict';
'require form';
'require fs';
'require poll';
'require rpc';
'require uci';
'require ui';
'require view';
const callServiceList = rpc.declare({
object: 'service',
method: 'list',
params: ['name'],
expect: { '': {} }
});
function getServiceStatus() {
return L.resolveDefault(callServiceList('mosdns'), {}).then(res => {
let isRunning = false;
try {
isRunning = res['mosdns']['instances']['mosdns']['running'];
} catch (e) { }
return isRunning;
});
}
function renderStatus(isRunning) {
const spanTemp = '<em><span style="color:%s"><strong>%s %s</strong></span></em>';
let renderHTML;
if (isRunning) {
renderHTML = spanTemp.format('green', _('MosDNS'), _('RUNNING'));
} else {
renderHTML = spanTemp.format('red', _('MosDNS'), _('NOT RUNNING'));
}
return renderHTML;
}
async function loadCodeMirrorResources() {
const styles = [
'/luci-static/resources/codemirror5/theme/dracula.min.css',
'/luci-static/resources/codemirror5/addon/lint/lint.min.css',
'/luci-static/resources/codemirror5/codemirror.min.css',
];
const scripts = [
'/luci-static/resources/codemirror5/libs/js-yaml.min.js',
'/luci-static/resources/codemirror5/codemirror.min.js',
'/luci-static/resources/codemirror5/addon/display/autorefresh.min.js',
'/luci-static/resources/codemirror5/mode/yaml/yaml.min.js',
'/luci-static/resources/codemirror5/addon/lint/lint.min.js',
'/luci-static/resources/codemirror5/addon/lint/yaml-lint.min.js',
];
const loadStyles = async () => {
for (const href of styles) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}
};
const loadScripts = async () => {
for (const src of scripts) {
const script = document.createElement('script');
script.src = src;
document.head.appendChild(script);
await new Promise(resolve => script.onload = resolve);
}
};
await loadStyles();
await loadScripts();
}
const callMosdns = rpc.declare({
object: 'luci.mosdns',
method: 'get_version',
expect: { '': {} }
});
const callFlushCache = rpc.declare({
object: 'luci.mosdns',
method: 'flush_cache',
expect: { '': {} }
});
return view.extend({
load() {
return Promise.all([
L.resolveDefault(callMosdns(), null),
]);
},
handleFlushCache() {
return callFlushCache().then(res => {
if (res.success) {
ui.addNotification(null, E('p', _('Flushing DNS Cache Success.')), 'info');
} else {
ui.addNotification(null, E('p', _('Flushing DNS Cache Failed, Please check if MosDNS is running.') + (res.error ? ': ' + res.error : '')), 'error');
}
});
},
render(data) {
let m, s, o;
const version = (data[0] && data[0].version) ? data[0].version : '';
m = new form.Map('mosdns', _('MosDNS') + ' ' + version,
_('MosDNS is a plugin-based DNS forwarder/traffic splitter.'));
s = m.section(form.TypedSection);
s.anonymous = true;
s.render = () => {
setTimeout(() => {
poll.add(() => {
return L.resolveDefault(getServiceStatus()).then(res => {
const view = document.getElementById('service_status');
if (view) {
view.innerHTML = renderStatus(res);
} else {
console.error('Element #service_status not found.');
}
});
});
}, 100);
/* dynamically loading Codemirror resources */
loadCodeMirrorResources();
return E('div', { class: 'cbi-section', id: 'status_bar' }, [
E('p', { id: 'service_status' }, _('Collecting data...'))
]);
};
s = m.section(form.NamedSection, 'config', 'mosdns');
s.tab('basic', _('Basic Options'));
s.tab('advanced', _('Advanced Options'));
s.tab('cloudflare', _('Cloudflare Options'));
s.tab('api', _('API Options'));
s.tab('geodata', _('GeoData Export'));
/* basic */
o = s.taboption('basic', form.Flag, 'enabled', _('Enabled'));
o.default = o.disabled;
o.rmempty = false;
o = s.taboption('basic', form.ListValue, 'configfile', _('Config File'));
o.value('/var/etc/mosdns.json', _('Default Config'));
o.value('/etc/mosdns/config_custom.yaml', _('Custom Config'));
o.default = '/var/etc/mosdns.json';
o.rmempty = false;
o = s.taboption('basic', form.Value, 'listen_port', _('Listen Port'));
o.default = '5335';
o.datatype = 'port';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('basic', form.Value, 'listen_address', _('Listen Address'));
o.default = '0.0.0.0';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('basic', form.ListValue, 'log_level', _('Log Level'));
o.value('debug', _('Debug'));
o.value('info', _('Info'));
o.value('warn', _('Warning'));
o.value('error', _('Error'));
o.default = 'info';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('basic', form.Value, 'log_file', _('Log File'));
o.placeholder = '/var/log/mosdns.log';
o.default = '/var/log/mosdns.log';
o.depends('configfile', '/var/etc/mosdns.json');
o.rmempty = false;
o = s.taboption('basic', form.Flag, 'redirect', _('DNS Forward'), _('Forward Dnsmasq Domain Name resolution requests to MosDNS'));
o.default = false;
if (L.hasSystemFeature('firewall4')) {
o = s.taboption('basic', form.Flag, 'local_dns_redirect', _('DNS redirect'), _('Force redirect all local DNS queries to MosDNS, a.k.a. DNS Hijacking'));
o.default = false;
o.depends('redirect', '1');
}
o = s.taboption('basic', form.Flag, 'prefer_ipv4_cn', _('China DNS prefer IPv4'),
_('IPv4 is preferred for China DNS resolution of dual-stack addresses, and is not affected when the destination is IPv6 only'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('basic', form.Flag, 'prefer_ipv4', _('Remote DNS prefer IPv4'),
_('IPv4 is preferred for Remote / Streaming Media DNS resolution of dual-stack addresses, and is not affected when the destination is IPv6 only'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('basic', form.Flag, 'custom_local_dns', _('Custom China DNS'), _('Follow WAN interface DNS if not enabled'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('basic', form.Flag, 'apple_optimization', _('Apple domains optimization'),
_('For Apple domains equipped with Chinese mainland CDN, always responsive to Chinese CDN IP addresses'));
o.depends('custom_local_dns', '1');
o.default = false;
o = s.taboption('basic', form.DynamicList, 'local_dns', _('China DNS server'));
o.value('119.29.29.29', _('Tencent Public DNS (119.29.29.29)'));
o.value('119.28.28.28', _('Tencent Public DNS (119.28.28.28)'));
o.value('223.5.5.5', _('Aliyun Public DNS (223.5.5.5)'));
o.value('223.6.6.6', _('Aliyun Public DNS (223.6.6.6)'));
o.value('180.184.1.1', _('TrafficRoute Public DNS (180.184.1.1)'));
o.value('180.184.2.2', _('TrafficRoute Public DNS (180.184.2.2)'));
o.value('114.114.114.114', _('Xinfeng Public DNS (114.114.114.114)'));
o.value('114.114.115.115', _('Xinfeng Public DNS (114.114.115.115)'));
o.value('180.76.76.76', _('Baidu Public DNS (180.76.76.76)'));
o.value('https://doh.pub/dns-query', _('Tencent Public DNS (DNS over HTTPS)'));
o.value('quic://dns.alidns.com', _('Aliyun Public DNS (DNS over QUIC)'));
o.value('https://dns.alidns.com/dns-query', _('Aliyun Public DNS (DNS over HTTPS)'));
o.value('h3://dns.alidns.com/dns-query', _('Aliyun Public DNS (DNS over HTTP/3)'));
o.value('https://doh.360.cn/dns-query', _('360 Public DNS (DNS over HTTPS)'));
o.default = '119.29.29.29';
o.depends('custom_local_dns', '1');
o = s.taboption('basic', form.DynamicList, 'remote_dns', _('Remote DNS server'));
o.value('tls://1.1.1.1', _('CloudFlare Public DNS (1.1.1.1)'));
o.value('tls://1.0.0.1', _('CloudFlare Public DNS (1.0.0.1)'));
o.value('tls://8.8.8.8', _('Google Public DNS (8.8.8.8)'));
o.value('tls://8.8.4.4', _('Google Public DNS (8.8.4.4)'));
o.value('tls://9.9.9.9', _('Quad9 Public DNS (9.9.9.9)'));
o.value('tls://149.112.112.112', _('Quad9 Public DNS (149.112.112.112)'));
o.value('tls://208.67.222.222', _('Cisco Public DNS (208.67.222.222)'));
o.value('tls://208.67.220.220', _('Cisco Public DNS (208.67.220.220)'));
o.default = 'tls://8.8.8.8';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('basic', form.Flag, 'custom_stream_media_dns', _('Custom Stream Media DNS'),
_('Netflix, Disney+, Hulu and streaming media rules list will use this DNS'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('basic', form.DynamicList, 'stream_media_dns', _('Streaming Media DNS server'));
o.value('tls://1.1.1.1', _('CloudFlare Public DNS (1.1.1.1)'));
o.value('tls://1.0.0.1', _('CloudFlare Public DNS (1.0.0.1)'));
o.value('tls://8.8.8.8', _('Google Public DNS (8.8.8.8)'));
o.value('tls://8.8.4.4', _('Google Public DNS (8.8.4.4)'));
o.value('tls://9.9.9.9', _('Quad9 Public DNS (9.9.9.9)'));
o.value('tls://149.112.112.112', _('Quad9 Public DNS (149.112.112.112)'));
o.value('tls://208.67.222.222', _('Cisco Public DNS (208.67.222.222)'));
o.value('tls://208.67.220.220', _('Cisco Public DNS (208.67.220.220)'));
o.default = 'tls://8.8.8.8';
o.depends('custom_stream_media_dns', '1');
o = s.taboption('basic', form.Value, 'bootstrap_dns', _('Bootstrap DNS servers'),
_('Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams'));
o.value('119.29.29.29', _('Tencent Public DNS (119.29.29.29)'));
o.value('119.28.28.28', _('Tencent Public DNS (119.28.28.28)'));
o.value('223.5.5.5', _('Aliyun Public DNS (223.5.5.5)'));
o.value('223.6.6.6', _('Aliyun Public DNS (223.6.6.6)'));
o.value('114.114.114.114', _('Xinfeng Public DNS (114.114.114.114)'));
o.value('114.114.115.115', _('Xinfeng Public DNS (114.114.115.115)'));
o.value('180.76.76.76', _('Baidu Public DNS (180.76.76.76)'));
o.value('8.8.8.8', _('Google Public DNS (8.8.8.8)'));
o.value('1.1.1.1', _('CloudFlare Public DNS (1.1.1.1)'));
o.default = '119.29.29.29';
o.depends('configfile', '/var/etc/mosdns.json');
/* advanced */
o = s.taboption('advanced', form.Value, 'concurrent', _('Concurrent'),
_('DNS query request concurrency, The number of upstream DNS servers that are allowed to initiate requests at the same time'));
o.datatype = 'and(uinteger,min(1),max(3))';
o.default = '2';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Value, 'idle_timeout', _('Idle Timeout'),
_('DoH/TCP/DoT Connection Multiplexing idle timeout (default 30 seconds)'));
o.datatype = 'and(uinteger,min(1))';
o.default = '30';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'enable_pipeline', _('TCP/DoT Connection Multiplexing'),
_('Enable TCP/DoT RFC 7766 new Query Pipelining connection multiplexing mode'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'insecure_skip_verify', _('Disable TLS Certificate'),
_('Disable TLS Servers certificate validation, Can be useful if system CA certificate expires or the system time is out of order'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'enable_ecs_remote',
_('Enable EDNS client subnet'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Value, 'remote_ecs_ip', _('IP Address'),
_('Please provide the IP address you use when accessing foreign websites. This IP subnet (0/24) will be used as the ECS address for Remote / Streaming Media DNS requests') +
_('This feature is typically used when using a self-built DNS server as an Remote / Streaming Media DNS upstream (requires support from the upstream server)'));
o.datatype = 'ipaddr';
o.depends('enable_ecs_remote', '1');
o = s.taboption('advanced', form.Flag, 'dns_leak', _('Prevent DNS Leaks'),
_('Enable this option fallback policy forces forwarding to remote DNS'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'cache', _('Enable DNS Cache'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Value, 'cache_size', _('DNS Cache Size'));
o.datatype = 'and(uinteger,min(0))';
o.default = 8000;
o.depends('cache', '1');
o = s.taboption('advanced', form.Value, 'lazy_cache_ttl', _('Lazy Cache TTL'),
_('Lazy cache survival time (in second). To disable Lazy Cache, please set to 0.'));
o.datatype = 'and(uinteger,min(0))';
o.default = 86400;
o.depends('cache', '1');
o = s.taboption('advanced', form.Flag, 'dump_file', _('Cache Dump'),
_('Save the cache locally and reload the cache dump on the next startup'));
o.rmempty = false;
o.default = false;
o.depends('cache', '1');
o = s.taboption('advanced', form.Value, 'dump_interval',
_('Auto Save Cache Interval'));
o.datatype = 'and(uinteger,min(0))';
o.default = 3600;
o.depends('dump_file', '1');
o = s.taboption('advanced', form.Value, 'minimal_ttl', _('Minimum TTL'),
_('Modify the Minimum TTL value (seconds) for DNS answer results, 0 indicating no modification'));
o.datatype = 'and(uinteger,min(0),max(604800))';
o.default = 0;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Value, 'maximum_ttl', _('Maximum TTL'),
_('Modify the Maximum TTL value (seconds) for DNS answer results, 0 indicating no modification'));
o.datatype = 'and(uinteger,min(0),max(604800))';
o.default = 0;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'reject_type65', _('Disable RR Type 65 (HTTPS/SVCB)'),
_('Block DNS RR Type 65 records (HTTPS/SVCB, used for HTTP/3, ECH, etc.), force using only A/AAAA records.'));
o.default = 0;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('advanced', form.Flag, 'adblock', _('Enable DNS ADblock'));
o.depends('configfile', '/var/etc/mosdns.json');
o.default = false;
o = s.taboption('advanced', form.DynamicList, 'ad_source', _('ADblock Source'),
_('When using custom rule sources, please use rule types supported by MosDNS (domain list or AdGuardHome rules).') +
'<br>' +
_('Support for local files, such as: file:///var/mosdns/example.txt'));
o.depends('adblock', '1');
o.default = 'geosite.dat';
o.value('geosite.dat', 'v2ray-geosite');
o.value('https://raw.githubusercontent.com/privacy-protection-tools/anti-AD/master/anti-ad-domains.txt', 'anti-AD');
o.value('https://raw.githubusercontent.com/Cats-Team/AdRules/main/mosdns_adrules.txt', 'Cats-Team/AdRules');
o.value('https://raw.githubusercontent.com/neodevpro/neodevhost/master/domain', 'NEO DEV HOST');
/* cloudflare */
o = s.taboption('cloudflare', form.Flag, 'cloudflare', _('Enabled'),
_('Match the parsing result with the Cloudflare IP ranges, and when there is a successful match, \
use the \'Custom IP\' as the parsing result (experimental feature)'));
o.rmempty = false;
o.default = false;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('cloudflare', form.DynamicList, 'cloudflare_ip', _('Custom IP'));
o.datatype = 'ipaddr';
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('cloudflare', form.TextValue, '_cloudflare',
_('Cloudflare IP Ranges'),
_('IPv4 CIDR: <a href="https://www.cloudflare.com/ips-v4" target="_blank">https://www.cloudflare.com/ips-v4</a> <br /> IPv6 CIDR: <a href="https://www.cloudflare.com/ips-v6" target="_blank">https://www.cloudflare.com/ips-v6</a>'));
o.rows = 15;
o.depends('configfile', '/var/etc/mosdns.json');
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/cloudflare-cidr.txt');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/cloudflare-cidr.txt', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
});
};
/* api */
o = s.taboption('api', form.Value, 'listen_port_api', _('API Listen port'));
o.datatype = 'and(port,min(1))';
o.default = 52001;
o.depends('configfile', '/var/etc/mosdns.json');
o = s.taboption('api', form.Button, '_flush_cache', null,
_('Flushing DNS Cache will clear any IP addresses or DNS records from MosDNS cache.'));
o.title = '&#160;';
o.inputtitle = _('Flush DNS Cache');
o.inputstyle = 'apply';
o.onclick = L.bind(this.handleFlushCache, this);
o.depends('cache', '1');
/* configuration */
let configeditor = null;
setTimeout(() => {
const textarea = document.getElementById('widget.cbid.mosdns.config._custom');
if (textarea) {
configeditor = CodeMirror.fromTextArea(textarea, {
autoRefresh: true,
lineNumbers: true,
lineWrapping: true,
lint: true,
gutters: ['CodeMirror-lint-markers'],
matchBrackets: true,
mode: 'text/yaml',
styleActiveLine: true,
theme: 'dracula'
});
}
}, 600);
o = s.taboption('basic', form.TextValue, '_custom', _('Configuration Editor'),
_('This is the content of the file \'/etc/mosdns/config_custom.yaml\' from which your MosDNS configuration will be generated. \
Only accepts configuration content in yaml format.'));
o.rows = 25;
o.depends('configfile', '/etc/mosdns/config_custom.yaml');
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/config_custom.yaml');
o.write = function(section_id, formvalue) {
if (configeditor) {
const editorContent = configeditor.getValue();
if (editorContent === formvalue) {
return;
}
return fs.write('/etc/mosdns/config_custom.yaml', editorContent.trim().replace(/\r\n/g, '\n') + '\n')
.then(i => fs.exec('/etc/init.d/mosdns', ['restart']))
.then(() => window.location.reload())
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
}
};
o = s.taboption('geodata', form.DynamicList, 'geosite_tags', _('GeoSite Tags'),
_('Enter the GeoSite.dat category to be exported, Allow add multiple tags'),
_('Export directory: /var/mosdns'));
o.depends('configfile', '/etc/mosdns/config_custom.yaml');
o = s.taboption('geodata', form.DynamicList, 'geoip_tags', _('GeoIP Tags'),
_('Enter the GeoIP.dat category to be exported, Allow add multiple tags'),
_('Export directory: /var/mosdns'));
o.depends('configfile', '/etc/mosdns/config_custom.yaml');
return m.render();
}
});
@@ -0,0 +1,85 @@
'use strict';
'require dom';
'require fs';
'require poll';
'require view';
'require rpc';
'require ui';
const callPrintLog = rpc.declare({
object: 'luci.mosdns',
method: 'print_log',
expect: { '': {} }
});
const callCleanLog = rpc.declare({
object: 'luci.mosdns',
method: 'clean_log',
expect: { '': {} }
});
let scrollPosition = 0;
let userScrolled = false;
let logTextarea;
function pollLog() {
return callPrintLog().then(res => {
logTextarea.value = res.log || _('No log data.');
if (!userScrolled) {
logTextarea.scrollTop = logTextarea.scrollHeight;
} else {
logTextarea.scrollTop = scrollPosition;
}
});
}
return view.extend({
handleCleanLogs() {
return callCleanLog().then(res => {
if (res.success) {
logTextarea.value = ''; // Clear textarea on success
} else {
ui.addNotification(null, E('p', _('Failed to clean logs.') + (res.error ? ': ' + res.error : '')), 'error');
}
}).catch(e => ui.addNotification(null, E('p', e.message)));
},
render() {
logTextarea = E('textarea', {
'class': 'cbi-input-textarea',
'wrap': 'off',
'readonly': 'readonly',
'style': 'width: calc(100% - 20px);height: 535px;margin: 10px;overflow-y: scroll;',
});
logTextarea.addEventListener('scroll', () => {
userScrolled = true;
scrollPosition = logTextarea.scrollTop;
});
const log_textarea_wrapper = E('div', { 'id': 'log_textarea' }, logTextarea);
poll.add(pollLog);
const clear_logs_button = E('input', { 'class': 'btn cbi-button-action', 'type': 'button', 'style': 'margin-left: 10px; margin-top: 10px;', 'value': _('Clear logs') });
clear_logs_button.addEventListener('click', this.handleCleanLogs.bind(this));
return E([
E('div', { 'class': 'cbi-map' }, [
E('h2', { 'name': 'content' }, '%s - %s'.format(_('MosDNS'), _('Log Data'))),
E('div', { 'class': 'cbi-section' }, [
clear_logs_button,
log_textarea_wrapper,
E('div', { 'style': 'text-align:right' },
E('small', {}, _('Refresh every %s seconds.').format(L.env.pollinterval))
)
])
])
]);
},
handleSave: null,
handleSaveApply: null,
handleReset: null
});
@@ -0,0 +1,229 @@
'use strict';
'require form';
'require fs';
'require ui';
'require view';
return view.extend({
render() {
let m, s, o;
m = new form.Map('mosdns', _('Rule Settings'),
_('The list of rules only apply to \'Default Config\' profiles.'));
s = m.section(form.TypedSection);
s.anonymous = true;
s.sortable = true;
s.tab('whitelist', _('White Lists'));
s.tab('blocklist', _('Block Lists'));
s.tab('greylist', _('Grey Lists'));
s.tab('ddnslist', _('DDNS Lists'));
s.tab('hostslist', _('Hosts'));
s.tab('redirectlist', _('Redirect'));
s.tab('localptrlist', _('Block PTR'));
s.tab('streamingmedialist', _('Streaming Media'));
// --- White Lists ---
o = s.taboption('whitelist', form.TextValue, '_whitelist',
null,
'<font color=\'red\'>'
+ _('Added domain names always permit resolution using \'local DNS\' with the highest priority (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/whitelist.txt').catch(e => '');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/whitelist.txt', (formvalue.trim() ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : ''))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o.remove = section_id => fs.write('/etc/mosdns/rule/whitelist.txt', '').catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
// --- Block Lists ---
o = s.taboption('blocklist', form.TextValue, '_blocklist',
null,
'<font color=\'red\'>'
+ _('Added domain names will block DNS resolution (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/blocklist.txt').catch(e => '');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/blocklist.txt', (formvalue.trim() ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : ''))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o.remove = section_id => fs.write('/etc/mosdns/rule/blocklist.txt', '').catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
// --- Grey Lists ---
o = s.taboption('greylist', form.TextValue, '_greylist',
null,
'<font color=\'red\'>'
+ _('Added domain names will always use \'Remote DNS\' for resolution (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/greylist.txt').catch(e => '');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/greylist.txt', (formvalue.trim() ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : ''))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o.remove = section_id => fs.write('/etc/mosdns/rule/greylist.txt', '').catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
// --- DDNS Lists ---
o = s.taboption('ddnslist', form.TextValue, '_ddnslist',
null,
'<font color=\'red\'>'
+ _('Added domain names will always use \'Local DNS\' for resolution, with a forced TTL of 5 seconds, and results will not be cached (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/ddnslist.txt').catch(e => '');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/ddnslist.txt', (formvalue.trim() ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : ''))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o.remove = section_id => fs.write('/etc/mosdns/rule/ddnslist.txt', '').catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
// --- Hosts ---
o = s.taboption('hostslist', form.TextValue, '_hostslist',
null,
'<font color=\'red\'>'
+ _('Custom Hosts rewrite, for example: baidu.com 10.0.0.1 (one rule per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/hosts.txt').catch(e => '');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/hosts.txt', (formvalue.trim() ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : ''))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o.remove = section_id => fs.write('/etc/mosdns/rule/hosts.txt', '').catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
// --- Redirect ---
o = s.taboption('redirectlist', form.TextValue, '_redirectlist',
null,
'<font color=\'red\'>'
+ _('Redirecting requests for domain names. Request domain A, but return records for domain B, for example: baidu.com qq.com (one rule per line).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/redirect.txt').catch(e => '');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/redirect.txt', (formvalue.trim() ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : ''))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o.remove = section_id => fs.write('/etc/mosdns/rule/redirect.txt', '').catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
// --- Block PTR ---
o = s.taboption('localptrlist', form.TextValue, '_localptrlist',
null,
'<font color=\'red\'>'
+ _('Added domain names will block PTR requests (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/local-ptr.txt').catch(e => '');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/local-ptr.txt', (formvalue.trim() ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : ''))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o.remove = section_id => fs.write('/etc/mosdns/rule/local-ptr.txt', '').catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
// --- Streaming Media ---
o = s.taboption('streamingmedialist', form.TextValue, '_streamingmedialist',
null,
'<font color=\'red\'>'
+ _('When enabling \'Custom Stream Media DNS\', added domains will always use the \'Streaming Media DNS server\' for resolution (one domain per line, supports domain matching rules).')
+ '</font>'
);
o.rows = 25;
o.cfgvalue = section_id => fs.trimmed('/etc/mosdns/rule/streaming.txt').catch(e => '');
o.write = function(section_id, formvalue) {
return this.cfgvalue(section_id).then(value => {
if (value === formvalue) {
return;
}
return fs.write('/etc/mosdns/rule/streaming.txt', (formvalue.trim() ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : ''))
.catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
});
};
o.remove = section_id => fs.write('/etc/mosdns/rule/streaming.txt', '').catch(e => {
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
});
return m.render();
},
handleSaveApply(ev) {
return this.handleSave(ev).then(() => {
window.location.reload();
});
},
handleReset: null
});
@@ -0,0 +1,156 @@
'use strict';
'require form';
'require fs';
'require ui';
'require view';
'require rpc';
const callStartUpdate = rpc.declare({
object: 'luci.mosdns',
method: 'start_update',
expect: { '': {} }
});
const callGetUpdateLog = rpc.declare({
object: 'luci.mosdns',
method: 'get_update_log',
expect: { '': {} }
});
return view.extend({
handleUpdate() {
const statusMsg = E('p', { 'class': 'spinning' }, _('Please wait, this may take a few moments...'));
const logTextarea = E('textarea', {
'class': 'cbi-input-textarea',
'readonly': 'readonly',
'style': 'width: 100%; height: 300px; font-family: monospace; font-size: 12px; margin-top: 10px;',
'placeholder': _('Starting update...')
});
const closeButton = E('button', {
'class': 'btn',
'style': 'display: none;',
'click': ui.hideModal
}, _('Close'));
ui.showModal(_('Updating Database...'), [
statusMsg,
logTextarea,
E('div', { 'class': 'right' }, [ closeButton ])
]);
const pollLog = () => {
return callGetUpdateLog().then(res => {
if (res && res.log) {
logTextarea.value = res.log;
logTextarea.scrollTop = logTextarea.scrollHeight;
if (res.log.match(/UPDATE_FINISHED/)) {
statusMsg.textContent = _('Update success');
statusMsg.classList.remove('spinning');
statusMsg.style.color = '#19be6b';
statusMsg.style.fontWeight = 'bold';
closeButton.style.display = 'inline';
return false;
}
if (res.log.match(/UPDATE_EXITED/)) {
statusMsg.textContent = _('Update failed');
statusMsg.classList.remove('spinning');
statusMsg.style.color = '#ed4014';
statusMsg.style.fontWeight = 'bold';
closeButton.style.display = 'inline';
return false;
}
if (res.log.match(/Another update is already in progress/)) {
statusMsg.textContent = _('Another update is already in progress.');
statusMsg.classList.remove('spinning');
statusMsg.style.color = '#ff9900';
closeButton.style.display = 'inline';
return false;
}
}
return true;
});
};
return callStartUpdate().then(res => {
if (res.success) {
const interval = window.setInterval(() => {
pollLog().then(continuePolling => {
if (!continuePolling) {
window.clearInterval(interval);
}
});
}, 1000);
} else {
statusMsg.textContent = res.error || _('Failed to start update.');
statusMsg.classList.remove('spinning');
statusMsg.style.color = '#ed4014';
closeButton.style.display = 'inline';
}
}).catch(e => {
statusMsg.textContent = _('Update failed: %s').format(e.message);
statusMsg.classList.remove('spinning');
statusMsg.style.color = '#ed4014';
closeButton.style.display = 'inline';
});
},
render() {
let m, s, o;
m = new form.Map('mosdns', _('Update GeoIP & GeoSite databases'),
_('Automatically update GeoIP and GeoSite databases as well as ad filtering rules through scheduled tasks.'));
s = m.section(form.TypedSection);
s.anonymous = true;
o = s.option(form.Flag, 'geo_auto_update', _('Enable Auto Database Update'));
o.rmempty = false;
o = s.option(form.ListValue, 'geo_update_week_time', _('Update Cycle'));
o.value('*', _('Every Day'));
o.value('1', _('Every Monday'));
o.value('2', _('Every Tuesday'));
o.value('3', _('Every Wednesday'));
o.value('4', _('Every Thursday'));
o.value('5', _('Every Friday'));
o.value('6', _('Every Saturday'));
o.value('0', _('Every Sunday'));
o.default = 3;
o = s.option(form.ListValue, 'geo_update_day_time', _('Update Time'));
for (let t = 0; t < 24; t++) {
o.value(t, t + ':00');
}
o.default = 3;
o = s.option(form.ListValue, 'geoip_type', _('GeoIP Type'),
_('Little: only include Mainland China and Private IP addresses.') +
'<br>' +
_('Full: includes all Countries and Private IP addresses.')
);
o.value('geoip', _('Full'));
o.value('geoip-only-cn-private', _('Little'));
o.rmempty = false;
o.default = 'geoip-only-cn-private';
o = s.option(form.Value, 'github_proxy', _('GitHub Proxy'),
_('Update data files with GitHub Proxy, leave blank to disable proxy downloads.'));
o.value('https://gh-proxy.com', _('https://gh-proxy.com'));
o.rmempty = true;
o.default = '';
o = s.option(form.Button, '_udpate', null,
_('Check And Update GeoData.'));
o.title = _('Database Update');
o.inputtitle = _('Check And Update');
o.inputstyle = 'apply';
o.onclick = () => this.handleUpdate();
return m.render();
}
});
+790
View File
@@ -0,0 +1,790 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:217
msgid "360 Public DNS (DNS over HTTPS)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:356
msgid "ADblock Source"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:395
msgid "API Listen port"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:138
msgid "API Options"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:31
msgid ""
"Added domain names always permit resolution using 'local DNS' with the "
"highest priority (one domain per line, supports domain matching rules)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:103
msgid ""
"Added domain names will always use 'Local DNS' for resolution, with a forced "
"TTL of 5 seconds, and results will not be cached (one domain per line, "
"supports domain matching rules)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:79
msgid ""
"Added domain names will always use 'Remote DNS' for resolution (one domain "
"per line, supports domain matching rules)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:55
msgid ""
"Added domain names will block DNS resolution (one domain per line, supports "
"domain matching rules)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:175
msgid ""
"Added domain names will block PTR requests (one domain per line, supports "
"domain matching rules)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:136
msgid "Advanced Options"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:206
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:254
msgid "Aliyun Public DNS (223.5.5.5)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:207
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:255
msgid "Aliyun Public DNS (223.6.6.6)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:216
msgid "Aliyun Public DNS (DNS over HTTP/3)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:215
msgid "Aliyun Public DNS (DNS over HTTPS)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:214
msgid "Aliyun Public DNS (DNS over QUIC)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:68
msgid "Another update is already in progress."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:198
msgid "Apple domains optimization"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:330
msgid "Auto Save Cache Interval"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:106
msgid ""
"Automatically update GeoIP and GeoSite databases as well as ad filtering "
"rules through scheduled tasks."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:212
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:258
msgid "Baidu Public DNS (180.76.76.76)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:135
msgid "Basic Options"
msgstr ""
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:14
msgid "Basic Setting"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:348
msgid ""
"Block DNS RR Type 65 records (HTTPS/SVCB, used for HTTP/3, ECH, etc.), force "
"using only A/AAAA records."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:19
msgid "Block Lists"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:24
msgid "Block PTR"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:250
msgid "Bootstrap DNS servers"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:251
msgid ""
"Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT "
"resolvers you specify as upstreams"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:323
msgid "Cache Dump"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:150
msgid "Check And Update"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:148
msgid "Check And Update GeoData."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:184
msgid "China DNS prefer IPv4"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:203
msgid "China DNS server"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:229
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:246
msgid "Cisco Public DNS (208.67.220.220)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:228
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:245
msgid "Cisco Public DNS (208.67.222.222)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:65
msgid "Clear logs"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:35
msgid "Close"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:223
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:240
msgid "CloudFlare Public DNS (1.0.0.1)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:222
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:239
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:260
msgid "CloudFlare Public DNS (1.1.1.1)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:380
msgid "Cloudflare IP Ranges"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:137
msgid "Cloudflare Options"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:129
msgid "Collecting data..."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:265
msgid "Concurrent"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:146
msgid "Config File"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:426
msgid "Configuration Editor"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:194
msgid "Custom China DNS"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:148
msgid "Custom Config"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:127
msgid ""
"Custom Hosts rewrite, for example: baidu.com 10.0.0.1 (one rule per line, "
"supports domain matching rules)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:375
msgid "Custom IP"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:233
msgid "Custom Stream Media DNS"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:21
msgid "DDNS Lists"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:312
msgid "DNS Cache Size"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:175
msgid "DNS Forward"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:266
msgid ""
"DNS query request concurrency, The number of upstream DNS servers that are "
"allowed to initiate requests at the same time"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:179
msgid "DNS redirect"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:149
msgid "Database Update"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:162
msgid "Debug"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:147
msgid "Default Config"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:347
msgid "Disable RR Type 65 (HTTPS/SVCB)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:283
msgid "Disable TLS Certificate"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:284
msgid ""
"Disable TLS Servers certificate validation, Can be useful if system CA "
"certificate expires or the system time is out of order"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:272
msgid "DoH/TCP/DoT Connection Multiplexing idle timeout (default 30 seconds)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:111
msgid "Enable Auto Database Update"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:352
msgid "Enable DNS ADblock"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:307
msgid "Enable DNS Cache"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:290
msgid "Enable EDNS client subnet"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:278
msgid ""
"Enable TCP/DoT RFC 7766 new Query Pipelining connection multiplexing mode"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:302
msgid "Enable this option fallback policy forces forwarding to remote DNS"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:142
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:368
msgid "Enabled"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:453
msgid "Enter the GeoIP.dat category to be exported, Allow add multiple tags"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:448
msgid "Enter the GeoSite.dat category to be exported, Allow add multiple tags"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:165
msgid "Error"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:115
msgid "Every Day"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:120
msgid "Every Friday"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:116
msgid "Every Monday"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:121
msgid "Every Saturday"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:122
msgid "Every Sunday"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:119
msgid "Every Thursday"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:117
msgid "Every Tuesday"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:118
msgid "Every Wednesday"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:449
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:454
msgid "Export directory: /var/mosdns"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:43
msgid "Failed to clean logs."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:89
msgid "Failed to start update."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:403
msgid "Flush DNS Cache"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:97
msgid "Flushing DNS Cache Failed, Please check if MosDNS is running."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:95
msgid "Flushing DNS Cache Success."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:401
msgid ""
"Flushing DNS Cache will clear any IP addresses or DNS records from MosDNS "
"cache."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:194
msgid "Follow WAN interface DNS if not enabled"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:199
msgid ""
"For Apple domains equipped with Chinese mainland CDN, always responsive to "
"Chinese CDN IP addresses"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:179
msgid "Force redirect all local DNS queries to MosDNS, a.k.a. DNS Hijacking"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:175
msgid "Forward Dnsmasq Domain Name resolution requests to MosDNS"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:136
msgid "Full"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:134
msgid "Full: includes all Countries and Private IP addresses."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:139
msgid "GeoData Export"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:452
msgid "GeoIP Tags"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:131
msgid "GeoIP Type"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:447
msgid "GeoSite Tags"
msgstr ""
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:30
msgid "Geodata Update"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:141
msgid "GitHub Proxy"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:225
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:242
msgid "Google Public DNS (8.8.4.4)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:224
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:241
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:259
msgid "Google Public DNS (8.8.8.8)"
msgstr ""
#: luci-app-mosdns/root/usr/share/rpcd/acl.d/luci-app-mosdns.json:3
msgid "Grant UCI access for luci-app-mosdns"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:20
msgid "Grey Lists"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:22
msgid "Hosts"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:295
msgid "IP Address"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:381
msgid ""
"IPv4 CIDR: <a href=\"https://www.cloudflare.com/ips-v4\" target=\"_blank"
"\">https://www.cloudflare.com/ips-v4</a> <br /> IPv6 CIDR: <a href=\"https://"
"www.cloudflare.com/ips-v6\" target=\"_blank\">https://www.cloudflare.com/ips-"
"v6</a>"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:185
msgid ""
"IPv4 is preferred for China DNS resolution of dual-stack addresses, and is "
"not affected when the destination is IPv6 only"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:190
msgid ""
"IPv4 is preferred for Remote / Streaming Media DNS resolution of dual-stack "
"addresses, and is not affected when the destination is IPv6 only"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:271
msgid "Idle Timeout"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:163
msgid "Info"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:317
msgid "Lazy Cache TTL"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:318
msgid ""
"Lazy cache survival time (in second). To disable Lazy Cache, please set to 0."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:157
msgid "Listen Address"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:152
msgid "Listen Port"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:137
msgid "Little"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:132
msgid "Little: only include Mainland China and Private IP addresses."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:70
msgid "Log Data"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:169
msgid "Log File"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:161
msgid "Log Level"
msgstr ""
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:38
msgid "Logs"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:369
msgid ""
"Match the parsing result with the Cloudflare IP ranges, and when there is a "
"successful match, use the 'Custom IP' as the parsing result (experimental "
"feature)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:341
msgid "Maximum TTL"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:335
msgid "Minimum TTL"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:342
msgid ""
"Modify the Maximum TTL value (seconds) for DNS answer results, 0 indicating "
"no modification"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:336
msgid ""
"Modify the Minimum TTL value (seconds) for DNS answer results, 0 indicating "
"no modification"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:31
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:33
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:106
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:70
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:3
msgid "MosDNS"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:107
msgid "MosDNS is a plugin-based DNS forwarder/traffic splitter."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:33
msgid "NOT RUNNING"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:234
msgid "Netflix, Disney+, Hulu and streaming media rules list will use this DNS"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:27
msgid "No log data."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:296
msgid ""
"Please provide the IP address you use when accessing foreign websites. This "
"IP subnet (0/24) will be used as the ECS address for Remote / Streaming "
"Media DNS requests"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:22
msgid "Please wait, this may take a few moments..."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:301
msgid "Prevent DNS Leaks"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:227
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:244
msgid "Quad9 Public DNS (149.112.112.112)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:226
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:243
msgid "Quad9 Public DNS (9.9.9.9)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:31
msgid "RUNNING"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:23
msgid "Redirect"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:151
msgid ""
"Redirecting requests for domain names. Request domain A, but return records "
"for domain B, for example: baidu.com qq.com (one rule per line)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:75
msgid "Refresh every %s seconds."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:189
msgid "Remote DNS prefer IPv4"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:221
msgid "Remote DNS server"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:11
msgid "Rule Settings"
msgstr ""
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:22
msgid "Rules"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:324
msgid "Save the cache locally and reload the cache dump on the next startup"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:28
msgid "Starting update..."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:25
msgid "Streaming Media"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:238
msgid "Streaming Media DNS server"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:359
msgid "Support for local files, such as: file:///var/mosdns/example.txt"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:277
msgid "TCP/DoT Connection Multiplexing"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:205
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:253
msgid "Tencent Public DNS (119.28.28.28)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:204
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:252
msgid "Tencent Public DNS (119.29.29.29)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:213
msgid "Tencent Public DNS (DNS over HTTPS)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:12
msgid "The list of rules only apply to 'Default Config' profiles."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:297
msgid ""
"This feature is typically used when using a self-built DNS server as an "
"Remote / Streaming Media DNS upstream (requires support from the upstream "
"server)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:427
msgid ""
"This is the content of the file '/etc/mosdns/config_custom.yaml' from which "
"your MosDNS configuration will be generated. Only accepts configuration "
"content in yaml format."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:208
msgid "TrafficRoute Public DNS (180.184.1.1)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:209
msgid "TrafficRoute Public DNS (180.184.2.2)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:442
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:43
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:48
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:67
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:72
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:91
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:96
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:115
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:120
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:139
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:144
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:163
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:168
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:187
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:192
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:211
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:216
msgid "Unable to save contents: %s"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:114
msgid "Update Cycle"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:105
msgid "Update GeoIP & GeoSite databases"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:125
msgid "Update Time"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:142
msgid ""
"Update data files with GitHub Proxy, leave blank to disable proxy downloads."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:59
msgid "Update failed"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:95
msgid "Update failed: %s"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:50
msgid "Update success"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:37
msgid "Updating Database..."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:164
msgid "Warning"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:199
msgid ""
"When enabling 'Custom Stream Media DNS', added domains will always use the "
"'Streaming Media DNS server' for resolution (one domain per line, supports "
"domain matching rules)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:357
msgid ""
"When using custom rule sources, please use rule types supported by MosDNS "
"(domain list or AdGuardHome rules)."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:18
msgid "White Lists"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:210
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:256
msgid "Xinfeng Public DNS (114.114.114.114)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:211
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:257
msgid "Xinfeng Public DNS (114.114.115.115)"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:143
msgid "https://gh-proxy.com"
msgstr ""
+824
View File
@@ -0,0 +1,824 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-20 09:23+0800\n"
"PO-Revision-Date: 2026-05-15 14:09+0800\n"
"Last-Translator: sbwml <admin@cooluc.com>\n"
"Language-Team: Chinese\n"
"Language: zh_Hans\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:217
msgid "360 Public DNS (DNS over HTTPS)"
msgstr "360 安全 DNSDNS over HTTPS"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:356
msgid "ADblock Source"
msgstr "广告过滤规则来源"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:395
msgid "API Listen port"
msgstr "API 监听端口"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:138
msgid "API Options"
msgstr "API 选项"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:31
msgid ""
"Added domain names always permit resolution using 'local DNS' with the "
"highest priority (one domain per line, supports domain matching rules)."
msgstr ""
"加入的域名始终允许使用 “本地 DNS” 进行解析,且优先级最高(每个域名一行,支持"
"域名匹配规则)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:103
msgid ""
"Added domain names will always use 'Local DNS' for resolution, with a forced "
"TTL of 5 seconds, and results will not be cached (one domain per line, "
"supports domain matching rules)."
msgstr ""
"加入的域名始终使用 “本地 DNS” 进行解析,并且强制 TTL 5 秒,解析结果不会进入缓"
"存(每个域名一行,支持域名匹配规则)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:79
msgid ""
"Added domain names will always use 'Remote DNS' for resolution (one domain "
"per line, supports domain matching rules)."
msgstr ""
"加入的域名始终使用 “远程 DNS” 进行解析(每个域名一行,支持域名匹配规则)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:55
msgid ""
"Added domain names will block DNS resolution (one domain per line, supports "
"domain matching rules)."
msgstr "加入的域名将屏蔽 DNS 解析(每个域名一行,支持域名匹配规则)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:175
msgid ""
"Added domain names will block PTR requests (one domain per line, supports "
"domain matching rules)."
msgstr "加入的域名将阻止 PTR 请求(每个域名一行,支持域名匹配规则)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:136
msgid "Advanced Options"
msgstr "高级选项"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:206
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:254
msgid "Aliyun Public DNS (223.5.5.5)"
msgstr "阿里云公共 DNS223.5.5.5"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:207
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:255
msgid "Aliyun Public DNS (223.6.6.6)"
msgstr "阿里云公共 DNS223.6.6.6"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:216
msgid "Aliyun Public DNS (DNS over HTTP/3)"
msgstr "阿里云公共 DNSDNS over HTTP/3"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:215
msgid "Aliyun Public DNS (DNS over HTTPS)"
msgstr "阿里云公共 DNSDNS over HTTPS"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:214
msgid "Aliyun Public DNS (DNS over QUIC)"
msgstr "阿里云公共 DNSDNS over QUIC"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:68
msgid "Another update is already in progress."
msgstr "另一个更新正在进行中。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:198
msgid "Apple domains optimization"
msgstr "Apple 域名解析优化"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:330
msgid "Auto Save Cache Interval"
msgstr "自动保存缓存间隔(秒)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:106
msgid ""
"Automatically update GeoIP and GeoSite databases as well as ad filtering "
"rules through scheduled tasks."
msgstr "通过定时任务自动更新 GeoIP 和 GeoSite 数据库以及广告过滤规则。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:212
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:258
msgid "Baidu Public DNS (180.76.76.76)"
msgstr "百度公共 DNS180.76.76.76"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:135
msgid "Basic Options"
msgstr "基本选项"
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:14
msgid "Basic Setting"
msgstr "基本设置"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:348
msgid ""
"Block DNS RR Type 65 records (HTTPS/SVCB, used for HTTP/3, ECH, etc.), force "
"using only A/AAAA records."
msgstr ""
"屏蔽 DNS 类型 65 记录(HTTPS/SVCB,用于 HTTP/3、ECH 等),强制仅使用 A/AAAA "
"解析。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:19
msgid "Block Lists"
msgstr "黑名单"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:24
msgid "Block PTR"
msgstr "PTR 黑名单"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:250
msgid "Bootstrap DNS servers"
msgstr "Bootstrap DNS 服务器"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:251
msgid ""
"Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT "
"resolvers you specify as upstreams"
msgstr "Bootstrap DNS 服务器用于解析您指定为上游的 DoH / DoT 解析器的 IP 地址"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:323
msgid "Cache Dump"
msgstr "自动保存缓存"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:150
msgid "Check And Update"
msgstr "检查并更新"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:148
msgid "Check And Update GeoData."
msgstr "检查并更新 GeoData 数据库。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:184
msgid "China DNS prefer IPv4"
msgstr "国内 DNS 首选 IPv4"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:203
msgid "China DNS server"
msgstr "国内 DNS 服务器"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:229
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:246
msgid "Cisco Public DNS (208.67.220.220)"
msgstr "思科公共 DNS208.67.220.220"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:228
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:245
msgid "Cisco Public DNS (208.67.222.222)"
msgstr "思科公共 DNS208.67.222.222"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:65
msgid "Clear logs"
msgstr "清空日志"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:35
msgid "Close"
msgstr "关闭"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:223
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:240
msgid "CloudFlare Public DNS (1.0.0.1)"
msgstr "CloudFlare 公共 DNS1.0.0.1"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:222
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:239
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:260
msgid "CloudFlare Public DNS (1.1.1.1)"
msgstr "CloudFlare 公共 DNS1.1.1.1"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:380
msgid "Cloudflare IP Ranges"
msgstr "Cloudflare IP 范围"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:137
msgid "Cloudflare Options"
msgstr "Cloudflare 选项"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:129
msgid "Collecting data..."
msgstr "获取数据中..."
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:265
msgid "Concurrent"
msgstr "DNS 服务器并发数(默认 2"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:146
msgid "Config File"
msgstr "配置文件"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:426
msgid "Configuration Editor"
msgstr "配置编辑器"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:194
msgid "Custom China DNS"
msgstr "自定义国内 DNS"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:148
msgid "Custom Config"
msgstr "自定义"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:127
msgid ""
"Custom Hosts rewrite, for example: baidu.com 10.0.0.1 (one rule per line, "
"supports domain matching rules)."
msgstr ""
"自定义 Hosts 重写,如:baidu.com 10.0.0.1(每个规则一行,支持域名匹配规则)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:375
msgid "Custom IP"
msgstr "自选 IP"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:233
msgid "Custom Stream Media DNS"
msgstr "自定义流媒体 DNS"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:21
msgid "DDNS Lists"
msgstr "DDNS 域名"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:312
msgid "DNS Cache Size"
msgstr "DNS 缓存大小"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:175
msgid "DNS Forward"
msgstr "DNS 转发"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:266
msgid ""
"DNS query request concurrency, The number of upstream DNS servers that are "
"allowed to initiate requests at the same time"
msgstr "DNS 查询请求并发数,允许同时发起请求的上游 DNS 服务器数量"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:179
msgid "DNS redirect"
msgstr "DNS 重定向"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:149
msgid "Database Update"
msgstr "数据库更新"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:162
msgid "Debug"
msgstr "调试"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:147
msgid "Default Config"
msgstr "内置预设"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:347
msgid "Disable RR Type 65 (HTTPS/SVCB)"
msgstr "禁用 RR Type 65 (HTTPS/SVCB)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:283
msgid "Disable TLS Certificate"
msgstr "禁用 TLS 证书"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:284
msgid ""
"Disable TLS Servers certificate validation, Can be useful if system CA "
"certificate expires or the system time is out of order"
msgstr ""
"禁用 TLS 服务器证书验证,当系统 CA 证书过期或系统时间错乱时,本选项可能会有用"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:272
msgid "DoH/TCP/DoT Connection Multiplexing idle timeout (default 30 seconds)"
msgstr "DoH/TCP/DoT 连接复用空闲保持时间(默认 30 秒)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:111
msgid "Enable Auto Database Update"
msgstr "启用自动更新"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:352
msgid "Enable DNS ADblock"
msgstr "启用 DNS 广告过滤"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:307
msgid "Enable DNS Cache"
msgstr "启用 DNS 缓存"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:290
msgid "Enable EDNS client subnet"
msgstr "启用 EDNS 客户端子网"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:278
msgid ""
"Enable TCP/DoT RFC 7766 new Query Pipelining connection multiplexing mode"
msgstr "启用 TCP/DoT RFC 7766 新型 Query Pipelining 连接复用模式"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:302
msgid "Enable this option fallback policy forces forwarding to remote DNS"
msgstr "启用此选项 fallback 策略会强制转发到远程 DNS"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:142
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:368
msgid "Enabled"
msgstr "启用"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:453
msgid "Enter the GeoIP.dat category to be exported, Allow add multiple tags"
msgstr "输入需要导出的 GeoIP.dat 类别条目,允许添加多个标签"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:448
msgid "Enter the GeoSite.dat category to be exported, Allow add multiple tags"
msgstr "填写需要导出的 GeoSite.dat 类别条目,允许添加多个标签"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:165
msgid "Error"
msgstr "错误"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:115
msgid "Every Day"
msgstr "每天"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:120
msgid "Every Friday"
msgstr "每周五"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:116
msgid "Every Monday"
msgstr "每周一"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:121
msgid "Every Saturday"
msgstr "每周六"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:122
msgid "Every Sunday"
msgstr "每周日"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:119
msgid "Every Thursday"
msgstr "每周四"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:117
msgid "Every Tuesday"
msgstr "每周二"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:118
msgid "Every Wednesday"
msgstr "每周三"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:449
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:454
msgid "Export directory: /var/mosdns"
msgstr "导出目录:/var/mosdns"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:43
msgid "Failed to clean logs."
msgstr "清理日志失败:%s"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:89
msgid "Failed to start update."
msgstr "启动更新失败"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:403
msgid "Flush DNS Cache"
msgstr "刷新 DNS 缓存"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:97
msgid "Flushing DNS Cache Failed, Please check if MosDNS is running."
msgstr "刷新 DNS 缓存失败,请检查 MosDNS 状态是否在运行中。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:95
msgid "Flushing DNS Cache Success."
msgstr "刷新 DNS 缓存成功"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:401
msgid ""
"Flushing DNS Cache will clear any IP addresses or DNS records from MosDNS "
"cache."
msgstr "刷新 DNS 缓存会清空 MosDNS 所有 IP 地址和 DNS 解析缓存。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:194
msgid "Follow WAN interface DNS if not enabled"
msgstr "不启用则使用 WAN 接口 DNS"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:199
msgid ""
"For Apple domains equipped with Chinese mainland CDN, always responsive to "
"Chinese CDN IP addresses"
msgstr "配备中国大陆 CDN 的 Apple 域名,始终应答中国大陆 CDN 地址"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:179
msgid "Force redirect all local DNS queries to MosDNS, a.k.a. DNS Hijacking"
msgstr "强制将所有本地 DNS 查询重定向到 MosDNS,即 DNS 劫持。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:175
msgid "Forward Dnsmasq Domain Name resolution requests to MosDNS"
msgstr "将 Dnsmasq 域名解析请求转发到 MosDNS 服务器"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:136
msgid "Full"
msgstr "全量"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:134
msgid "Full: includes all Countries and Private IP addresses."
msgstr "全量:包含所有国家和私有 IP 地址。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:139
msgid "GeoData Export"
msgstr "GeoData 导出"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:452
msgid "GeoIP Tags"
msgstr "GeoIP 标签"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:131
msgid "GeoIP Type"
msgstr "GeoIP 类型"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:447
msgid "GeoSite Tags"
msgstr "GeoSite 标签"
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:30
msgid "Geodata Update"
msgstr "更新数据库"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:141
msgid "GitHub Proxy"
msgstr "GitHub 代理"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:225
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:242
msgid "Google Public DNS (8.8.4.4)"
msgstr "谷歌公共 DNS8.8.4.4"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:224
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:241
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:259
msgid "Google Public DNS (8.8.8.8)"
msgstr "谷歌公共 DNS8.8.8.8"
#: luci-app-mosdns/root/usr/share/rpcd/acl.d/luci-app-mosdns.json:3
msgid "Grant UCI access for luci-app-mosdns"
msgstr "授予 luci-app-mosdns 的 UCI 访问权限"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:20
msgid "Grey Lists"
msgstr "灰名单"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:22
msgid "Hosts"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:295
msgid "IP Address"
msgstr "IP 地址"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:381
msgid ""
"IPv4 CIDR: <a href=\"https://www.cloudflare.com/ips-v4\" target=\"_blank"
"\">https://www.cloudflare.com/ips-v4</a> <br /> IPv6 CIDR: <a href=\"https://"
"www.cloudflare.com/ips-v6\" target=\"_blank\">https://www.cloudflare.com/ips-"
"v6</a>"
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:185
msgid ""
"IPv4 is preferred for China DNS resolution of dual-stack addresses, and is "
"not affected when the destination is IPv6 only"
msgstr "国内 DNS 解析双栈地址时首选 IPv4,目标仅 IPv6 时不受影响"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:190
msgid ""
"IPv4 is preferred for Remote / Streaming Media DNS resolution of dual-stack "
"addresses, and is not affected when the destination is IPv6 only"
msgstr "远程 / 流媒体 DNS 解析双栈地址时首选 IPv4,目标仅 IPv6 时不受影响"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:271
msgid "Idle Timeout"
msgstr "空闲超时"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:163
msgid "Info"
msgstr "信息"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:317
msgid "Lazy Cache TTL"
msgstr "乐观缓存 TTL"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:318
msgid ""
"Lazy cache survival time (in second). To disable Lazy Cache, please set to 0."
msgstr "乐观缓存生存时间(单位:秒),要禁用乐观缓存,请设置为 0"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:157
msgid "Listen Address"
msgstr "监听地址"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:152
msgid "Listen Port"
msgstr "监听端口"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:137
msgid "Little"
msgstr "轻量"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:132
msgid "Little: only include Mainland China and Private IP addresses."
msgstr "轻量:仅包含中国大陆和私有 IP 地址。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:70
msgid "Log Data"
msgstr "日志数据"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:169
msgid "Log File"
msgstr "日志文件"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:161
msgid "Log Level"
msgstr "日志等级"
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:38
msgid "Logs"
msgstr "日志"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:369
#, fuzzy
msgid ""
"Match the parsing result with the Cloudflare IP ranges, and when there is a "
"successful match, use the 'Custom IP' as the parsing result (experimental "
"feature)"
msgstr ""
"将解析结果与 Cloudflare IP 范围进行匹配,当匹配成功时,使用 “自选 IP” 作为解"
"析结果(实验性功能)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:341
msgid "Maximum TTL"
msgstr "覆盖最大 TTL 值(默认 0"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:335
msgid "Minimum TTL"
msgstr "覆盖最小 TTL 值(默认 0"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:342
msgid ""
"Modify the Maximum TTL value (seconds) for DNS answer results, 0 indicating "
"no modification"
msgstr "修改 DNS 应答结果的最大 TTL 值(秒),0 表示不修改"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:336
msgid ""
"Modify the Minimum TTL value (seconds) for DNS answer results, 0 indicating "
"no modification"
msgstr "修改 DNS 应答结果的最小 TTL 值 (秒),0 表示不修改"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:31
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:33
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:106
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:70
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:3
msgid "MosDNS"
msgstr "MosDNS"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:107
msgid "MosDNS is a plugin-based DNS forwarder/traffic splitter."
msgstr "MosDNS 是一个插件化的 DNS 转发/分流器。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:33
msgid "NOT RUNNING"
msgstr "未运行"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:234
msgid "Netflix, Disney+, Hulu and streaming media rules list will use this DNS"
msgstr "自定义 Netflix、Disney+、Hulu 以及 “流媒体” 规则列表的 DNS 服务器"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:27
msgid "No log data."
msgstr "无日志数据。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:296
msgid ""
"Please provide the IP address you use when accessing foreign websites. This "
"IP subnet (0/24) will be used as the ECS address for Remote / Streaming "
"Media DNS requests"
msgstr ""
"请提供您在访问国外网站时使用的 IP 地址,这个 IP 子网(0/24)将用作 远程 / 流"
"媒体 DNS 请求的 ECS 地址"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:22
msgid "Please wait, this may take a few moments..."
msgstr "请稍候,这可能需要一点时间..."
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:301
msgid "Prevent DNS Leaks"
msgstr "防止 DNS 泄漏"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:227
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:244
msgid "Quad9 Public DNS (149.112.112.112)"
msgstr "Quad9 公共 DNS149.112.112.112"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:226
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:243
msgid "Quad9 Public DNS (9.9.9.9)"
msgstr "Quad9 公共 DNS9.9.9.9"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:31
msgid "RUNNING"
msgstr "运行中"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:23
msgid "Redirect"
msgstr "重定向"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:151
msgid ""
"Redirecting requests for domain names. Request domain A, but return records "
"for domain B, for example: baidu.com qq.com (one rule per line)."
msgstr ""
"重定向请求的域名。请求域名 A,但返回域名 B 的记录,如:baidu.com qq.com(每个"
"规则一行)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/logs.js:75
msgid "Refresh every %s seconds."
msgstr "每 %s 秒刷新。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:189
msgid "Remote DNS prefer IPv4"
msgstr "远程 DNS 首选 IPv4"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:221
msgid "Remote DNS server"
msgstr "远程 DNS 服务器"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:11
msgid "Rule Settings"
msgstr "自定义规则列表"
#: luci-app-mosdns/root/usr/share/luci/menu.d/luci-app-mosdns.json:22
msgid "Rules"
msgstr "规则列表"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:324
msgid "Save the cache locally and reload the cache dump on the next startup"
msgstr "保存缓存到本地文件,以供下次启动时重新载入使用"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:28
msgid "Starting update..."
msgstr ""
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:25
msgid "Streaming Media"
msgstr "流媒体"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:238
msgid "Streaming Media DNS server"
msgstr "流媒体 DNS 服务器"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:359
msgid "Support for local files, such as: file:///var/mosdns/example.txt"
msgstr "支持本地文件,例如:file:///var/mosdns/example.txt"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:277
msgid "TCP/DoT Connection Multiplexing"
msgstr "TCP/DoT 连接复用"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:205
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:253
msgid "Tencent Public DNS (119.28.28.28)"
msgstr "腾讯公共 DNS119.28.28.28"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:204
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:252
msgid "Tencent Public DNS (119.29.29.29)"
msgstr "腾讯公共 DNS119.29.29.29"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:213
msgid "Tencent Public DNS (DNS over HTTPS)"
msgstr "腾讯公共 DNSDNS over HTTPS"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:12
msgid "The list of rules only apply to 'Default Config' profiles."
msgstr "规则列表仅适用于 “内置预设” 配置文件。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:297
msgid ""
"This feature is typically used when using a self-built DNS server as an "
"Remote / Streaming Media DNS upstream (requires support from the upstream "
"server)"
msgstr ""
"此功能通常在使用自建 DNS 服务器作为 远程 / 流媒体 DNS 上游时使用(需要上游服"
"务器的支持)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:427
msgid ""
"This is the content of the file '/etc/mosdns/config_custom.yaml' from which "
"your MosDNS configuration will be generated. Only accepts configuration "
"content in yaml format."
msgstr ""
"这是文件 “/etc/mosdns/config_custom.yaml” 的内容,您的 MosDNS 配置将从此文件"
"生成。仅接受 yaml 格式的配置内容。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:208
msgid "TrafficRoute Public DNS (180.184.1.1)"
msgstr "火山引擎公共 DNS180.184.1.1"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:209
msgid "TrafficRoute Public DNS (180.184.2.2)"
msgstr "火山引擎公共 DNS180.184.2.2"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:442
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:43
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:48
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:67
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:72
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:91
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:96
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:115
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:120
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:139
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:144
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:163
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:168
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:187
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:192
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:211
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:216
msgid "Unable to save contents: %s"
msgstr "无法保存内容:%s"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:114
msgid "Update Cycle"
msgstr "更新周期"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:105
msgid "Update GeoIP & GeoSite databases"
msgstr "更新广告规则、GeoIP & GeoSite 数据库"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:125
msgid "Update Time"
msgstr "更新时间"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:142
msgid ""
"Update data files with GitHub Proxy, leave blank to disable proxy downloads."
msgstr "通过 GitHub 代理更新数据文件,留空则禁用代理下载。"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:59
msgid "Update failed"
msgstr "更新失败"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:95
msgid "Update failed: %s"
msgstr "更新失败: %s"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:50
msgid "Update success"
msgstr "更新成功"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:37
msgid "Updating Database..."
msgstr "更新数据库..."
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:164
msgid "Warning"
msgstr "警告"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:199
msgid ""
"When enabling 'Custom Stream Media DNS', added domains will always use the "
"'Streaming Media DNS server' for resolution (one domain per line, supports "
"domain matching rules)."
msgstr ""
"启用 “自定义流媒体 DNS” 时,加入的域名始终使用 “流媒体 DNS 服务器” 进行解析"
"(每个域名一行,支持域名匹配规则)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:357
msgid ""
"When using custom rule sources, please use rule types supported by MosDNS "
"(domain list or AdGuardHome rules)."
msgstr ""
"使用自定义规则来源时,请使用 MosDNS 支持的规则类型(域名列表或 AdGuardHome 规"
"则)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/rules.js:18
msgid "White Lists"
msgstr "白名单"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:210
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:256
msgid "Xinfeng Public DNS (114.114.114.114)"
msgstr "信风公共 DNS114.114.114.114"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:211
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:257
msgid "Xinfeng Public DNS (114.114.115.115)"
msgstr "信风公共 DNS114.114.115.115"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:143
msgid "https://gh-proxy.com"
msgstr ""
+32
View File
@@ -0,0 +1,32 @@
config mosdns 'config'
option enabled '0'
option listen_port '5335'
option listen_address '0.0.0.0'
option geo_auto_update '0'
option geo_update_week_time '*'
option geo_update_day_time '2'
option geoip_type 'geoip-only-cn-private'
option configfile '/var/etc/mosdns.json'
option log_level 'info'
option log_file '/var/log/mosdns.log'
option cache '1'
option concurrent '2'
option idle_timeout '30'
option minimal_ttl '0'
option maximum_ttl '0'
option enable_pipeline '1'
option insecure_skip_verify '0'
option dns_leak '0'
option cloudflare '0'
option listen_port_api '9091'
option bootstrap_dns '119.29.29.29'
list remote_dns 'tls://8.8.8.8'
option redirect '1'
option prefer_ipv4 '1'
option enable_ecs_remote '0'
option cache_size '8000'
option lazy_cache_ttl '86400'
option dump_file '0'
option reject_type65 '1'
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
[ "$ACTION" = ifup ] && /etc/init.d/mosdns restart
+836
View File
@@ -0,0 +1,836 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2020-2022, IrineSistiana
# Copyright (C) 2023-2026, sbwml <admin@cooluc.com>
START=75
USE_PROCD=1
PROG=/usr/bin/mosdns
CONF=$(uci -q get mosdns.config.configfile)
CRON_FILE=/etc/crontabs/root
DUMP_FILE=/etc/mosdns/cache.dump
DUMP_FILE_DEFAULT=/usr/share/mosdns/cache.dump
MOSDNS_SCRIPT=/usr/share/mosdns/mosdns.uc
REDIRECT_LOCK_FILE=/etc/mosdns/redirect.lock
get_config() {
config_get enabled $1 enabled 0
config_get adblock $1 adblock 0
config_get ad_source $1 ad_source ""
config_get cache $1 cache 0
config_get cache_size $1 cache_size 8000
config_get lazy_cache_ttl $1 lazy_cache_ttl 86400
config_get dump_file $1 dump_file 0
config_get dump_interval $1 dump_interval 3600
config_get enable_pipeline $1 enable_pipeline 0
config_get geo_auto_update $1 geo_auto_update 0
config_get geo_update_day_time $1 geo_update_day_time 2
config_get geo_update_week_time $1 geo_update_week_time "*"
config_get listen_port $1 listen_port 5335
config_get listen_address $1 listen_address "0.0.0.0"
config_get log_file $1 log_file "/var/log/mosdns.log"
config_get log_level $1 log_level "info"
config_get minimal_ttl $1 minimal_ttl 0
config_get maximum_ttl $1 maximum_ttl 0
config_get redirect $1 redirect 0
config_get local_dns_redirect $1 local_dns_redirect 0
config_get prefer_ipv4_cn $1 prefer_ipv4_cn 0
config_get prefer_ipv4 $1 prefer_ipv4 0
config_get remote_dns $1 remote_dns "tls://8.8.8.8 tls://1.1.1.1"
config_get custom_local_dns $1 custom_local_dns 0
config_get apple_optimization $1 apple_optimization 0
config_get custom_stream_media_dns $1 custom_stream_media_dns 0
config_get stream_media_dns $1 stream_media_dns "tls://8.8.8.8"
config_get bootstrap_dns $1 bootstrap_dns "119.29.29.29"
config_get listen_port_api $1 listen_port_api 52001
config_get concurrent $1 concurrent 1
config_get insecure_skip_verify $1 insecure_skip_verify 0
config_get idle_timeout $1 idle_timeout 30
config_get enable_ecs_remote $1 enable_ecs_remote 0
config_get remote_ecs_ip $1 remote_ecs_ip "110.34.181.1"
config_get dns_leak $1 dns_leak 0
config_get cloudflare $1 cloudflare 0
config_get cloudflare_ip $1 cloudflare_ip ""
config_get reject_type65 $1 reject_type65 "0"
}
generate_config() {
# jshn shell library
. /usr/share/libubox/jshn.sh
# json data
json_init
# log
json_add_object 'log'
json_add_string "level" "$log_level"
json_add_string "file" "$log_file"
json_close_object
# api
json_add_object 'api'
json_add_string "http" "127.0.0.1:$listen_port_api"
json_close_object
# include
json_add_array "include"
json_close_array
# plugins
json_add_array "plugins"
# plugin: geosite_cn
json_add_object
json_add_string "tag" "geosite_cn"
json_add_string "type" "domain_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/var/mosdns/geosite_cn.txt"
json_close_array
json_close_object
json_close_object
# plugin: geoip_cn
json_add_object
json_add_string "tag" "geoip_cn"
json_add_string "type" "ip_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/var/mosdns/geoip_cn.txt"
json_close_array
json_close_object
json_close_object
# plugin: geosite_apple
json_add_object
json_add_string "tag" "geosite_apple"
json_add_string "type" "domain_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/var/mosdns/geosite_apple.txt"
json_close_array
json_close_object
json_close_object
# plugin: geosite_no_cn
json_add_object
json_add_string "tag" "geosite_no_cn"
json_add_string "type" "domain_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/var/mosdns/geosite_geolocation-!cn.txt"
json_close_array
json_close_object
json_close_object
# plugin: whitelist
json_add_object
json_add_string "tag" "whitelist"
json_add_string "type" "domain_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/etc/mosdns/rule/whitelist.txt"
json_close_array
json_close_object
json_close_object
# plugin: blocklist
json_add_object
json_add_string "tag" "blocklist"
json_add_string "type" "adblock_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/etc/mosdns/rule/blocklist.txt"
json_close_array
json_close_object
json_close_object
# plugin: greylist
json_add_object
json_add_string "tag" "greylist"
json_add_string "type" "domain_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/etc/mosdns/rule/greylist.txt"
json_close_array
json_close_object
json_close_object
# plugin: ddnslist
json_add_object
json_add_string "tag" "ddnslist"
json_add_string "type" "domain_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/etc/mosdns/rule/ddnslist.txt"
json_close_array
json_close_object
json_close_object
# plugin: hosts
json_add_object
json_add_string "tag" "hosts"
json_add_string "type" "hosts"
json_add_object "args"
json_add_array "files"
json_add_string "" "/etc/mosdns/rule/hosts.txt"
json_close_array
json_close_object
json_close_object
# plugin: redirect
json_add_object
json_add_string "tag" "redirect"
json_add_string "type" "redirect"
json_add_object "args"
json_add_array "files"
json_add_string "" "/etc/mosdns/rule/redirect.txt"
json_close_array
json_close_object
json_close_object
# plugin: adlist
json_add_object
json_add_string "tag" "adlist"
json_add_string "type" "adblock_set"
json_add_object "args"
json_add_array "files"
adlist=$($MOSDNS_SCRIPT get_adlist)
[ -z "$adlist" ] && adlist="/var/mosdns/disable-ads.txt" # fail-safe
for list in $adlist; do
json_add_string "" "$list"
done
json_close_array
json_close_object
json_close_object
# plugin: local_ptr
json_add_object
json_add_string "tag" "local_ptr"
json_add_string "type" "domain_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/etc/mosdns/rule/local-ptr.txt"
json_close_array
json_close_object
json_close_object
# plugin: stream_media
json_add_object
json_add_string "tag" "stream_media"
json_add_string "type" "domain_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/var/mosdns/geosite_disney.txt"
json_add_string "" "/var/mosdns/geosite_netflix.txt"
json_add_string "" "/var/mosdns/geosite_hulu.txt"
json_add_string "" "/etc/mosdns/rule/streaming.txt"
json_close_array
json_close_object
json_close_object
# plugin: cloudflare_cidr
json_add_object
json_add_string "tag" "cloudflare_cidr"
json_add_string "type" "ip_set"
json_add_object "args"
json_add_array "files"
json_add_string "" "/etc/mosdns/rule/cloudflare-cidr.txt"
json_close_array
json_close_object
json_close_object
# plugin: lazy_cache
[ "$cache" -eq 1 ] && {
json_add_object
json_add_string "tag" "lazy_cache"
json_add_string "type" "cache"
json_add_object "args"
json_add_int "size" "$cache_size"
json_add_int "lazy_cache_ttl" "$lazy_cache_ttl"
[ "$dump_file" -eq 1 ] && {
json_add_string "dump_file" "/etc/mosdns/cache.dump"
json_add_int "dump_interval" "$dump_interval"
}
json_close_object
json_close_object
}
# plugin: forward_xinfeng_udp
json_add_object
json_add_string "tag" "forward_xinfeng_udp"
json_add_string "type" "forward"
json_add_object "args"
json_add_int "concurrent" 2
json_add_array "upstreams"
json_add_object
json_add_string "addr" "114.114.114.114"
json_close_object
json_add_object
json_add_string "addr" "114.114.115.115"
json_close_object
json_close_array
json_close_object
json_close_object
# plugin: forward_local
json_add_object
json_add_string "tag" "forward_local"
json_add_string "type" "forward"
json_add_object "args"
json_add_int "concurrent" "$concurrent"
json_add_array "upstreams"
local_dns=$($MOSDNS_SCRIPT interface_dns)
[ -z "$local_dns" ] && local_dns="119.29.29.29 223.5.5.5" # fail-safe
for addr in $local_dns; do
enable_http3=0
if echo "$addr" | grep -q "^h3://"; then
enable_http3=1
addr=$(echo $addr | sed 's/h3:\/\//https:\/\//g')
fi
json_add_object
json_add_string "addr" "$addr"
json_add_string "bootstrap" "$bootstrap_dns"
json_add_boolean "enable_pipeline" "$enable_pipeline"
json_add_boolean "insecure_skip_verify" "$insecure_skip_verify"
json_add_int "idle_timeout" "$idle_timeout"
[ "$enable_http3" -eq 1 ] && json_add_boolean "enable_http3" "1"
json_close_object
done
json_close_array
json_close_object
json_close_object
# plugin: forward_remote
json_add_object
json_add_string "tag" "forward_remote"
json_add_string "type" "forward"
json_add_object "args"
json_add_int "concurrent" "$concurrent"
json_add_array "upstreams"
for addr in $remote_dns; do
enable_http3=0
if echo "$addr" | grep -q "^h3://"; then
enable_http3=1
addr=$(echo $addr | sed 's/h3:\/\//https:\/\//g')
fi
json_add_object
json_add_string "addr" "$addr"
json_add_string "bootstrap" "$bootstrap_dns"
json_add_boolean "enable_pipeline" "$enable_pipeline"
json_add_boolean "insecure_skip_verify" "$insecure_skip_verify"
json_add_int "idle_timeout" "$idle_timeout"
[ "$enable_http3" -eq 1 ] && json_add_boolean "enable_http3" "1"
json_close_object
done
json_close_array
json_close_object
json_close_object
# plugin: forward_remote_upstream
json_add_object
json_add_string "tag" "forward_remote_upstream"
json_add_string "type" "sequence"
json_add_array "args"
[ "$prefer_ipv4" -eq 1 ] && {
json_add_object
json_add_string "exec" "prefer_ipv4"
json_close_object
}
[ "$enable_ecs_remote" -eq 1 ] && {
json_add_object
json_add_string "exec" "ecs $remote_ecs_ip"
json_close_object
}
json_add_object
json_add_string "exec" "\$forward_remote"
json_close_object
json_close_array
json_close_object
# plugin: forward_stream_media
json_add_object
json_add_string "tag" "forward_stream_media"
json_add_string "type" "forward"
json_add_object "args"
json_add_int "concurrent" "$concurrent"
json_add_array "upstreams"
for addr in $stream_media_dns; do
enable_http3=0
if echo "$addr" | grep -q "^h3://"; then
enable_http3=1
addr=$(echo $addr | sed 's/h3:\/\//https:\/\//g')
fi
json_add_object
json_add_string "addr" "$addr"
json_add_string "bootstrap" "$bootstrap_dns"
json_add_boolean "enable_pipeline" "$enable_pipeline"
json_add_boolean "insecure_skip_verify" "$insecure_skip_verify"
json_add_int "idle_timeout" "$idle_timeout"
[ "$enable_http3" -eq 1 ] && json_add_boolean "enable_http3" "1"
json_close_object
done
json_close_array
json_close_object
json_close_object
# plugin: forward_stream_media_upstream
json_add_object
json_add_string "tag" "forward_stream_media_upstream"
json_add_string "type" "sequence"
json_add_array "args"
[ "$prefer_ipv4" -eq 1 ] && {
json_add_object
json_add_string "exec" "prefer_ipv4"
json_close_object
}
[ "$enable_ecs_remote" -eq 1 ] && {
json_add_object
json_add_string "exec" "ecs $remote_ecs_ip"
json_close_object
}
json_add_object
json_add_string "exec" "\$forward_stream_media"
json_close_object
json_close_array
json_close_object
# plugin: modify_ttl
json_add_object
json_add_string "tag" "modify_ttl"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "exec" "ttl $minimal_ttl-$maximum_ttl"
json_close_object
json_close_array
json_close_object
# plugin: modify_ddns_ttl
json_add_object
json_add_string "tag" "modify_ddns_ttl"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "exec" "ttl 5-5"
json_close_object
json_close_array
json_close_object
# plugin: has_resp_sequence
json_add_object
json_add_string "tag" "has_resp_sequence"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "matches" "qname \$ddnslist"
json_add_string "exec" "\$modify_ddns_ttl"
json_close_object
json_add_object
json_add_string "matches" "!qname \$ddnslist"
json_add_string "exec" "\$modify_ttl"
json_close_object
[ "$cloudflare" -eq 1 ] && {
json_add_object
json_add_array "matches"
json_add_string "" "!qname \$whitelist"
json_add_string "" "!qname \$greylist"
json_add_string "" "!qname \$stream_media"
json_add_string "" "resp_ip \$cloudflare_cidr"
json_close_array
json_add_string "exec" "black_hole $cloudflare_ip"
json_close_object
}
json_add_object
json_add_string "matches" "has_resp"
json_add_string "exec" "accept"
json_close_object
json_close_array
json_close_object
# plugin: query_is_non_local_ip
json_add_object
json_add_string "tag" "query_is_non_local_ip"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "exec" "\$forward_local"
json_close_object
json_add_object
json_add_string "matches" "!resp_ip \$geoip_cn"
json_add_string "exec" "drop_resp"
json_close_object
json_close_array
json_close_object
# plugin: fallback
json_add_object
json_add_string "tag" "fallback"
json_add_string "type" "fallback"
json_add_object "args"
[ "$dns_leak" -eq 1 ] && json_add_string "primary" "forward_remote_upstream" || json_add_string "primary" "query_is_non_local_ip"
json_add_string "secondary" "forward_remote_upstream"
json_add_int "threshold" 500
json_add_boolean "always_standby" 1
json_close_object
json_close_object
# plugin: apple_domain_fallback
json_add_object
json_add_string "tag" "apple_domain_fallback"
json_add_string "type" "fallback"
json_add_object "args"
json_add_string "primary" "query_is_non_local_ip"
json_add_string "secondary" "forward_xinfeng_udp"
json_add_int "threshold" 100
json_add_boolean "always_standby" 1
json_close_object
json_close_object
# plugin: query_is_apple_domain
json_add_object
json_add_string "tag" "query_is_apple_domain"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "matches" "!qname \$geosite_apple"
json_add_string "exec" "return"
json_close_object
json_add_object
json_add_string "exec" "\$apple_domain_fallback"
json_close_object
json_close_array
json_close_object
# plugin: query_is_ddns_domain
json_add_object
json_add_string "tag" "query_is_ddns_domain"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "matches" "qname \$ddnslist"
json_add_string "exec" "\$forward_local"
json_close_object
json_close_array
json_close_object
# plugin: query_is_local_domain
json_add_object
json_add_string "tag" "query_is_local_domain"
json_add_string "type" "sequence"
json_add_array "args"
[ "$prefer_ipv4_cn" -eq 1 ] && {
json_add_object
json_add_string "exec" "prefer_ipv4"
json_close_object
}
json_add_object
json_add_string "matches" "qname \$geosite_cn"
json_add_string "exec" "\$forward_local"
json_close_object
json_close_array
json_close_object
# plugin: query_is_no_local_domain
json_add_object
json_add_string "tag" "query_is_no_local_domain"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "matches" "qname \$geosite_no_cn"
json_add_string "exec" "\$forward_remote_upstream"
json_close_object
json_close_array
json_close_object
# plugin: query_is_whitelist_domain
json_add_object
json_add_string "tag" "query_is_whitelist_domain"
json_add_string "type" "sequence"
json_add_array "args"
[ "$prefer_ipv4_cn" -eq 1 ] && {
json_add_object
json_add_string "exec" "prefer_ipv4"
json_close_object
}
json_add_object
json_add_string "matches" "qname \$whitelist"
json_add_string "exec" "\$forward_local"
json_close_object
json_close_array
json_close_object
# plugin: query_is_greylist_domain
json_add_object
json_add_string "tag" "query_is_greylist_domain"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "matches" "qname \$greylist"
json_add_string "exec" "\$forward_remote_upstream"
json_close_object
json_close_array
json_close_object
# plugin: query_is_reject_domain
json_add_object
json_add_string "tag" "query_is_reject_domain"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "matches" "qname \$blocklist"
json_add_string "exec" "reject 3"
json_close_object
json_add_object
json_add_string "matches" "qname \$adlist"
json_add_string "exec" "reject 3"
json_close_object
json_add_object
json_add_array "matches"
json_add_string "" "qtype 12"
json_add_string "" "qname \$local_ptr"
json_close_array
json_add_string "exec" "reject 3"
json_close_object
[ "$reject_type65" -eq 1 ] && {
json_add_object
json_add_string "matches" "qtype 65"
json_add_string "exec" "reject 3"
json_close_object
}
json_close_array
json_close_object
# plugin: query_is_stream_media_domain
json_add_object
json_add_string "tag" "query_is_stream_media_domain"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "matches" "qname \$stream_media"
json_add_string "exec" "\$forward_stream_media_upstream"
json_close_object
json_close_array
json_close_object
# plugin: main_sequence
json_add_object
json_add_string "tag" "main_sequence"
json_add_string "type" "sequence"
json_add_array "args"
json_add_object
json_add_string "exec" "\$hosts"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
[ "$cache" -eq 1 ] && {
json_add_object
json_add_array "matches"
json_add_string "" "!qname \$ddnslist"
json_add_string "" "!qname \$blocklist"
json_add_string "" "!qname \$adlist"
json_add_string "" "!qname \$local_ptr"
json_close_array
json_add_string "exec" "\$lazy_cache"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
}
json_add_object
json_add_string "exec" "\$redirect"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
json_add_object
[ "$apple_optimization" -eq 1 ] && {
json_add_string "exec" "\$query_is_apple_domain"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
json_add_object
}
json_add_string "exec" "\$query_is_ddns_domain"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
json_add_object
json_add_string "exec" "\$query_is_whitelist_domain"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
json_add_object
json_add_string "exec" "\$query_is_reject_domain"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
json_add_object
json_add_string "exec" "\$query_is_greylist_domain"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
[ "$custom_stream_media_dns" -eq 1 ] && {
json_add_object
json_add_string "exec" "\$query_is_stream_media_domain"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
}
json_add_object
json_add_string "exec" "\$query_is_local_domain"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
json_add_object
json_add_string "exec" "\$query_is_no_local_domain"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
json_add_object
json_add_string "exec" "\$fallback"
json_close_object
json_add_object
json_add_string "exec" "jump has_resp_sequence"
json_close_object
json_close_array
json_close_object
# plugin: udp_server
json_add_object
json_add_string "tag" "udp_server"
json_add_string "type" "udp_server"
json_add_object "args"
json_add_string "entry" "main_sequence"
json_add_string "listen" "$listen_address:$listen_port"
json_close_object
json_close_object
# plugin: tcp_server
json_add_object
json_add_string "tag" "tcp_server"
json_add_string "type" "tcp_server"
json_add_object "args"
json_add_string "entry" "main_sequence"
json_add_string "listen" "$listen_address:$listen_port"
json_close_object
json_close_object
# close plugins array
json_close_array
# print json
json_dump > /var/etc/mosdns.json
# init dump_file
[ "$dump_file" -eq 1 ] && [ ! -f $DUMP_FILE ] && cp -a $DUMP_FILE_DEFAULT $DUMP_FILE
[ "$dump_file" -eq 0 ] && \cp -a $DUMP_FILE_DEFAULT $DUMP_FILE
}
service_triggers() {
procd_add_reload_trigger "mosdns"
}
dhcp_setting() {
[ ! -f "$REDIRECT_LOCK_FILE" ] && {
printf "rebind_protection=$(uci -q get dhcp.@dnsmasq[0].rebind_protection)\n"
printf "rebind_localhost=$(uci -q get dhcp.@dnsmasq[0].rebind_localhost)\n"
printf "noresolv=$(uci -q get dhcp.@dnsmasq[0].noresolv)\n"
printf "resolvfile=$(uci -q get dhcp.@dnsmasq[0].resolvfile)\n"
printf "cachesize=$(uci -q get dhcp.@dnsmasq[0].cachesize)\n"
} > $REDIRECT_LOCK_FILE
if [ "${CONF}" = "/var/etc/mosdns.json" ]; then
sed -i "/list server/d" /etc/config/dhcp
uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#$listen_port"
uci set dhcp.@dnsmasq[0].rebind_protection='0'
uci set dhcp.@dnsmasq[0].noresolv="1"
uci set dhcp.@dnsmasq[0].cachesize='0'
uci commit dhcp
else
sed -i "/list server/d" /etc/config/dhcp
uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#$(awk -F'[:" ]+' '/^\s+listen:/{for(i=1;i<=NF;i++){if($i~/^[0-9]+$/){print $i;exit}}}' $CONF)"
uci set dhcp.@dnsmasq[0].rebind_protection='0'
uci set dhcp.@dnsmasq[0].noresolv="1"
uci set dhcp.@dnsmasq[0].cachesize='0'
uci commit dhcp
fi
}
uci_set_or_del() {
local key="$1"
local val="$2"
if [ -n "$val" ]; then
uci set "$key=$val"
else
uci del "$key"
fi
}
restore_dhcp_setting() {
if [ -f "$REDIRECT_LOCK_FILE" ]; then
sed -i "/list server/d" /etc/config/dhcp
source "$REDIRECT_LOCK_FILE"
uci_set_or_del dhcp.@dnsmasq[0].rebind_protection "$rebind_protection"
uci_set_or_del dhcp.@dnsmasq[0].resolvfile "$resolvfile"
uci_set_or_del dhcp.@dnsmasq[0].rebind_localhost "$rebind_localhost"
uci_set_or_del dhcp.@dnsmasq[0].noresolv "$noresolv"
uci_set_or_del dhcp.@dnsmasq[0].cachesize "$cachesize"
uci commit dhcp
rm -f "$REDIRECT_LOCK_FILE"
fi
}
reload_dnsmasq() {
[ "$(/etc/init.d/dnsmasq status)" = "running" ] && /etc/init.d/dnsmasq reload
}
reload_service() {
stop
sleep 1
start
}
setcron() {
sed -i '/mosdns.uc/d' $CRON_FILE 2>/dev/null
[ "$geo_auto_update" -eq 1 ] && echo "0 $geo_update_day_time * * $geo_update_week_time /usr/share/mosdns/mosdns.uc update" >> $CRON_FILE
crontab $CRON_FILE
}
delcron() {
sed -i '/mosdns.uc/d' $CRON_FILE 2>/dev/null
crontab $CRON_FILE
}
start_service() {
config_load "mosdns"
config_foreach get_config "mosdns"
[ $enabled -ne 1 ] && return 1
delcron ; setcron
rm -rf /tmp/log/mosdns*
$MOSDNS_SCRIPT v2dat_dump
[ "${CONF}" = "/var/etc/mosdns.json" ] && generate_config
procd_open_instance mosdns
procd_set_param env QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING=true
procd_set_param command $PROG start
procd_append_param command -c "$CONF"
procd_append_param command -d "/etc/mosdns"
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param respawn
procd_close_instance mosdns
[ "$redirect" -ne 1 ] && restore_dhcp_setting
[ "$redirect" -eq 1 ] && dhcp_setting
reload_dnsmasq
# dns hijack
if [ "$local_dns_redirect" -eq 1 ] && [ -f "/sbin/fw4" ]; then
! nft --check list table inet mosdns > "/dev/null" 2>&1 || \
nft delete table inet mosdns
nft add table inet mosdns
nft add chain inet mosdns prerouting "{ type nat hook prerouting priority -95; policy accept; }"
nft add rule inet mosdns prerouting "meta nfproto { ipv4, ipv6 } udp dport 53 counter redirect to :$listen_port comment \"DNS HIJACK\""
fi
# Update Adlist
update_list=0
if [ "$adblock" -eq 1 ]; then
if [ -f "/etc/mosdns/rule/.ad_source" ]; then
for url in $ad_source; do
if [ "$url" = "geosite.dat" ] ||[ $(echo "$url" | grep -c -E "^file://") -eq 1 ]; then
continue
fi
if [ $(grep -c "$url" "/etc/mosdns/rule/.ad_source") -eq 0 ]; then
update_list=1
break
fi
done
else
update_list=1
fi
fi
[ "$update_list" -eq 1 ] && $MOSDNS_SCRIPT update_adlist &
}
stop_service() {
config_load "mosdns"
config_foreach get_config "mosdns"
[ "$enabled" -eq "0" ] && restore_dhcp_setting
! nft --check list table inet mosdns > "/dev/null" 2>&1 || \
nft delete table inet mosdns
reload_dnsmasq
delcron
}
@@ -0,0 +1,143 @@
log:
level: info
file: "/var/log/mosdns.log"
# API 入口设置
api:
http: "0.0.0.0:9091"
include: []
plugins:
# 国内域名
- tag: geosite_cn
type: domain_set
args:
files:
- "/var/mosdns/geosite_cn.txt"
# 国内 IP
- tag: geoip_cn
type: ip_set
args:
files:
- "/var/mosdns/geoip_cn.txt"
# 国外域名
- tag: geosite_no_cn
type: domain_set
args:
files:
- "/var/mosdns/geosite_geolocation-!cn.txt"
# 缓存
- tag: lazy_cache
type: cache
args:
size: 20000
lazy_cache_ttl: 86400
dump_file: "/etc/mosdns/cache.dump"
dump_interval: 600
# 转发至本地服务器
- tag: forward_local
type: forward
args:
upstreams:
- addr: "https://doh.pub/dns-query"
bootstrap: 180.76.76.76
- addr: 119.29.29.29
# 转发至远程服务器
- tag: forward_remote
type: forward
args:
upstreams:
- addr: tls://8.8.8.8
enable_pipeline: false
# 国内解析
- tag: local_sequence
type: sequence
args:
- exec: $forward_local
# 国外解析
- tag: remote_sequence
type: sequence
args:
- exec: prefer_ipv4
- exec: $forward_remote
# 有响应终止返回
- tag: has_resp_sequence
type: sequence
args:
- matches: has_resp
exec: accept
# fallback 用本地服务器 sequence
# 返回非国内 ip 则 drop_resp
- tag: query_is_local_ip
type: sequence
args:
- exec: $local_sequence
- matches: "!resp_ip $geoip_cn"
exec: drop_resp
# fallback 用远程服务器 sequence
- tag: query_is_remote
type: sequence
args:
- exec: $remote_sequence
# fallback 用远程服务器 sequence
- tag: fallback
type: fallback
args:
primary: query_is_local_ip
secondary: query_is_remote
threshold: 500
always_standby: true
# 查询国内域名
- tag: query_is_local_domain
type: sequence
args:
- matches: qname $geosite_cn
exec: $local_sequence
# 查询国外域名
- tag: query_is_no_local_domain
type: sequence
args:
- matches: qname $geosite_no_cn
exec: $remote_sequence
# 主要的运行逻辑插件
# sequence 插件中调用的插件 tag 必须在 sequence 前定义,
# 否则 sequence 找不到对应插件。
- tag: main_sequence
type: sequence
args:
- exec: $lazy_cache
- exec: jump has_resp_sequence
- exec: $query_is_local_domain
- exec: jump has_resp_sequence
- exec: $query_is_no_local_domain
- exec: jump has_resp_sequence
- exec: $fallback
# 启动 udp 服务器。
- tag: udp_server
type: udp_server
args:
entry: main_sequence
listen: ":5335"
# 启动 tcp 服务器。
- tag: tcp_server
type: tcp_server
args:
entry: main_sequence
listen: ":5335"
@@ -0,0 +1,2 @@
# MosDNS Rules
@@ -0,0 +1,22 @@
173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0.0/15
104.16.0.0/13
104.24.0.0/14
172.64.0.0/13
131.0.72.0/22
2400:cb00::/32
2606:4700::/32
2803:f800::/32
2405:b500::/32
2405:8100::/32
2a06:98c0::/29
2c0f:f248::/32
@@ -0,0 +1,2 @@
# MosDNS Rules
@@ -0,0 +1,2 @@
# MosDNS Rules
@@ -0,0 +1,2 @@
# MosDNS Rules
@@ -0,0 +1,87 @@
0.in-addr.arpa
10.in-addr.arpa
127.in-addr.arpa
16.172.in-addr.arpa
17.172.in-addr.arpa
18.172.in-addr.arpa
19.172.in-addr.arpa
20.172.in-addr.arpa
21.172.in-addr.arpa
22.172.in-addr.arpa
23.172.in-addr.arpa
24.172.in-addr.arpa
25.172.in-addr.arpa
26.172.in-addr.arpa
27.172.in-addr.arpa
28.172.in-addr.arpa
29.172.in-addr.arpa
30.172.in-addr.arpa
31.172.in-addr.arpa
64.100.in-addr.arpa
65.100.in-addr.arpa
66.100.in-addr.arpa
67.100.in-addr.arpa
68.100.in-addr.arpa
69.100.in-addr.arpa
70.100.in-addr.arpa
71.100.in-addr.arpa
72.100.in-addr.arpa
73.100.in-addr.arpa
74.100.in-addr.arpa
75.100.in-addr.arpa
76.100.in-addr.arpa
77.100.in-addr.arpa
78.100.in-addr.arpa
79.100.in-addr.arpa
80.100.in-addr.arpa
81.100.in-addr.arpa
82.100.in-addr.arpa
83.100.in-addr.arpa
84.100.in-addr.arpa
85.100.in-addr.arpa
86.100.in-addr.arpa
87.100.in-addr.arpa
88.100.in-addr.arpa
89.100.in-addr.arpa
90.100.in-addr.arpa
91.100.in-addr.arpa
92.100.in-addr.arpa
93.100.in-addr.arpa
94.100.in-addr.arpa
95.100.in-addr.arpa
96.100.in-addr.arpa
97.100.in-addr.arpa
98.100.in-addr.arpa
99.100.in-addr.arpa
100.100.in-addr.arpa
101.100.in-addr.arpa
102.100.in-addr.arpa
103.100.in-addr.arpa
104.100.in-addr.arpa
105.100.in-addr.arpa
106.100.in-addr.arpa
107.100.in-addr.arpa
108.100.in-addr.arpa
109.100.in-addr.arpa
110.100.in-addr.arpa
111.100.in-addr.arpa
112.100.in-addr.arpa
113.100.in-addr.arpa
114.100.in-addr.arpa
115.100.in-addr.arpa
116.100.in-addr.arpa
117.100.in-addr.arpa
118.100.in-addr.arpa
119.100.in-addr.arpa
120.100.in-addr.arpa
121.100.in-addr.arpa
122.100.in-addr.arpa
123.100.in-addr.arpa
124.100.in-addr.arpa
125.100.in-addr.arpa
126.100.in-addr.arpa
127.100.in-addr.arpa
2.0.192.in-addr.arpa
168.192.in-addr.arpa
255.255.255.255.in-addr.arpa
domain:ip6.arpa
@@ -0,0 +1,2 @@
# MosDNS Rules
@@ -0,0 +1,2 @@
# MosDNS Rules
@@ -0,0 +1,2 @@
# MosDNS Rules
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
[ -f "/etc/config/ucitrack" ] && {
uci -q batch <<-EOF >/dev/null
delete ucitrack.@mosdns[-1]
add ucitrack mosdns
set ucitrack.@mosdns[-1].init=mosdns
commit ucitrack
EOF
}
rm -rf /tmp/luci-*
exit 0
@@ -0,0 +1,45 @@
{
"admin/services/mosdns": {
"title": "MosDNS",
"order": 30,
"action": {
"type": "firstchild"
},
"depends": {
"acl": [ "luci-app-mosdns" ],
"uci": { "mosdns": true }
}
},
"admin/services/mosdns/basic": {
"title": "Basic Setting",
"order": 10,
"action": {
"type": "view",
"path": "mosdns/basic"
}
},
"admin/services/mosdns/rules": {
"title": "Rules",
"order": 15,
"action": {
"type": "view",
"path": "mosdns/rules"
}
},
"admin/services/mosdns/update": {
"title": "Geodata Update",
"order": 20,
"action": {
"type": "view",
"path": "mosdns/update"
}
},
"admin/services/mosdns/logs": {
"title": "Logs",
"order": 25,
"action": {
"type": "view",
"path": "mosdns/logs"
}
}
}
Binary file not shown.
+354
View File
@@ -0,0 +1,354 @@
#!/usr/bin/env ucode
'use strict';
import { popen, mkdir, unlink, writefile, open, stat, stdout } from 'fs';
import { cursor } from 'uci';
import { connect } from 'ubus';
function to_array(val) {
let res =[];
if (type(val) == 'array') {
for (let i = 0; i < length(val); i++) {
if (type(val[i]) == 'string') {
let s = replace(val[i], /^\s+|\s+$/g, '');
if (s != "") push(res, s);
}
}
} else if (type(val) == 'string') {
let parts = split(val, /[ \t\n]+/);
for (let i = 0; i < length(parts); i++) {
if (parts[i] != "") push(res, parts[i]);
}
}
return res;
}
function exec_sys(cmd) {
let p = popen(cmd + " 2>&1", "r");
if (!p) return { code: -1, stdout: "" };
let stdout = p.read("all");
let code = p.close();
if (type(stdout) == 'string') {
stdout = replace(stdout, /^\s+|\s+$/g, '');
}
return { code: code, stdout: stdout || "" };
}
function interface_dns() {
let uci_cursor = cursor();
uci_cursor.load('mosdns');
let dns_list =[];
if (uci_cursor.get('mosdns', 'config', 'custom_local_dns') === '1') {
dns_list = to_array(uci_cursor.get('mosdns', 'config', 'local_dns'));
} else {
uci_cursor.load('network');
let peerdns = uci_cursor.get('network', 'wan', 'peerdns');
let proto = uci_cursor.get('network', 'wan', 'proto');
if (peerdns === '0' || proto === 'static') {
dns_list = to_array(uci_cursor.get('network', 'wan', 'dns'));
} else {
let ubus_conn = connect();
if (ubus_conn) {
let status = ubus_conn.call('network.interface.wan', 'status');
if (status && type(status['dns-server']) == 'array' && length(status['dns-server']) > 0) {
dns_list = status['dns-server'];
}
}
}
}
if (length(dns_list) === 0) {
dns_list =['119.29.29.29', '223.5.5.5'];
}
print(join(" ", dns_list) + "\n");
}
function get_adlist() {
let uci_cursor = cursor();
uci_cursor.load('mosdns');
let adblock = uci_cursor.get('mosdns', 'config', 'adblock');
if (adblock !== '1') {
mkdir('/etc/mosdns/rule', 0755);
exec_sys('rm -rf /etc/mosdns/rule/adlist /etc/mosdns/rule/.ad_source');
writefile('/var/mosdns/disable-ads.txt', '');
print("/var/mosdns/disable-ads.txt\n");
return;
}
mkdir('/etc/mosdns/rule/adlist', 0755);
let ad_source = to_array(uci_cursor.get('mosdns', 'config', 'ad_source'));
let adlist =[];
for (let i = 0; i < length(ad_source); i++) {
let url = ad_source[i];
if (!url) continue;
if (url === 'geosite.dat') {
push(adlist, '/var/mosdns/geosite_category-ads-all.txt');
} else if (index(url, 'file://') === 0) {
push(adlist, substr(url, 7));
} else {
let parts = split(url, '/');
let filename = parts[length(parts) - 1];
let local_path = `/etc/mosdns/rule/adlist/${filename}`;
if (!stat(local_path)) {
writefile(local_path, '');
}
push(adlist, local_path);
}
}
print(join("\n", adlist) + "\n");
}
function update_adlist() {
let uci_cursor = cursor();
uci_cursor.load('mosdns');
if (uci_cursor.get('mosdns', 'config', 'adblock') !== '1') {
return false;
}
let lock_file = '/var/lock/mosdns_ad_update.lock';
let ad_source = to_array(uci_cursor.get('mosdns', 'config', 'ad_source'));
let github_proxy = uci_cursor.get('mosdns', 'config', 'github_proxy') || '';
mkdir('/etc/mosdns/rule', 0755);
writefile('/etc/mosdns/rule/.ad_source', '');
if (stat(lock_file)) return false;
writefile(lock_file, '');
let tmp_res = exec_sys('mktemp -d');
if (tmp_res.code !== 0) {
unlink(lock_file);
die("Failed to create temp directory for adlist.");
}
let ad_tmpdir = tmp_res.stdout;
let has_update = false;
let download_failed = false;
for (let i = 0; i < length(ad_source); i++) {
let url = ad_source[i];
if (!url) continue;
if (url !== 'geosite.dat' && index(url, 'file://') !== 0) {
has_update = true;
exec_sys(`echo "${url}" >> /etc/mosdns/rule/.ad_source`);
let parts = split(url, '/');
let filename = parts[length(parts) - 1];
let mirror = "";
if (match(url, /^https:\/\/raw\.githubusercontent\.com/)) {
mirror = github_proxy ? github_proxy + '/' : '';
}
print(`Downloading ${mirror}${url}\n`);
stdout.flush();
let curl_res = exec_sys(`curl --connect-timeout 5 -m 90 --ipv4 -kfSLo "${ad_tmpdir}/${filename}" "${mirror}${url}"`);
if (curl_res.code !== 0) download_failed = true;
}
}
if (download_failed) {
exec_sys(`rm -rf "${ad_tmpdir}"`);
unlink(lock_file);
die("Rules download failed.");
} else {
if (has_update) {
mkdir('/etc/mosdns/rule/adlist', 0755);
exec_sys('rm -rf /etc/mosdns/rule/adlist/*');
exec_sys(`cp "${ad_tmpdir}"/* /etc/mosdns/rule/adlist/`);
}
}
exec_sys(`rm -rf "${ad_tmpdir}"`);
unlink(lock_file);
return has_update;
}
function update_geodat() {
let uci_cursor = cursor();
uci_cursor.load('mosdns');
let github_proxy = uci_cursor.get('mosdns', 'config', 'github_proxy') || '';
let mirror = github_proxy ? github_proxy + '/' : '';
let geoip_type = uci_cursor.get('mosdns', 'config', 'geoip_type') || 'geoip-only-cn-private';
let v2dat_dir = '/usr/share/v2ray';
let tmp_res = exec_sys('mktemp -d');
if (tmp_res.code !== 0) die("Failed to create temp directory for geodata.");
let tmpdir = tmp_res.stdout;
exec_sys(`mkdir -p "${v2dat_dir}"`);
let geoip_updated = false;
let geoip_url = mirror + "https://github.com/Loyalsoldier/geoip/releases/latest/download/" + geoip_type + ".dat";
print(`Downloading ${geoip_url}.sha256sum\n`);
stdout.flush();
if (exec_sys(`curl --connect-timeout 5 -m 20 --ipv4 -kfSLo "${tmpdir}/geoip.dat.sha256sum" "${geoip_url}.sha256sum"`).code !== 0) {
exec_sys(`rm -rf "${tmpdir}"`);
die("Failed to download geoip.dat.sha256sum");
}
let geoip_sum_remote = split(exec_sys(`cat "${tmpdir}/geoip.dat.sha256sum"`).stdout, /[ \t\n]+/)[0];
let geoip_sum_local = "";
if (stat(`${v2dat_dir}/geoip.dat`)) {
geoip_sum_local = split(exec_sys(`sha256sum "${v2dat_dir}/geoip.dat"`).stdout, /[ \t\n]+/)[0];
}
if (geoip_sum_local === geoip_sum_remote) {
print("geoip.dat is up to date.\n");
stdout.flush();
} else {
print(`Downloading ${geoip_url}\n`);
stdout.flush();
if (exec_sys(`curl --connect-timeout 5 -m 120 --ipv4 -kfSLo "${tmpdir}/geoip.dat" "${geoip_url}"`).code !== 0) {
exec_sys(`rm -rf "${tmpdir}"`);
die("Failed to download geoip.dat");
}
let sum_downloaded = split(exec_sys(`sha256sum "${tmpdir}/geoip.dat"`).stdout, /[ \t\n]+/)[0];
if (sum_downloaded !== geoip_sum_remote) {
exec_sys(`rm -rf "${tmpdir}"`);
die("geoip.dat checksum error");
}
geoip_updated = true;
}
let geosite_updated = false;
let geosite_url = mirror + "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat";
print(`Downloading ${geosite_url}.sha256sum\n`);
stdout.flush();
if (exec_sys(`curl --connect-timeout 5 -m 20 --ipv4 -kfSLo "${tmpdir}/geosite.dat.sha256sum" "${geosite_url}.sha256sum"`).code !== 0) {
exec_sys(`rm -rf "${tmpdir}"`);
die("Failed to download geosite.dat.sha256sum");
}
let geosite_sum_remote = split(exec_sys(`cat "${tmpdir}/geosite.dat.sha256sum"`).stdout, /[ \t\n]+/)[0];
let geosite_sum_local = "";
if (stat(`${v2dat_dir}/geosite.dat`)) {
geosite_sum_local = split(exec_sys(`sha256sum "${v2dat_dir}/geosite.dat"`).stdout, /[ \t\n]+/)[0];
}
if (geosite_sum_local === geosite_sum_remote) {
print("geosite.dat is up to date.\n");
stdout.flush();
} else {
print(`Downloading ${geosite_url}\n`);
stdout.flush();
if (exec_sys(`curl --connect-timeout 5 -m 120 --ipv4 -kfSLo "${tmpdir}/geosite.dat" "${geosite_url}"`).code !== 0) {
exec_sys(`rm -rf "${tmpdir}"`);
die("Failed to download geosite.dat");
}
let sum_downloaded = split(exec_sys(`sha256sum "${tmpdir}/geosite.dat"`).stdout, /[ \t\n]+/)[0];
if (sum_downloaded !== geosite_sum_remote) {
exec_sys(`rm -rf "${tmpdir}"`);
die("geosite.dat checksum error");
}
geosite_updated = true;
}
if (geoip_updated) {
exec_sys(`cp -a "${tmpdir}/geoip.dat" "${v2dat_dir}/"`);
}
if (geosite_updated) {
exec_sys(`cp -a "${tmpdir}/geosite.dat" "${v2dat_dir}/"`);
}
exec_sys(`rm -rf "${tmpdir}"`);
}
function v2dat_dump() {
let uci_cursor = cursor();
uci_cursor.load('mosdns');
let v2dat_dir = '/usr/share/v2ray';
let configfile = uci_cursor.get('mosdns', 'config', 'configfile') || '/var/etc/mosdns.json';
let adblock = uci_cursor.get('mosdns', 'config', 'adblock');
let ad_source = uci_cursor.get('mosdns', 'config', 'ad_source') || "";
let streaming_media = uci_cursor.get('mosdns', 'config', 'custom_stream_media_dns');
mkdir('/var/mosdns', 0755);
exec_sys('rm -f /var/mosdns/geo*.txt');
if (configfile === "/var/etc/mosdns.json") {
exec_sys(`v2dat unpack geoip -o /var/mosdns -f cn ${v2dat_dir}/geoip.dat`);
exec_sys(`v2dat unpack geosite -o /var/mosdns -f cn -f apple -f 'geolocation-!cn' ${v2dat_dir}/geosite.dat`);
if (adblock === '1' && index(ad_source, 'geosite.dat') !== -1) {
exec_sys(`v2dat unpack geosite -o /var/mosdns -f category-ads-all ${v2dat_dir}/geosite.dat`);
}
if (streaming_media === '1') {
exec_sys(`v2dat unpack geosite -o /var/mosdns -f netflix -f disney -f hulu ${v2dat_dir}/geosite.dat`);
} else {
writefile('/var/mosdns/geosite_disney.txt', '');
writefile('/var/mosdns/geosite_netflix.txt', '');
writefile('/var/mosdns/geosite_hulu.txt', '');
}
} else {
exec_sys(`v2dat unpack geoip -o /var/mosdns -f cn ${v2dat_dir}/geoip.dat`);
exec_sys(`v2dat unpack geosite -o /var/mosdns -f cn -f 'geolocation-!cn' ${v2dat_dir}/geosite.dat`);
let geoip_tags = to_array(uci_cursor.get('mosdns', 'config', 'geoip_tags'));
if (length(geoip_tags) > 0) {
let tags_str = "-f '" + join("' -f '", geoip_tags) + "'";
exec_sys(`v2dat unpack geoip -o /var/mosdns ${tags_str} ${v2dat_dir}/geoip.dat`);
}
let geosite_tags = to_array(uci_cursor.get('mosdns', 'config', 'geosite_tags'));
if (length(geosite_tags) > 0) {
let tags_str = "-f '" + join("' -f '", geosite_tags) + "'";
exec_sys(`v2dat unpack geosite -o /var/mosdns ${tags_str} ${v2dat_dir}/geosite.dat`);
}
}
}
let action = ARGV[0];
switch (action) {
case "interface_dns":
interface_dns();
break;
case "get_adlist":
get_adlist();
break;
case "update":
if (stat('/var/lock/mosdns_update.lock')) {
print("Another update is already in progress.\n");
exit(1);
}
writefile('/var/lock/mosdns_update.lock', '');
try {
update_geodat();
update_adlist();
v2dat_dump();
print("UPDATE_FINISHED\n");
stdout.flush();
} catch (e) {
print("Update failed: " + e + "\n");
print("UPDATE_EXITED\n");
stdout.flush();
unlink('/var/lock/mosdns_update.lock');
exit(1);
}
unlink('/var/lock/mosdns_update.lock');
break;
case "update_adlist":
update_adlist();
break;
case "v2dat_dump":
v2dat_dump();
break;
default:
exit(0);
}
@@ -0,0 +1,43 @@
{
"luci-app-mosdns": {
"description": "Grant UCI access for luci-app-mosdns",
"read": {
"file": {
"/etc/init.d/mosdns": [ "exec" ],
"/etc/mosdns/config_custom.yaml": [ "read" ],
"/etc/mosdns/rule/*": [ "read" ],
"/usr/bin/mosdns": [ "exec" ],
"/usr/share/mosdns/mosdns.uc": [ "exec" ],
"/var/log/*": [ "read" ],
"/var/mosdns/*": [ "read" ]
},
"ubus": {
"file": [ "read" ],
"service": [ "list" ],
"luci.mosdns": [
"clean_log",
"flush_cache",
"get_version",
"print_log",
"get_update_log",
"start_update"
]
},
"uci": [ "mosdns" ]
},
"write": {
"file": {
"/etc/mosdns/config_custom.yaml": [ "write" ],
"/etc/mosdns/rule/*": [ "write" ],
"/usr/share/mosdns/*": [ "write" ],
"/usr/share/v2ray/*": [ "write" ],
"/var/log/*": [ "write" ],
"/var/mosdns/*": [ "write" ]
},
"ubus": {
"file": [ "write" ]
},
"uci": [ "mosdns" ]
}
}
}
@@ -0,0 +1,154 @@
#!/usr/bin/env ucode
'use strict';
import { popen, writefile, stat, readfile } from 'fs';
import { cursor } from 'uci';
function to_array(val) {
let res =[];
if (type(val) == 'array') {
for (let i = 0; i < length(val); i++) {
if (type(val[i]) == 'string') {
let s = replace(val[i], /^\s+|\s+$/g, '');
if (s != "") push(res, s);
}
}
} else if (type(val) == 'string') {
let parts = split(val, /[ \t\n]+/);
for (let i = 0; i < length(parts); i++) {
if (parts[i] != "") push(res, parts[i]);
}
}
return res;
}
function exec_sys(cmd) {
let p = popen(cmd + " 2>&1", "r");
if (!p) return { code: -1, stdout: "" };
let stdout = p.read("all");
let code = p.close();
if (type(stdout) == 'string') {
stdout = replace(stdout, /^\s+|\s+$/g, '');
}
return { code: code, stdout: stdout || "" };
}
function get_logfile_path_internal() {
let uci_cursor = cursor();
uci_cursor.load('mosdns');
let configfile = uci_cursor.get('mosdns', 'config', 'configfile');
if (configfile === '/var/etc/mosdns.json' || !configfile) {
return uci_cursor.get('mosdns', 'config', 'log_file');
} else {
let content = readfile(configfile);
if (content) {
let m = match(content, /file:\s*([^\r\n]+)/);
if (m && m[1]) {
let log_path = m[1];
log_path = replace(log_path, /^\s+|\s+$/g, '');
log_path = replace(log_path, /^["']|["']$/g, '');
if (log_path != "") {
return log_path;
}
}
}
return '/var/log/mosdns.log';
}
}
const methods = {
flush_cache: {
call: function() {
try {
let uci_cursor = cursor();
uci_cursor.load('mosdns');
let port = uci_cursor.get('mosdns', 'config', 'listen_port_api');
if (!port) return { error: "API listen port not configured." };
let res = exec_sys(`curl -s 127.0.0.1:${port}/plugins/lazy_cache/flush`);
if (res.code === 0) {
return { success: true };
} else {
return { success: false, error: res.stdout };
}
} catch (e) {
return { error: String(e) };
}
}
},
print_log: {
call: function() {
try {
let path = get_logfile_path_internal();
if (path && stat(path)) {
return { log: readfile(path) };
} else {
return { error: 'Log file not accessible or does not exist.' };
}
} catch (e) {
return { error: String(e) };
}
}
},
clean_log: {
call: function() {
try {
let path = get_logfile_path_internal();
if (path) {
writefile(path, '');
return { success: true };
} else {
return { error: 'Log file path could not be determined.' };
}
} catch (e) {
return { error: String(e) };
}
}
},
get_version: {
call: function() {
let res = exec_sys('mosdns version');
if (res.code === 0) {
return { version: res.stdout };
} else {
return { error: res.stdout };
}
}
},
start_update: {
call: function() {
try {
if (stat('/var/lock/mosdns_update.lock')) {
return { success: false, error: 'Another update is already in progress.' };
}
exec_sys('echo "" > /var/log/mosdns_update.log');
exec_sys('/usr/share/mosdns/mosdns.uc update > /var/log/mosdns_update.log 2>&1 &');
return { success: true };
} catch (e) {
return { success: false, error: String(e) };
}
}
},
get_update_log: {
call: function() {
try {
if (stat('/var/log/mosdns_update.log')) {
return { log: readfile('/var/log/mosdns_update.log') };
} else {
return { log: '' };
}
} catch (e) {
return { error: String(e) };
}
}
}
};
return { "luci.mosdns": methods };
@@ -0,0 +1,4 @@
{
"config": "mosdns",
"init": "mosdns"
}