diff --git a/luci-app-mosdns/Makefile b/luci-app-mosdns/Makefile
index 13e9982..f58c2e0 100644
--- a/luci-app-mosdns/Makefile
+++ b/luci-app-mosdns/Makefile
@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-mosdns
-PKG_VERSION:=1.5.20
+PKG_VERSION:=1.5.21
PKG_RELEASE:=1
LUCI_TITLE:=LuCI Support for mosdns
diff --git a/luci-app-mosdns/luasrc/model/cbi/mosdns/basic.lua b/luci-app-mosdns/luasrc/model/cbi/mosdns/basic.lua
index cff0c60..5d6d76d 100644
--- a/luci-app-mosdns/luasrc/model/cbi/mosdns/basic.lua
+++ b/luci-app-mosdns/luasrc/model/cbi/mosdns/basic.lua
@@ -47,7 +47,7 @@ o:depends("configfile", "/var/etc/mosdns.json")
o = s:taboption("basic", Flag, "redirect", translate("DNS Forward"), translate("Forward Dnsmasq Domain Name resolution requests to MosDNS"))
o.default = true
-o = s:taboption("basic", Flag, "prefer_ipv4", translate("Remote DNS prefer IPv4"), translate("IPv4 is preferred for remote DNS resolution of dual-stack addresses, and is not affected when the destination is IPv6 only"))
+o = s:taboption("basic", Flag, "prefer_ipv4", translate("Remote DNS prefer IPv4"), translate("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 = true
@@ -85,6 +85,22 @@ o:value("tls://208.67.222.222", translate("Cisco Public DNS (208.67.222.222)"))
o:value("tls://208.67.220.220", translate("Cisco Public DNS (208.67.220.220)"))
o:depends("configfile", "/var/etc/mosdns.json")
+o = s:taboption("basic", Flag, "custom_stream_media_dns", translate("Custom Stream Media DNS"), translate("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", DynamicList, "stream_media_dns", translate("Streaming Media DNS server"))
+o:value("tls://1.1.1.1", translate("CloudFlare Public DNS (1.1.1.1)"))
+o:value("tls://1.0.0.1", translate("CloudFlare Public DNS (1.0.0.1)"))
+o:value("tls://8.8.8.8", translate("Google Public DNS (8.8.8.8)"))
+o:value("tls://8.8.4.4", translate("Google Public DNS (8.8.4.4)"))
+o:value("tls://9.9.9.9", translate("Quad9 Public DNS (9.9.9.9)"))
+o:value("tls://149.112.112.112", translate("Quad9 Public DNS (149.112.112.112)"))
+o:value("tls://208.67.222.222", translate("Cisco Public DNS (208.67.222.222)"))
+o:value("tls://208.67.220.220", translate("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", ListValue, "bootstrap_dns", translate("Bootstrap DNS servers"), translate("Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams"))
o:value("119.29.29.29", translate("Tencent Public DNS (119.29.29.29)"))
o:value("119.28.28.28", translate("Tencent Public DNS (119.28.28.28)"))
@@ -125,7 +141,7 @@ o.rmempty = false
o.default = false
o:depends("configfile", "/var/etc/mosdns.json")
-o = s:taboption("advanced", Value, "remote_ecs_ip", translate("IP Address"), translate("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 DNS requests") .. '
' .. translate("This feature is typically used when using a self-built DNS server as an Remote DNS upstream (requires support from the upstream server)"))
+o = s:taboption("advanced", Value, "remote_ecs_ip", translate("IP Address"), translate("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") .. '
' .. translate("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")
diff --git a/luci-app-mosdns/luasrc/model/cbi/mosdns/rule_list.lua b/luci-app-mosdns/luasrc/model/cbi/mosdns/rule_list.lua
index 1d6554e..d41957b 100644
--- a/luci-app-mosdns/luasrc/model/cbi/mosdns/rule_list.lua
+++ b/luci-app-mosdns/luasrc/model/cbi/mosdns/rule_list.lua
@@ -7,6 +7,7 @@ local hosts_list_file = "/etc/mosdns/rule/hosts.txt"
local redirect_list_file = "/etc/mosdns/rule/redirect.txt"
local local_ptr_file = "/etc/mosdns/rule/local-ptr.txt"
local ddns_list_file = "/etc/mosdns/rule/ddnslist.txt"
+local streaming_media_list_file = "/etc/mosdns/rule/streaming.txt"
m = Map("mosdns")
@@ -20,6 +21,7 @@ s:tab("ddns_list", translate("DDNS Lists"))
s:tab("hosts_list", translate("Hosts"))
s:tab("redirect_list", translate("Redirect"))
s:tab("local_ptr_list", translate("Block PTR"))
+s:tab("streaming_media_list", translate("Streaming Media"))
o = s:taboption("white_list", TextValue, "whitelist", "", "" .. translate("These domain names allow DNS resolution with the highest priority. Please input the domain names of websites, every line can input only one website domain. For example: hm.baidu.com.") .. "" .. "" .. translate("
The list of rules only apply to 'Default Config' profiles.") .. "")
o.rows = 15
@@ -91,6 +93,16 @@ o.validate = function(self, value)
return value
end
+o = s:taboption("streaming_media_list", TextValue, "streaming_media", "", "" .. translate("These domains are always resolved using Streaming Media DNS. Please input the domain names of websites, every line can input only one website domain. For example: netflix.com.") .. "" .. "" .. translate("
The list of rules only apply to 'Default Config' profiles.") .. "")
+o.rows = 15
+o.wrap = "off"
+o.cfgvalue = function(self, section) return nixio.fs.readfile(streaming_media_list_file) or "" end
+o.write = function(self, section, value) nixio.fs.writefile(streaming_media_list_file, value:gsub("\r\n", "\n")) end
+o.remove = function(self, section, value) nixio.fs.writefile(streaming_media_list_file, "") end
+o.validate = function(self, value)
+ return value
+end
+
local apply = luci.http.formvalue("cbi.apply")
if apply then
luci.sys.exec("/etc/init.d/mosdns reload")
diff --git a/luci-app-mosdns/po/zh-cn/mosdns.po b/luci-app-mosdns/po/zh-cn/mosdns.po
index 0785980..15989d5 100644
--- a/luci-app-mosdns/po/zh-cn/mosdns.po
+++ b/luci-app-mosdns/po/zh-cn/mosdns.po
@@ -163,8 +163,8 @@ msgstr "日志文件"
msgid "Remote DNS prefer IPv4"
msgstr "远程 DNS 首选 IPv4"
-msgid "IPv4 is preferred for remote DNS resolution of dual-stack addresses, and is not affected when the destination is IPv6 only"
-msgstr "远程 DNS 解析双栈地址时首选 IPv4,目标仅 IPv6 时不受影响"
+msgid "IPv4 is preferred for Remote / Streaming Media DNS resolution of dual-stack addresses, and is not affected when the destination is IPv6 only"
+msgstr "远程 / 流媒体 DNS 解析双栈地址时首选 IPv4,目标仅 IPv6 时不受影响"
msgid "Custom China DNS"
msgstr "自定义国内 DNS"
@@ -280,11 +280,11 @@ msgstr "启用 EDNS 客户端子网"
msgid "IP Address"
msgstr "IP 地址"
-msgid "Please provide the IP address you use when accessing foreign websites. This IP subnet (0/24) will be used as the ECS address for Remote DNS requests"
-msgstr "请提供您在访问国外网站时使用的 IP 地址,这个 IP 子网(0/24)将用作远程 DNS 请求的 ECS 地址"
+msgid "Please provide the IP address you use when accessing foreign websites. This IP subnet (0/24) will be used as the ECS address for Remote / Streaming Media DNS requests"
+msgstr "请提供您在访问国外网站时使用的 IP 地址,这个 IP 子网(0/24)将用作 远程 / 流媒体 DNS 请求的 ECS 地址"
-msgid "This feature is typically used when using a self-built DNS server as an Remote DNS upstream (requires support from the upstream server)"
-msgstr "此功能通常在使用自建 DNS 服务器作为 远程 DNS 上游时使用(需要上游服务器的支持)"
+msgid "This feature is typically used when using a self-built DNS server as an Remote / Streaming Media DNS upstream (requires support from the upstream server)"
+msgstr "此功能通常在使用自建 DNS 服务器作为 远程 / 流媒体 DNS 上游时使用(需要上游服务器的支持)"
msgid "Prevent DNS Leaks"
msgstr "防止 DNS 泄漏"
@@ -396,3 +396,18 @@ msgstr "输入需要导出的 GeoIP.dat 类别条目,允许添加多个标签"
msgid "Export directory: /var/mosdns"
msgstr "导出目录:/var/mosdns"
+
+msgid "Custom Stream Media DNS"
+msgstr "自定义流媒体 DNS"
+
+msgid "Streaming Media DNS server"
+msgstr "流媒体 DNS 服务器"
+
+msgid "Netflix, Disney+, Hulu and streaming media rules list will use this DNS"
+msgstr "自定义 Netflix、Disney+、Hulu 以及 “流媒体” 规则列表的 DNS 服务器"
+
+msgid "Streaming Media"
+msgstr "流媒体"
+
+msgid "These domains are always resolved using Streaming Media DNS. Please input the domain names of websites, every line can input only one website domain. For example: netflix.com."
+msgstr "启用 “自定义流媒体 DNS” 时,加入的域名始终使用 “流媒体 DNS 服务器” 进行解析(每个域名一行,支持域名匹配规则)"
diff --git a/luci-app-mosdns/root/etc/config/mosdns b/luci-app-mosdns/root/etc/config/mosdns
index 603ab76..a15981f 100644
--- a/luci-app-mosdns/root/etc/config/mosdns
+++ b/luci-app-mosdns/root/etc/config/mosdns
@@ -24,6 +24,7 @@ config mosdns 'config'
option dns_leak '0'
option cloudflare '0'
option listen_port_api '9091'
+ option custom_stream_media_dns '0'
option bootstrap_dns '119.29.29.29'
list remote_dns 'tls://8.8.8.8'
list remote_dns 'tls://1.1.1.1'
diff --git a/luci-app-mosdns/root/etc/init.d/mosdns b/luci-app-mosdns/root/etc/init.d/mosdns
index 8670fb1..0843e7a 100755
--- a/luci-app-mosdns/root/etc/init.d/mosdns
+++ b/luci-app-mosdns/root/etc/init.d/mosdns
@@ -51,6 +51,8 @@ get_config() {
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 9091
config_get concurrent $1 concurrent 1
@@ -205,6 +207,19 @@ generate_config() {
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"
@@ -315,6 +330,51 @@ generate_config() {
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"
@@ -491,6 +551,17 @@ generate_config() {
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"
@@ -550,6 +621,12 @@ generate_config() {
json_add_string "exec" "jump has_resp_sequence"
json_close_object
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
diff --git a/luci-app-mosdns/root/etc/mosdns/rule/streaming.txt b/luci-app-mosdns/root/etc/mosdns/rule/streaming.txt
new file mode 100644
index 0000000..e69de29
diff --git a/luci-app-mosdns/root/usr/share/mosdns/mosdns.sh b/luci-app-mosdns/root/usr/share/mosdns/mosdns.sh
index a8fb606..91817a6 100755
--- a/luci-app-mosdns/root/usr/share/mosdns/mosdns.sh
+++ b/luci-app-mosdns/root/usr/share/mosdns/mosdns.sh
@@ -143,6 +143,7 @@ v2dat_dump() {
adblock=$(uci -q get mosdns.config.adblock)
ad_source=$(uci -q get mosdns.config.ad_source)
configfile=$(uci -q get mosdns.config.configfile)
+ streaming_media=$(uci -q get mosdns.config.custom_stream_media_dns)
mkdir -p /var/mosdns
rm -f /var/mosdns/geo*.txt
if [ "$configfile" = "/var/etc/mosdns.json" ]; then
@@ -150,6 +151,7 @@ v2dat_dump() {
v2dat unpack geoip -o /var/mosdns -f cn $v2dat_dir/geoip.dat
v2dat unpack geosite -o /var/mosdns -f cn -f apple -f 'geolocation-!cn' $v2dat_dir/geosite.dat
[ "$adblock" -eq 1 ] && [ $(echo $ad_source | grep -c geosite.dat) -ge '1' ] && v2dat unpack geosite -o /var/mosdns -f category-ads-all $v2dat_dir/geosite.dat
+ [ "$streaming_media" -eq 1 ] && v2dat unpack geosite -o /var/mosdns -f netflix -f disney -f hulu $v2dat_dir/geosite.dat
else
# custom config
v2dat unpack geoip -o /var/mosdns -f cn $v2dat_dir/geoip.dat