mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-10-30 00:15:13 +08:00
update 2026-09-26 11:07:27
This commit is contained in:
1 parent
7b88b273d0
commit
97ae9f68da
4898 files changed
-1712274
No files matched your search
@@ -1,23 +0,0 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-mosdns
|
||||
PKG_VERSION:=1.7.14
|
||||
PKG_RELEASE:=1
|
||||
|
||||
LUCI_TITLE:=LuCI Support for mosdns
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+mosdns +uclient-fetch +v2ray-geoip +v2ray-geosite +geo2txt +ucode
|
||||
|
||||
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
|
||||
/etc/mosdns/stats.dump
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
-1
@@ -1 +0,0 @@
|
||||
!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))})});
|
||||
-1
@@ -1 +0,0 @@
|
||||
.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)}
|
||||
-1
@@ -1 +0,0 @@
|
||||
!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)})});
|
||||
-1
@@ -1 +0,0 @@
|
||||
!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})});
|
||||
@@ -1 +0,0 @@
|
||||
.CodeMirror{font-family:Arial,monospace;height:500px;color:#000;direction:ltr;border-radius:4px}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor .CodeMirror-line::selection,.cm-fat-cursor .CodeMirror-line>span::selection,.cm-fat-cursor .CodeMirror-line>span>span::selection{background:0 0}.cm-fat-cursor .CodeMirror-line::-moz-selection,.cm-fat-cursor .CodeMirror-line>span::-moz-selection,.cm-fat-cursor .CodeMirror-line>span>span::-moz-selection{background:0 0}.cm-fat-cursor{caret-color:transparent}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:0;position:relative;z-index:0}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none;outline:0}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:Arial,monospace;font-size:15px;margin:0;white-space:pre;word-wrap:normal;line-height:1.25;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizLine truncated
|
||||
@@ -1 +0,0 @@
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.CodeMirror=t()}(this,function(){"use strict";var e=navigator.userAgent,t=navigator.platform,r=/gecko\/\d/i.test(e),n=/MSIE \d/.test(e),i=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),o=/Edge\/(\d+)/.exec(e),l=n||i||o,s=l&&(n?document.documentMode||6:+(o||i)[1]),a=!o&&/WebKit\//.test(e),u=a&&/Qt\/\d+\.\d+/.test(e),c=!o&&/Chrome\//.test(e),h=/Opera\//.test(e),f=/Apple Computer/.test(navigator.vendor),d=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),p=/PhantomJS/.test(e),g=!o&&/AppleWebKit/.test(e)&&/Mobile\/\w+/.test(e),v=/Android/.test(e),m=g||v||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),y=g||/Mac/.test(t),b=/\bCrOS\b/.test(e),w=/win/i.test(t),x=h&&e.match(/Version\/(\d*\.\d*)/);x&&(x=Number(x[1])),x&&x>=15&&(h=!1,a=!0);var C=y&&(u||h&&(null==x||x<12.11)),S=r||l&&s>=9;function L(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}var k,T=function(e,t){var r=e.className,n=L(t).exec(r);if(n){var i=r.slice(n.index+n[0].length);e.className=r.slice(0,n.index)+(i?n[1]+i:"")}};function M(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function N(e,t){return M(e).appendChild(t)}function O(e,t,r,n){var i=document.createElement(e);if(r&&(i.className=r),n&&(i.style.cssText=n),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o<t.length;++o)i.appendChild(t[o]);return i}function A(e,t,r,n){var i=O(e,t,r,n);return i.setAttribute("role","presentation"),i}function D(e,t){if(3==t.nodeType&&(t=t.parentNode),e.contains)return e.contains(t);do{if(11==t.nodeType&&(t=t.host),t==e)return!0}while(t=t.parentNode)}function W(){var e;try{e=document.activeElement}catch(t){e=document.body||null}for(;e&&e.shadowRoot&&e.shadowRoot.activeElement;)e=e.shadowRoot.activeElement;return e}function H(e,t){var r=e.className;L(t).test(r)||(e.className+=(r?" ":"")+t)}function F(e,t){for(var r=e.split(" "),n=0;n<r.length;n++)r[n]&&!L(r[n]).test(t)&&(t+=" "+r[n]);return t}k=document.createRange?function(e,t,r,n){var i=document.createRange();return i.setEnd(n||e,r),i.setStart(e,t),i}:function(e,t,r){var n=document.body.createTextRange();try{n.moveToElementText(e.parentNode)}catch(e){return n}return n.collapse(!0),n.moveEnd("character",r),n.moveStart("character",t),n};var P=function(e){e.select()};function E(e){var t=Array.prototype.slice.call(arguments,1);return function(){return e.apply(null,t)}}function I(e,t,r){for(var n in t||(t={}),e)!e.hasOwnProperty(n)||!1===r&&t.hasOwnProperty(n)||(t[n]=e[n]);return t}function z(e,t,r,n,i){null==t&&-1==(t=e.search(/[^\s\u00a0]/))&&(t=e.length);for(var o=n||0,l=i||0;;){var s=e.indexOf("\t",o);if(s<0||s>=t)return l+(t-o);l+=s-o,l+=r-l%r,o=s+1}}g?P=function(e){e.selectionStart=0,e.selectionEnd=e.value.length}:l&&(P=function(e){try{e.select()}catch(e){}});var R=function(){this.id=null,this.f=null,this.time=0,this.handler=E(this.onTimeout,this)};function B(e,t){for(var r=0;r<e.length;++r)if(e[r]==t)return r;return-1}R.prototype.onTimeout=function(e){e.id=0,e.time<=+new Date?e.f():setTimeout(e.handler,e.time-+new Date)},R.prototype.set=function(e,t){this.f=t;var r=+new Date+e;(!this.id||r<this.time)&&(clearTimeout(this.id),this.id=setTimeout(this.handler,e),this.time=r)};var G=30,U={toString:function(){return"CodeMirror.Pass"}},V={scroll:!1},K={origin:"*mouse"},j={origin:"+move"};function X(e,t,r){for(var n=0,i=0;;){var o=e.indexOf("\t",n);-1==o&&(o=e.length);var l=o-n;if(o==e.length||i+l>=t)return n+Math.min(l,t-i);if(i+=o-n,n=o+1,(i+=r-i%r)>=t)return n}}var Y=[""];function _(e){for(;Y.length<=e;)Y.push($(Y)+" ");return Y[e]}function $(e){return e[e.length-1]}function q(e,t){for(var r=[],n=0;n<e.length;n++)r[n]=t(e[n],n);return r}function Z(){}function Q(e,t){var r;return Object.create?r=Object.create(e):(Z.prototype=e,r=new Z),t&&I(t,r),r}var J=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;function ee(e){return/\w/.test(e)||e>""&&(e.toUpperCase()!=e.toLowerCase()||J.test(e))}function te(e,t){return t?!!(t.source.indexOf("\\w")>-1&&ee(e))||t.test(e):ee(e)}function re(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}var ne=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cdLine truncated
|
||||
@@ -1,2 +0,0 @@
|
||||
/*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jsyaml={})}(this,(function(e){"use strict";function t(e){return null==e}var n={isNothing:t,isObject:function(e){return"object"==typeof e&&null!==e},toArray:function(e){return Array.isArray(e)?e:t(e)?[]:[e]},repeat:function(e,t){var n,i="";for(n=0;n<t;n+=1)i+=e;return i},isNegativeZero:function(e){return 0===e&&Number.NEGATIVE_INFINITY===1/e},extend:function(e,t){var n,i,r,o;if(t)for(n=0,i=(o=Object.keys(t)).length;n<i;n+=1)e[r=o[n]]=t[r];return e}};function i(e,t){var n="",i=e.reason||"(unknown reason)";return e.mark?(e.mark.name&&(n+='in "'+e.mark.name+'" '),n+="("+(e.mark.line+1)+":"+(e.mark.column+1)+")",!t&&e.mark.snippet&&(n+="\n\n"+e.mark.snippet),i+" "+n):i}function r(e,t){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=t,this.message=i(this,!1),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r.prototype.toString=function(e){return this.name+": "+i(this,e)};var o=r;function a(e,t,n,i,r){var o="",a="",l=Math.floor(r/2)-1;return i-t>l&&(t=i-l+(o=" ... ").length),n-i>l&&(n=i+l-(a=" ...").length),{str:o+e.slice(t,n).replace(/\t/g,"→")+a,pos:i-t+o.length}}function l(e,t){return n.repeat(" ",t-e.length)+e}var c=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var i,r=/\r?\n|\r|\0/g,o=[0],c=[],s=-1;i=r.exec(e.buffer);)c.push(i.index),o.push(i.index+i[0].length),e.position<=i.index&&s<0&&(s=o.length-2);s<0&&(s=o.length-1);var u,p,f="",d=Math.min(e.line+t.linesAfter,c.length).toString().length,h=t.maxLength-(t.indent+d+3);for(u=1;u<=t.linesBefore&&!(s-u<0);u++)p=a(e.buffer,o[s-u],c[s-u],e.position-(o[s]-o[s-u]),h),f=n.repeat(" ",t.indent)+l((e.line-u+1).toString(),d)+" | "+p.str+"\n"+f;for(p=a(e.buffer,o[s],c[s],e.position,h),f+=n.repeat(" ",t.indent)+l((e.line+1).toString(),d)+" | "+p.str+"\n",f+=n.repeat("-",t.indent+d+3+p.pos)+"^\n",u=1;u<=t.linesAfter&&!(s+u>=c.length);u++)p=a(e.buffer,o[s+u],c[s+u],e.position-(o[s]-o[s+u]),h),f+=n.repeat(" ",t.indent)+l((e.line+u+1).toString(),d)+" | "+p.str+"\n";return f.replace(/\n$/,"")},s=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],u=["scalar","sequence","mapping"];var p=function(e,t){if(t=t||{},Object.keys(t).forEach((function(t){if(-1===s.indexOf(t))throw new o('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=function(e){var t={};return null!==e&&Object.keys(e).forEach((function(n){e[n].forEach((function(e){t[String(e)]=n}))})),t}(t.styleAliases||null),-1===u.indexOf(this.kind))throw new o('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')};function f(e,t){var n=[];return e[t].forEach((function(e){var t=n.length;n.forEach((function(n,i){n.tag===e.tag&&n.kind===e.kind&&n.multi===e.multi&&(t=i)})),n[t]=e})),n}function d(e){return this.extend(e)}d.prototype.extend=function(e){var t=[],n=[];if(e instanceof p)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new o("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach((function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new o("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new o("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")})),n.forEach((function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.")}));var i=Object.create(d.prototype);return i.implicit=(this.implicit||[]).concat(t),i.explicit=(this.explicit||[]).concat(n),i.compiledImplicit=f(i,"implicit"),i.compiledExplicit=f(i,"explicit"),i.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function i(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.Line truncated
|
||||
-1
@@ -1 +0,0 @@
|
||||
!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")});
|
||||
-1
@@ -1 +0,0 @@
|
||||
.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}
|
||||
@@ -1,511 +0,0 @@
|
||||
'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 = 'error';
|
||||
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.Value, 'log_size', _('Log File Size'), _('Set the maximum size of the log file (in MB).'));
|
||||
o.datatype = 'uinteger';
|
||||
o.default = '1';
|
||||
o.depends('configfile', '/var/etc/mosdns.json');
|
||||
|
||||
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, 'prefetch', _('Cache Prefetching'),
|
||||
_('Proactively refresh hot cache entries in the background before they expire.'));
|
||||
o.rmempty = false;
|
||||
o.default = false;
|
||||
o.depends('cache', '1');
|
||||
|
||||
o = s.taboption('advanced', form.Value, 'prefetch_before_expire', _('Prefetch Before Expire'),
|
||||
_('Prefetch when the remaining TTL is less than this value (in seconds).'));
|
||||
o.datatype = 'and(uinteger,min(1))';
|
||||
o.default = 10;
|
||||
o.depends('prefetch', '1');
|
||||
|
||||
o = s.taboption('advanced', form.Value, 'prefetch_min_hits', _('Prefetch Min Hits'),
|
||||
_('Minimum cache hits required since the last refresh to trigger a prefetch.'));
|
||||
o.datatype = 'and(uinteger,min(1))';
|
||||
o.default = 3;
|
||||
o.depends('prefetch', '1');
|
||||
|
||||
o = s.taboption('advanced', form.Value, 'prefetch_scan_interval', _('Prefetch Scan Interval'),
|
||||
_('Interval for the background thread to scan the cache for prefetching (in seconds).'));
|
||||
o.datatype = 'and(uinteger,min(1))';
|
||||
o.default = 5;
|
||||
o.depends('prefetch', '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.Flag, 'stats_collector', _('Enable Stats Collector'));
|
||||
o.rmempty = false;
|
||||
o.default = o.enabled;
|
||||
o.depends('configfile', '/var/etc/mosdns.json');
|
||||
|
||||
o = s.taboption('api', form.Value, 'stats_capacity', _('Ring Buffer Capacity'),
|
||||
_('Query log ring buffer capacity (FIFO overwrite, default 2000, larger values consume more memory)'));
|
||||
o.datatype = 'and(uinteger,min(1))';
|
||||
o.default = 2000;
|
||||
o.depends('stats_collector', '1');
|
||||
|
||||
o = s.taboption('api', form.Flag, 'stats_dump_file', _('Stats Dump'),
|
||||
_('Save query statistics and logs locally and reload on next startup.'));
|
||||
o.rmempty = false;
|
||||
o.default = false;
|
||||
o.depends('stats_collector', '1');
|
||||
|
||||
o = s.taboption('api', form.Value, 'stats_dump_interval',
|
||||
_('Auto Save Stats Interval'));
|
||||
o.datatype = 'and(uinteger,min(1))';
|
||||
o.default = 600;
|
||||
o.depends('stats_dump_file', '1');
|
||||
|
||||
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 = ' ';
|
||||
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();
|
||||
}
|
||||
});
|
||||
@@ -1,85 +0,0 @@
|
||||
'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
|
||||
});
|
||||
@@ -1,115 +0,0 @@
|
||||
'use strict';
|
||||
'require form';
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require view';
|
||||
|
||||
return view.extend({
|
||||
render() {
|
||||
const m = new form.Map('mosdns', _('Rule Settings'),
|
||||
_('The list of rules only apply to \'Default Config\' profiles.'));
|
||||
|
||||
const s = m.section(form.TypedSection);
|
||||
s.anonymous = true;
|
||||
s.sortable = true;
|
||||
|
||||
const handleSaveError = e => {
|
||||
ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message)));
|
||||
};
|
||||
|
||||
const rules = [
|
||||
{
|
||||
name: 'whitelist',
|
||||
title: _('White Lists'),
|
||||
file: '/etc/mosdns/rule/whitelist.txt',
|
||||
desc: '<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>'
|
||||
},
|
||||
{
|
||||
name: 'blocklist',
|
||||
title: _('Block Lists'),
|
||||
file: '/etc/mosdns/rule/blocklist.txt',
|
||||
desc: '<font color=\'red\'>'
|
||||
+ _('Added domain names will block DNS resolution (one domain per line, supports domain matching rules).')
|
||||
+ '</font>'
|
||||
},
|
||||
{
|
||||
name: 'greylist',
|
||||
title: _('Grey Lists'),
|
||||
file: '/etc/mosdns/rule/greylist.txt',
|
||||
desc: '<font color=\'red\'>'
|
||||
+ _('Added domain names will always use \'Remote DNS\' for resolution (one domain per line, supports domain matching rules).')
|
||||
+ '</font>'
|
||||
},
|
||||
{
|
||||
name: 'ddnslist',
|
||||
title: _('DDNS Lists'),
|
||||
file: '/etc/mosdns/rule/ddnslist.txt',
|
||||
desc: '<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>'
|
||||
},
|
||||
{
|
||||
name: 'hostslist',
|
||||
title: _('Hosts'),
|
||||
file: '/etc/mosdns/rule/hosts.txt',
|
||||
desc: '<font color=\'red\'>'
|
||||
+ _('Custom Hosts rewrite, for example: baidu.com 10.0.0.1 (one rule per line, supports domain matching rules).')
|
||||
+ '</font>'
|
||||
},
|
||||
{
|
||||
name: 'redirectlist',
|
||||
title: _('Redirect'),
|
||||
file: '/etc/mosdns/rule/redirect.txt',
|
||||
desc: '<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>'
|
||||
},
|
||||
{
|
||||
name: 'localptrlist',
|
||||
title: _('Block PTR'),
|
||||
file: '/etc/mosdns/rule/local-ptr.txt',
|
||||
desc: '<font color=\'red\'>'
|
||||
+ _('Added domain names will block PTR requests (one domain per line, supports domain matching rules).')
|
||||
+ '</font>'
|
||||
},
|
||||
{
|
||||
name: 'streamingmedialist',
|
||||
title: _('Streaming Media'),
|
||||
file: '/etc/mosdns/rule/streaming.txt',
|
||||
desc: '<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>'
|
||||
}
|
||||
];
|
||||
|
||||
rules.forEach(rule => {
|
||||
s.tab(rule.name, rule.title);
|
||||
|
||||
const o = s.taboption(rule.name, form.TextValue, '_' + rule.name, null, rule.desc);
|
||||
o.rows = 25;
|
||||
o.cfgvalue = () => fs.trimmed(rule.file).catch(() => '');
|
||||
o.write = function(section_id, formvalue) {
|
||||
return this.cfgvalue(section_id).then(value => {
|
||||
if (value === formvalue) {
|
||||
return;
|
||||
}
|
||||
const content = (formvalue && formvalue.trim()) ? formvalue.trim().replace(/\r\n/g, '\n') + '\n' : '';
|
||||
return fs.write(rule.file, content).catch(handleSaveError);
|
||||
});
|
||||
};
|
||||
o.remove = () => fs.write(rule.file, '').catch(handleSaveError);
|
||||
});
|
||||
|
||||
return m.render();
|
||||
},
|
||||
|
||||
handleSaveApply(ev) {
|
||||
return this.handleSave(ev).then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
},
|
||||
|
||||
handleReset: null
|
||||
});
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,167 +0,0 @@
|
||||
'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 {
|
||||
if (res.error && res.error.match(/Another update is already in progress/)) {
|
||||
statusMsg.textContent = _('Another update is already in progress.');
|
||||
statusMsg.style.color = '#ff9900';
|
||||
callGetUpdateLog().then(logRes => {
|
||||
if (logRes && logRes.log) {
|
||||
logTextarea.value = logRes.log;
|
||||
logTextarea.scrollTop = logTextarea.scrollHeight;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
statusMsg.textContent = res.error || _('Failed to start update.');
|
||||
statusMsg.style.color = '#ed4014';
|
||||
}
|
||||
statusMsg.classList.remove('spinning');
|
||||
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();
|
||||
}
|
||||
});
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,38 +0,0 @@
|
||||
|
||||
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 'error'
|
||||
option log_file '/var/log/mosdns.log'
|
||||
option log_size '1'
|
||||
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'
|
||||
option stats_collector '1'
|
||||
option stats_capacity '2000'
|
||||
option stats_dump_file '0'
|
||||
option stats_dump_interval '600'
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
[ "$ACTION" = "ifup" ] || exit 0
|
||||
[ "$INTERFACE" = "wan" ] && /etc/init.d/mosdns reload
|
||||
@@ -1,893 +0,0 @@
|
||||
#!/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
|
||||
STATS_DUMP_FILE=/etc/mosdns/stats.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 prefetch $1 prefetch 0
|
||||
config_get prefetch_before_expire $1 prefetch_before_expire 10
|
||||
config_get prefetch_min_hits $1 prefetch_min_hits 3
|
||||
config_get prefetch_scan_interval $1 prefetch_scan_interval 5
|
||||
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_size $1 log_size "1"
|
||||
config_get log_level $1 log_level "error"
|
||||
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"
|
||||
config_get stats_collector $1 stats_collector 1
|
||||
config_get stats_capacity $1 stats_capacity 2000
|
||||
config_get stats_dump_file $1 stats_dump_file 0
|
||||
config_get stats_dump_interval $1 stats_dump_interval 600
|
||||
}
|
||||
|
||||
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_add_string "size" "$log_size"
|
||||
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: stats_collector
|
||||
[ "$stats_collector" -eq 1 ] && {
|
||||
json_add_object
|
||||
json_add_string "tag" "stats_collector"
|
||||
json_add_string "type" "stats_api"
|
||||
json_add_object "args"
|
||||
json_add_int "capacity" "$stats_capacity"
|
||||
[ "$stats_dump_file" -eq 1 ] && {
|
||||
json_add_string "dump_file" "$STATS_DUMP_FILE"
|
||||
json_add_int "dump_interval" "$stats_dump_interval"
|
||||
}
|
||||
json_close_object
|
||||
json_close_object
|
||||
}
|
||||
# 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"
|
||||
}
|
||||
[ "$prefetch" -eq 1 ] && {
|
||||
json_add_boolean "prefetch" 1
|
||||
json_add_int "prefetch_before_expire" "$prefetch_before_expire"
|
||||
json_add_int "prefetch_min_hits" "$prefetch_min_hits"
|
||||
json_add_int "prefetch_scan_interval" "$prefetch_scan_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_array "matches"
|
||||
json_add_string "" "!qname \$ddnslist"
|
||||
json_add_string "" "!qname \$blocklist"
|
||||
json_add_string "" "!qname \$adlist"
|
||||
json_close_array
|
||||
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" "black_hole 0.0.0.0 ::"
|
||||
json_close_object
|
||||
json_add_object
|
||||
json_add_string "matches" "qname \$adlist"
|
||||
json_add_string "exec" "black_hole 0.0.0.0 ::"
|
||||
json_close_object
|
||||
json_add_object
|
||||
json_add_string "matches" "has_resp"
|
||||
json_add_string "exec" "ttl 3600"
|
||||
json_close_object
|
||||
json_add_object
|
||||
json_add_string "matches" "has_resp"
|
||||
json_add_string "exec" "accept"
|
||||
json_close_object
|
||||
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"
|
||||
[ "$stats_collector" -eq 1 ] && {
|
||||
json_add_object
|
||||
json_add_string "exec" "\$stats_collector"
|
||||
json_close_object
|
||||
}
|
||||
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
|
||||
[ "$stats_dump_file" -eq 0 ] && rm -f $STATS_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
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
log:
|
||||
level: info
|
||||
file: "/var/log/mosdns.log"
|
||||
|
||||
# API 入口设置
|
||||
api:
|
||||
http: "0.0.0.0:9091"
|
||||
|
||||
include: []
|
||||
|
||||
plugins:
|
||||
# 统计收集器
|
||||
- tag: stats_collector
|
||||
type: stats_api
|
||||
args:
|
||||
capacity: 2000 # 查询日志环缓冲区容量 (FIFO 覆盖)
|
||||
dump_file: "/etc/mosdns/stats.dump" # 数据持久化转存文件路径,不设置则不转存
|
||||
dump_interval: 600 # 周期性转储间隔(秒)
|
||||
|
||||
# 国内域名
|
||||
- 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: $stats_collector # 执行全局统计控制器
|
||||
- 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"
|
||||
@@ -1,2 +0,0 @@
|
||||
# MosDNS Rules
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
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
|
||||
@@ -1,2 +0,0 @@
|
||||
# MosDNS Rules
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# MosDNS Rules
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# MosDNS Rules
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
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
|
||||
@@ -1,2 +0,0 @@
|
||||
# MosDNS Rules
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# MosDNS Rules
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# MosDNS Rules
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/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
|
||||
@@ -1,53 +0,0 @@
|
||||
{
|
||||
"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/statistics": {
|
||||
"title": "Statistics",
|
||||
"order": 25,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "mosdns/statistics"
|
||||
}
|
||||
},
|
||||
"admin/services/mosdns/logs": {
|
||||
"title": "Logs",
|
||||
"order": 30,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "mosdns/logs"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,354 +0,0 @@
|
||||
#!/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('/var/mosdns', 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 dl_res = exec_sys(`wget -4 -q --no-check-certificate -T 90 -O "${ad_tmpdir}/${filename}" "${mirror}${url}"`);
|
||||
if (dl_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(`wget -4 -q --no-check-certificate -T 20 -O "${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(`wget -4 -q --no-check-certificate -T 120 -O "${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(`wget -4 -q --no-check-certificate -T 20 -O "${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(`wget -4 -q --no-check-certificate -T 120 -O "${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(`geo2txt geoip -f ${v2dat_dir}/geoip.dat -e cn -o /var/mosdns`);
|
||||
exec_sys(`geo2txt geosite -f ${v2dat_dir}/geosite.dat -e cn -e apple -e 'geolocation-!cn' -o /var/mosdns`);
|
||||
|
||||
if (adblock === '1' && index(ad_source, 'geosite.dat') !== -1) {
|
||||
exec_sys(`geo2txt geosite -f ${v2dat_dir}/geosite.dat -e category-ads-all -o /var/mosdns`);
|
||||
}
|
||||
|
||||
if (streaming_media === '1') {
|
||||
exec_sys(`geo2txt geosite -f ${v2dat_dir}/geosite.dat -e netflix -e disney -e hulu -o /var/mosdns`);
|
||||
} else {
|
||||
writefile('/var/mosdns/geosite_disney.txt', '');
|
||||
writefile('/var/mosdns/geosite_netflix.txt', '');
|
||||
writefile('/var/mosdns/geosite_hulu.txt', '');
|
||||
}
|
||||
} else {
|
||||
exec_sys(`geo2txt geoip -f ${v2dat_dir}/geoip.dat -e cn -o /var/mosdns`);
|
||||
exec_sys(`geo2txt geosite -f ${v2dat_dir}/geosite.dat -e cn -e 'geolocation-!cn' -o /var/mosdns`);
|
||||
|
||||
let geoip_tags = to_array(uci_cursor.get('mosdns', 'config', 'geoip_tags'));
|
||||
if (length(geoip_tags) > 0) {
|
||||
let tags_str = "-e '" + join("' -e '", geoip_tags) + "'";
|
||||
exec_sys(`geo2txt geoip -f ${v2dat_dir}/geoip.dat ${tags_str} -o /var/mosdns`);
|
||||
}
|
||||
|
||||
let geosite_tags = to_array(uci_cursor.get('mosdns', 'config', 'geosite_tags'));
|
||||
if (length(geosite_tags) > 0) {
|
||||
let tags_str = "-e '" + join("' -e '", geosite_tags) + "'";
|
||||
exec_sys(`geo2txt geosite -f ${v2dat_dir}/geosite.dat ${tags_str} -o /var/mosdns`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
{
|
||||
"luci-app-mosdns": {
|
||||
"description": "Grant UCI access for luci-app-mosdns",
|
||||
"read": {
|
||||
"file": {
|
||||
"/etc/hosts": [ "read" ],
|
||||
"/etc/init.d/mosdns": [ "exec" ],
|
||||
"/etc/mosdns/config_custom.yaml": [ "read" ],
|
||||
"/etc/mosdns/rule/*": [ "read" ],
|
||||
"/tmp/dhcp.leases": [ "read" ],
|
||||
"/tmp/hosts/*": [ "read" ],
|
||||
"/tmp/odhcpd.leases": [ "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",
|
||||
"clear_query_logs",
|
||||
"flush_cache",
|
||||
"get_history",
|
||||
"get_leases",
|
||||
"get_logs",
|
||||
"get_stats",
|
||||
"get_top",
|
||||
"get_update_log",
|
||||
"get_version",
|
||||
"print_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" ],
|
||||
"luci.mosdns": [ "clear_query_logs" ]
|
||||
},
|
||||
"uci": [ "mosdns" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
#!/usr/bin/env ucode
|
||||
|
||||
'use strict';
|
||||
|
||||
import { popen, stat, readfile, open } 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';
|
||||
}
|
||||
}
|
||||
|
||||
function parse_json_safe(str) {
|
||||
if (!str || str == "")
|
||||
return null;
|
||||
|
||||
try {
|
||||
return json(str);
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function call_mosdns_api(endpoint, method) {
|
||||
try {
|
||||
let uci_cursor = cursor();
|
||||
uci_cursor.load('mosdns');
|
||||
let port = uci_cursor.get('mosdns', 'config', 'listen_port_api') || '9091';
|
||||
let http_method = method ? method : 'GET';
|
||||
let post_flag = (http_method === 'POST') ? '--post-data=""' : '';
|
||||
let cmd = `wget -q -O - ${post_flag} "http://127.0.0.1:${port}/plugins/stats_collector${endpoint}"`;
|
||||
let res = exec_sys(cmd);
|
||||
if (res.code === 0 && res.stdout != "") {
|
||||
let json_val = parse_json_safe(res.stdout);
|
||||
if (json_val) return json_val;
|
||||
}
|
||||
return { error: "MosDNS API unreachable" };
|
||||
} catch (e) {
|
||||
return { error: String(e) };
|
||||
}
|
||||
}
|
||||
|
||||
function get_client_leases() {
|
||||
let leases = {};
|
||||
|
||||
let add_lease = function(ip, name) {
|
||||
if (!ip || !name) return;
|
||||
ip = replace(ip, /^\s+|\s+$/g, '');
|
||||
name = replace(name, /^\s+|\s+$/g, '');
|
||||
if (ip == "" || name == "" || name == "*" || name == "unknown") return;
|
||||
|
||||
ip = replace(ip, /\/[0-9]+$/, '');
|
||||
ip = replace(ip, /^::ffff:/i, '');
|
||||
|
||||
leases[ip] = name;
|
||||
try {
|
||||
if (type(lc) == 'function') {
|
||||
leases[lc(ip)] = name;
|
||||
}
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
let parse_hosts_file = function(filepath) {
|
||||
try {
|
||||
if (stat(filepath)) {
|
||||
let content = readfile(filepath);
|
||||
if (content) {
|
||||
let lines = split(content, '\n');
|
||||
for (let i = 0; i < length(lines); i++) {
|
||||
let line = replace(lines[i], /^\s+|\s+$/g, '');
|
||||
if (line == "" || match(line, /^#/)) continue;
|
||||
let parts = split(line, /[ \t]+/);
|
||||
if (length(parts) >= 2) {
|
||||
add_lease(parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
try {
|
||||
if (stat('/tmp/dhcp.leases')) {
|
||||
let content = readfile('/tmp/dhcp.leases');
|
||||
if (content) {
|
||||
let lines = split(content, '\n');
|
||||
for (let i = 0; i < length(lines); i++) {
|
||||
let line = replace(lines[i], /^\s+|\s+$/g, '');
|
||||
if (line == "" || match(line, /^#/)) continue;
|
||||
let parts = split(line, /[ \t]+/);
|
||||
if (length(parts) >= 4) {
|
||||
add_lease(parts[2], parts[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
parse_hosts_file('/tmp/hosts/odhcpd');
|
||||
|
||||
parse_hosts_file('/tmp/hosts/dhcp');
|
||||
|
||||
try {
|
||||
if (stat('/tmp/odhcpd.leases')) {
|
||||
let content = readfile('/tmp/odhcpd.leases');
|
||||
if (content) {
|
||||
let lines = split(content, '\n');
|
||||
for (let i = 0; i < length(lines); i++) {
|
||||
let line = replace(lines[i], /^\s+|\s+$/g, '');
|
||||
if (line == "" || match(line, /^#/)) continue;
|
||||
let parts = split(line, /[ \t]+/);
|
||||
if (length(parts) >= 6) {
|
||||
let host = parts[3];
|
||||
for (let j = 5; j < length(parts); j++) {
|
||||
add_lease(parts[j], host);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
parse_hosts_file('/etc/hosts');
|
||||
|
||||
return leases;
|
||||
}
|
||||
|
||||
const methods = {
|
||||
get_stats: {
|
||||
call: function() {
|
||||
return call_mosdns_api('/api/v1/stats', 'GET');
|
||||
}
|
||||
},
|
||||
|
||||
get_history: {
|
||||
args: { points: 24 },
|
||||
call: function(request) {
|
||||
let points = request?.args?.points || 24;
|
||||
return call_mosdns_api(`/api/v1/history?points=${points}`, 'GET');
|
||||
}
|
||||
},
|
||||
|
||||
get_top: {
|
||||
args: { limit: 10 },
|
||||
call: function(request) {
|
||||
let limit = request?.args?.limit || 10;
|
||||
let res = call_mosdns_api(`/api/v1/top?limit=${limit}`, 'GET');
|
||||
if (type(res) == 'object' && !res.error) {
|
||||
res.leases = get_client_leases();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
},
|
||||
|
||||
get_leases: {
|
||||
call: function() {
|
||||
return { leases: get_client_leases() };
|
||||
}
|
||||
},
|
||||
|
||||
get_logs: {
|
||||
args: { limit: 50, offset: 0, search: '', filter: 'all' },
|
||||
call: function(request) {
|
||||
let limit = request?.args?.limit || 50;
|
||||
let offset = request?.args?.offset || 0;
|
||||
let search = request?.args?.search || '';
|
||||
let filter = request?.args?.filter || 'all';
|
||||
return call_mosdns_api(`/api/v1/logs?limit=${limit}&offset=${offset}&search=${search}&filter=${filter}`, 'GET');
|
||||
}
|
||||
},
|
||||
|
||||
clear_query_logs: {
|
||||
call: function() {
|
||||
return call_mosdns_api('/api/v1/logs/clear', 'POST');
|
||||
}
|
||||
},
|
||||
|
||||
flush_cache: {
|
||||
call: function() {
|
||||
try {
|
||||
let uci_cursor = cursor();
|
||||
uci_cursor.load('mosdns');
|
||||
let port = uci_cursor.get('mosdns', 'config', 'listen_port_api') || '9091';
|
||||
if (!port) return { error: "API listen port not configured." };
|
||||
|
||||
let res = exec_sys(`wget -q -O - "http://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) {
|
||||
let f = open(path, 'w');
|
||||
if (f) {
|
||||
f.close();
|
||||
return { success: true };
|
||||
}
|
||||
return { error: 'Failed to open log file for writing.' };
|
||||
} 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 };
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"config": "mosdns",
|
||||
"init": "mosdns"
|
||||
}
|
||||
Reference in new issue
Block a user