diff --git a/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm b/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm
index 3dad68b73..6bcad56da 100644
--- a/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm
+++ b/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm
@@ -1101,7 +1101,7 @@ local api = require "luci.passwall.api"
}
}
- opt.set(dom_prefix + 'encryption', queryParam.encryption);
+ opt.set(dom_prefix + 'encryption', queryParam.encryption || "none");
if (queryParam.security) {
if (queryParam.security == "tls") {
opt.set(dom_prefix + 'tls', true);
diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh
index e9036dc8c..c022dc46f 100755
--- a/luci-app-passwall/root/usr/share/passwall/app.sh
+++ b/luci-app-passwall/root/usr/share/passwall/app.sh
@@ -1548,20 +1548,43 @@ start_dns() {
[ "$(expr $dnsmasq_version \>= 2.87)" == 0 ] && echolog "Dnsmasq版本低于2.87,有可能无法正常使用!!!"
}
- GLOBAL_DNSMASQ_PORT=$(get_new_port 11400)
- local GLOBAL_DNSMASQ_CONF=${GLOBAL_ACL_PATH}/dnsmasq.conf
- local GLOBAL_DNSMASQ_CONF_PATH=${GLOBAL_ACL_PATH}/dnsmasq.d
- source $APP_PATH/helper_dnsmasq.sh copy_instance listen_port=$GLOBAL_DNSMASQ_PORT dnsmasq_conf="${GLOBAL_DNSMASQ_CONF}" dnsmasq_conf_path="${GLOBAL_DNSMASQ_CONF_PATH}"
- lua $APP_PATH/helper_dnsmasq_add.lua -FLAG "default" -TMP_DNSMASQ_PATH ${GLOBAL_DNSMASQ_CONF_PATH} \
- -DNSMASQ_CONF_FILE ${GLOBAL_DNSMASQ_CONF} -DEFAULT_DNS ${DEFAULT_DNS} -LOCAL_DNS ${LOCAL_DNS} \
- -TUN_DNS ${TUN_DNS} -REMOTE_FAKEDNS ${fakedns:-0} -USE_DEFAULT_DNS "${USE_DEFAULT_DNS:-direct}" -CHINADNS_DNS ${china_ng_listen:-0} \
- -USE_DIRECT_LIST "${USE_DIRECT_LIST}" -USE_PROXY_LIST "${USE_PROXY_LIST}" -USE_BLOCK_LIST "${USE_BLOCK_LIST}" -USE_GFW_LIST "${USE_GFW_LIST}" -CHN_LIST "${CHN_LIST}" \
- -TCP_NODE ${TCP_NODE} -DEFAULT_PROXY_MODE ${TCP_PROXY_MODE} -NO_PROXY_IPV6 ${DNSMASQ_FILTER_PROXY_IPV6:-0} -NFTFLAG ${nftflag:-0} \
- -NO_LOGIC_LOG ${NO_LOGIC_LOG:-0}
- awk '!seen[$0]++' ${GLOBAL_DNSMASQ_CONF} > ${TMP_PATH}/dnsmasq_default.tmp && mv ${TMP_PATH}/dnsmasq_default.tmp ${GLOBAL_DNSMASQ_CONF}
- ln_run "$(first_type dnsmasq)" "dnsmasq_default" "/dev/null" -C ${GLOBAL_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/dnsmasq.pid
- echo "${GLOBAL_DNSMASQ_PORT}" > ${GLOBAL_ACL_PATH}/var_redirect_dns_port
- DNS_REDIRECT_PORT=${GLOBAL_DNSMASQ_PORT}
+ local RUN_NEW_DNSMASQ=1
+ if [ "${RUN_NEW_DNSMASQ}" == "0" ]; then
+ #The old logic will be removed in the future.
+ #Run a copy dnsmasq instance, DNS hijack that don't need a proxy devices.
+ [ "1" = "0" ] && {
+ DIRECT_DNSMASQ_PORT=$(get_new_port 11400)
+ DIRECT_DNSMASQ_CONF=${GLOBAL_ACL_PATH}/direct_dnsmasq.conf
+ lua $APP_PATH/helper_dnsmasq.lua copy_instance -LISTEN_PORT ${DIRECT_DNSMASQ_PORT} -DNSMASQ_CONF ${DIRECT_DNSMASQ_CONF}
+ ln_run "$(first_type dnsmasq)" "dnsmasq_direct" "/dev/null" -C ${DIRECT_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/direct_dnsmasq.pid
+ echo "${DIRECT_DNSMASQ_PORT}" > ${GLOBAL_ACL_PATH}/direct_dnsmasq_port
+ }
+
+ #Rewrite the default DNS service configuration
+ #Modify the default dnsmasq service
+ lua $APP_PATH/helper_dnsmasq.lua stretch
+ lua $APP_PATH/helper_dnsmasq.lua add_rule -FLAG "default" -TMP_DNSMASQ_PATH ${GLOBAL_DNSMASQ_CONF_PATH} -DNSMASQ_CONF_FILE ${GLOBAL_DNSMASQ_CONF} \
+ -DEFAULT_DNS ${DEFAULT_DNS} -LOCAL_DNS ${LOCAL_DNS} -TUN_DNS ${TUN_DNS} \
+ -REMOTE_FAKEDNS ${fakedns:-0} -USE_DEFAULT_DNS "${USE_DEFAULT_DNS:-direct}" -CHINADNS_DNS ${china_ng_listen:-0} \
+ -USE_DIRECT_LIST "${USE_DIRECT_LIST}" -USE_PROXY_LIST "${USE_PROXY_LIST}" -USE_BLOCK_LIST "${USE_BLOCK_LIST}" -USE_GFW_LIST "${USE_GFW_LIST}" -CHN_LIST "${CHN_LIST}" \
+ -TCP_NODE ${TCP_NODE} -DEFAULT_PROXY_MODE ${TCP_PROXY_MODE} -NO_PROXY_IPV6 ${DNSMASQ_FILTER_PROXY_IPV6:-0} -NFTFLAG ${nftflag:-0} \
+ -NO_LOGIC_LOG ${NO_LOGIC_LOG:-0}
+ /etc/init.d/dnsmasq restart >/dev/null 2>&1
+ else
+ #Run a copy dnsmasq instance, DNS hijack for that need proxy devices.
+ GLOBAL_DNSMASQ_PORT=$(get_new_port 11400)
+ GLOBAL_DNSMASQ_CONF=${GLOBAL_ACL_PATH}/dnsmasq.conf
+ GLOBAL_DNSMASQ_CONF_PATH=${GLOBAL_ACL_PATH}/dnsmasq.d
+ lua $APP_PATH/helper_dnsmasq.lua add_rule -FLAG "default" -TMP_DNSMASQ_PATH ${GLOBAL_DNSMASQ_CONF_PATH} -DNSMASQ_CONF_FILE ${GLOBAL_DNSMASQ_CONF} \
+ -LISTEN_PORT ${GLOBAL_DNSMASQ_PORT} -DEFAULT_DNS ${DEFAULT_DNS} -LOCAL_DNS ${LOCAL_DNS} -TUN_DNS ${TUN_DNS} \
+ -REMOTE_FAKEDNS ${fakedns:-0} -USE_DEFAULT_DNS "${USE_DEFAULT_DNS:-direct}" -CHINADNS_DNS ${china_ng_listen:-0} \
+ -USE_DIRECT_LIST "${USE_DIRECT_LIST}" -USE_PROXY_LIST "${USE_PROXY_LIST}" -USE_BLOCK_LIST "${USE_BLOCK_LIST}" -USE_GFW_LIST "${USE_GFW_LIST}" -CHN_LIST "${CHN_LIST}" \
+ -TCP_NODE ${TCP_NODE} -DEFAULT_PROXY_MODE ${TCP_PROXY_MODE} -NO_PROXY_IPV6 ${DNSMASQ_FILTER_PROXY_IPV6:-0} -NFTFLAG ${nftflag:-0} \
+ -NO_LOGIC_LOG ${NO_LOGIC_LOG:-0}
+ ln_run "$(first_type dnsmasq)" "dnsmasq_default" "/dev/null" -C ${GLOBAL_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/dnsmasq.pid
+ echo "${GLOBAL_DNSMASQ_PORT}" > ${GLOBAL_ACL_PATH}/var_redirect_dns_port
+ DNS_REDIRECT_PORT=${GLOBAL_DNSMASQ_PORT}
+ fi
}
add_ip2route() {
@@ -1752,14 +1775,12 @@ acl_app() {
dnsmasq_port=$(get_new_port $(expr $dnsmasq_port + 1))
local dnsmasq_conf=${acl_path}/dnsmasq.conf
local dnsmasq_conf_path=${acl_path}/dnsmasq.d
- source $APP_PATH/helper_dnsmasq.sh copy_instance listen_port=$dnsmasq_port dnsmasq_conf="${dnsmasq_conf}" dnsmasq_conf_path="${dnsmasq_conf_path}"
- lua $APP_PATH/helper_dnsmasq_add.lua -FLAG ${sid} -TMP_DNSMASQ_PATH ${dnsmasq_conf_path} \
- -DNSMASQ_CONF_FILE ${dnsmasq_conf} -DEFAULT_DNS $DEFAULT_DNS -LOCAL_DNS $LOCAL_DNS \
+ lua $APP_PATH/helper_dnsmasq.lua add_rule -FLAG ${sid} -TMP_DNSMASQ_PATH ${dnsmasq_conf_path} -DNSMASQ_CONF_FILE ${dnsmasq_conf} \
+ -LISTEN_PORT ${dnsmasq_port} -DEFAULT_DNS $DEFAULT_DNS -LOCAL_DNS $LOCAL_DNS \
-USE_DIRECT_LIST "${use_direct_list}" -USE_PROXY_LIST "${use_proxy_list}" -USE_BLOCK_LIST "${use_block_list}" -USE_GFW_LIST "${use_gfw_list}" -CHN_LIST "${chn_list}" \
-TUN_DNS "127.0.0.1#${_dns_port}" -REMOTE_FAKEDNS 0 -USE_DEFAULT_DNS "${use_default_dns:-direct}" -CHINADNS_DNS ${_china_ng_listen:-0} \
-TCP_NODE $tcp_node -DEFAULT_PROXY_MODE ${tcp_proxy_mode} -NO_PROXY_IPV6 ${dnsmasq_filter_proxy_ipv6:-0} -NFTFLAG ${nftflag:-0} \
-NO_LOGIC_LOG 1
- awk '!seen[$0]++' ${dnsmasq_conf} > ${TMP_PATH}/dnsmasq_${sid}.tmp && mv ${TMP_PATH}/dnsmasq_${sid}.tmp ${dnsmasq_conf}
ln_run "$(first_type dnsmasq)" "dnsmasq_${sid}" "/dev/null" -C ${dnsmasq_conf} -x ${acl_path}/dnsmasq.pid
echo "${dnsmasq_port}" > ${acl_path}/var_redirect_dns_port
eval node_${tcp_node}_$(echo -n "${tcp_proxy_mode}${remote_dns}" | md5sum | cut -d " " -f1)=${dnsmasq_port}
@@ -1930,6 +1951,9 @@ start() {
start_dns
}
[ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start
+ [ ! -s "${GLOBAL_ACL_PATH}/var_redirect_dns_port" ] && {
+ lua $APP_PATH/helper_dnsmasq.lua logic_restart -LOG 1
+ }
start_crontab
echolog "运行完成!\n"
}
@@ -1946,6 +1970,9 @@ stop() {
unset XRAY_LOCATION_ASSET
stop_crontab
source $APP_PATH/helper_smartdns.sh del
+ rm -rf $GLOBAL_DNSMASQ_CONF
+ rm -rf $GLOBAL_DNSMASQ_CONF_PATH
+ [ ! -s "${GLOBAL_ACL_PATH}/var_redirect_dns_port" ] && lua $APP_PATH/helper_dnsmasq.lua restart -LOG 0
[ -s "$TMP_PATH/bridge_nf_ipt" ] && sysctl -w net.bridge.bridge-nf-call-iptables=$(cat $TMP_PATH/bridge_nf_ipt) >/dev/null 2>&1
[ -s "$TMP_PATH/bridge_nf_ip6t" ] && sysctl -w net.bridge.bridge-nf-call-ip6tables=$(cat $TMP_PATH/bridge_nf_ip6t) >/dev/null 2>&1
rm -rf ${TMP_PATH}
@@ -2021,6 +2048,21 @@ DEFAULT_DNS=$(uci show dhcp.@dnsmasq[0] | grep "\.server=" | awk -F '=' '{print
LOCAL_DNS="${DEFAULT_DNS:-119.29.29.29,223.5.5.5}"
IPT_APPEND_DNS=${LOCAL_DNS}
+DNSMASQ_CONF_DIR=/tmp/dnsmasq.d
+TMP_DNSMASQ_PATH=${DNSMASQ_CONF_DIR}/${CONFIG}
+DEFAULT_DNSMASQ_CFGID="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')"
+if [ -f "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID" ]; then
+ DNSMASQ_CONF_DIR="$(awk -F '=' '/^conf-dir=/ {print $2}' "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID")"
+ if [ -n "$DNSMASQ_CONF_DIR" ]; then
+ DNSMASQ_CONF_DIR=${DNSMASQ_CONF_DIR%*/}
+ TMP_DNSMASQ_PATH=${DNSMASQ_CONF_DIR}/${CONFIG}
+ else
+ DNSMASQ_CONF_DIR="/tmp/dnsmasq.d"
+ fi
+fi
+GLOBAL_DNSMASQ_CONF=${DNSMASQ_CONF_DIR}/dnsmasq-${CONFIG}.conf
+GLOBAL_DNSMASQ_CONF_PATH=${TMP_DNSMASQ_PATH}
+
DNS_QUERY_STRATEGY="UseIP"
[ "$FILTER_PROXY_IPV6" = "1" ] && DNS_QUERY_STRATEGY="UseIPv4"
DNSMASQ_FILTER_PROXY_IPV6=${FILTER_PROXY_IPV6}
diff --git a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua b/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua
new file mode 100644
index 000000000..2e54acc51
--- /dev/null
+++ b/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua
@@ -0,0 +1,677 @@
+local api = require "luci.passwall.api"
+local appname = "passwall"
+local uci = api.uci
+local sys = api.sys
+local fs = api.fs
+local datatypes = api.datatypes
+local TMP = {}
+
+local function tinsert(table_name, val)
+ if table_name and type(table_name) == "table" then
+ if not TMP[table_name] then
+ TMP[table_name] = {}
+ end
+ if TMP[table_name][val] then
+ return false
+ end
+ table.insert(table_name, val)
+ TMP[table_name][val] = true
+ return true
+ end
+ return false
+end
+
+local function backup_servers()
+ local DNSMASQ_DNS = uci:get("dhcp", "@dnsmasq[0]", "server")
+ if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then
+ uci:set(appname, "@global[0]", "dnsmasq_servers", DNSMASQ_DNS)
+ uci:commit(appname)
+ end
+end
+
+local function restore_servers()
+ local dns_table = {}
+ local DNSMASQ_DNS = uci:get("dhcp", "@dnsmasq[0]", "server")
+ if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then
+ for k, v in ipairs(DNSMASQ_DNS) do
+ tinsert(dns_table, v)
+ end
+ end
+ local OLD_SERVER = uci:get(appname, "@global[0]", "dnsmasq_servers")
+ if OLD_SERVER and #OLD_SERVER > 0 then
+ for k, v in ipairs(OLD_SERVER) do
+ tinsert(dns_table, v)
+ end
+ uci:delete(appname, "@global[0]", "dnsmasq_servers")
+ uci:commit(appname)
+ end
+ if dns_table and #dns_table > 0 then
+ uci:set_list("dhcp", "@dnsmasq[0]", "server", dns_table)
+ uci:commit("dhcp")
+ end
+end
+
+function stretch()
+ local dnsmasq_server = uci:get("dhcp", "@dnsmasq[0]", "server")
+ local dnsmasq_noresolv = uci:get("dhcp", "@dnsmasq[0]", "noresolv")
+ local _flag
+ if dnsmasq_server and #dnsmasq_server > 0 then
+ for k, v in ipairs(dnsmasq_server) do
+ if not v:find("/") then
+ _flag = true
+ end
+ end
+ end
+ if not _flag and dnsmasq_noresolv == "1" then
+ uci:delete("dhcp", "@dnsmasq[0]", "noresolv")
+ local RESOLVFILE = "/tmp/resolv.conf.d/resolv.conf.auto"
+ local file = io.open(RESOLVFILE, "r")
+ if not file then
+ RESOLVFILE = "/tmp/resolv.conf.auto"
+ else
+ local size = file:seek("end")
+ file:close()
+ if size == 0 then
+ RESOLVFILE = "/tmp/resolv.conf.auto"
+ end
+ end
+ uci:set("dhcp", "@dnsmasq[0]", "resolvfile", RESOLVFILE)
+ uci:commit("dhcp")
+ end
+end
+
+function restart(var)
+ local LOG = var["-LOG"]
+ sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
+ if LOG == "1" then
+ api.log("重启 dnsmasq 服务")
+ end
+end
+
+function logic_restart(var)
+ local LOG = var["-LOG"]
+ local file = io.open(api.TMP_PATH .. "/default_DNS", "r")
+ if file then
+ backup_servers()
+ --sys.call("sed -i '/list server/d' /etc/config/dhcp >/dev/null 2>&1")
+ local dns_table = {}
+ local dnsmasq_server = uci:get("dhcp", "@dnsmasq[0]", "server")
+ if dnsmasq_server and #dnsmasq_server > 0 then
+ for k, v in ipairs(dnsmasq_server) do
+ if v:find("/") then
+ tinsert(dns_table, v)
+ end
+ end
+ if dns_table and #dns_table > 0 then
+ uci:set_list("dhcp", "@dnsmasq[0]", "server", dns_table)
+ uci:commit("dhcp")
+ end
+ end
+ sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
+ restore_servers()
+ else
+ sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
+ end
+ if LOG == "1" then
+ api.log("重启 dnsmasq 服务")
+ end
+end
+
+function copy_instance(var)
+ local LISTEN_PORT = var["-LISTEN_PORT"]
+ local DNSMASQ_CONF = var["-DNSMASQ_CONF"]
+ local conf_lines = {}
+ local DEFAULT_DNSMASQ_CFGID = sys.exec("echo -n $(uci -q show dhcp.@dnsmasq[0] | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')")
+ for line in io.lines("/tmp/etc/dnsmasq.conf." .. DEFAULT_DNSMASQ_CFGID) do
+ local filter
+ if line:find("passwall") then filter = true end
+ if line:find("ubus") then filter = true end
+ if line:find("dhcp") then filter = true end
+ if line:find("server") then filter = true end
+ if line:find("port") then filter = true end
+ if not filter then
+ tinsert(conf_lines, line)
+ end
+ end
+ tinsert(conf_lines, "port=" .. LISTEN_PORT)
+ if #conf_lines > 0 then
+ local conf_out = io.open(DNSMASQ_CONF, "a")
+ conf_out:write(table.concat(conf_lines, "\n"))
+ conf_out:close()
+ end
+end
+
+function add_rule(var)
+ local FLAG = var["-FLAG"]
+ local TMP_DNSMASQ_PATH = var["-TMP_DNSMASQ_PATH"]
+ local DNSMASQ_CONF_FILE = var["-DNSMASQ_CONF_FILE"]
+ local LISTEN_PORT = var["-LISTEN_PORT"]
+ local DEFAULT_DNS = var["-DEFAULT_DNS"]
+ local LOCAL_DNS = var["-LOCAL_DNS"]
+ local TUN_DNS = var["-TUN_DNS"]
+ local REMOTE_FAKEDNS = var["-REMOTE_FAKEDNS"]
+ local USE_DEFAULT_DNS = var["-USE_DEFAULT_DNS"]
+ local CHINADNS_DNS = var["-CHINADNS_DNS"]
+ local TCP_NODE = var["-TCP_NODE"]
+ local USE_DIRECT_LIST = var["-USE_DIRECT_LIST"]
+ local USE_PROXY_LIST = var["-USE_PROXY_LIST"]
+ local USE_BLOCK_LIST = var["-USE_BLOCK_LIST"]
+ local USE_GFW_LIST = var["-USE_GFW_LIST"]
+ local CHN_LIST = var["-CHN_LIST"]
+ local DEFAULT_PROXY_MODE = var["-DEFAULT_PROXY_MODE"]
+ local NO_PROXY_IPV6 = var["-NO_PROXY_IPV6"]
+ local NO_LOGIC_LOG = var["-NO_LOGIC_LOG"]
+ local NFTFLAG = var["-NFTFLAG"]
+ local CACHE_PATH = api.CACHE_PATH
+ local CACHE_FLAG = "dnsmasq_" .. FLAG
+ local CACHE_DNS_PATH = CACHE_PATH .. "/" .. CACHE_FLAG
+ local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt"
+ local USE_CHINADNS_NG = "0"
+
+ local list1 = {}
+ local excluded_domain = {}
+ local excluded_domain_str = "!"
+
+ local function log(...)
+ if NO_LOGIC_LOG == "1" then
+ return
+ end
+ api.log(...)
+ end
+
+ local function check_dns(domain, dns)
+ if domain == "" or domain:find("#") then
+ return false
+ end
+ if not dns then
+ return
+ end
+ for k,v in ipairs(list1[domain].dns) do
+ if dns == v then
+ return true
+ end
+ end
+ return false
+ end
+
+ local function check_ipset(domain, ipset)
+ if domain == "" or domain:find("#") then
+ return false
+ end
+ if not ipset then
+ return
+ end
+ for k,v in ipairs(list1[domain].ipsets) do
+ if ipset == v then
+ return true
+ end
+ end
+ return false
+ end
+
+ local function set_domain_address(domain, address)
+ if domain == "" or domain:find("#") then
+ return
+ end
+ if not list1[domain] then
+ list1[domain] = {
+ dns = {},
+ ipsets = {}
+ }
+ end
+ if not list1[domain].address then
+ list1[domain].address = address
+ end
+ end
+
+ local function set_domain_dns(domain, dns)
+ if domain == "" or domain:find("#") then
+ return
+ end
+ if not dns then
+ return
+ end
+ if not list1[domain] then
+ list1[domain] = {
+ dns = {},
+ ipsets = {}
+ }
+ end
+ for line in string.gmatch(dns, '[^' .. "," .. ']+') do
+ if not check_dns(domain, line) then
+ table.insert(list1[domain].dns, line)
+ end
+ end
+ end
+
+ local function set_domain_ipset(domain, ipset)
+ if domain == "" or domain:find("#") then
+ return
+ end
+ if not ipset then
+ return
+ end
+ if not list1[domain] then
+ list1[domain] = {
+ dns = {},
+ ipsets = {}
+ }
+ end
+ for line in string.gmatch(ipset, '[^' .. "," .. ']+') do
+ if not check_ipset(domain, line) then
+ table.insert(list1[domain].ipsets, line)
+ end
+ end
+ end
+
+ local function add_excluded_domain(domain)
+ if domain == "" or domain:find("#") then
+ return
+ end
+ table.insert(excluded_domain, domain)
+ excluded_domain_str = excluded_domain_str .. "|" .. domain
+ end
+
+ local function check_excluded_domain(domain)
+ if domain == "" or domain:find("#") then
+ return false
+ end
+ for k,v in ipairs(excluded_domain) do
+ if domain:find(v) then
+ return true
+ end
+ end
+ return false
+ end
+
+ local cache_text = ""
+ local nodes_address_md5 = sys.exec("echo -n $(uci show passwall | grep '\\.address') | md5sum")
+ local new_rules = sys.exec("echo -n $(find /usr/share/passwall/rules -type f | xargs md5sum)")
+ local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. REMOTE_FAKEDNS .. USE_DEFAULT_DNS .. CHINADNS_DNS .. USE_DIRECT_LIST .. USE_PROXY_LIST .. USE_BLOCK_LIST .. USE_GFW_LIST .. CHN_LIST .. DEFAULT_PROXY_MODE .. NO_PROXY_IPV6 .. nodes_address_md5 .. new_rules .. NFTFLAG
+ if fs.access(CACHE_TEXT_FILE) then
+ for line in io.lines(CACHE_TEXT_FILE) do
+ cache_text = line
+ end
+ end
+
+ if cache_text ~= new_text then
+ api.remove(CACHE_DNS_PATH .. "*")
+ end
+
+ local dnsmasq_default_dns
+ if USE_DEFAULT_DNS ~= "nil" then
+ if USE_DEFAULT_DNS == "direct" then
+ dnsmasq_default_dns = LOCAL_DNS
+ end
+ if USE_DEFAULT_DNS == "remote" then
+ dnsmasq_default_dns = TUN_DNS
+ end
+ if USE_DEFAULT_DNS == "remote" and CHN_LIST == "direct" then
+ dnsmasq_default_dns = TUN_DNS
+ end
+ end
+
+ local only_global
+ if DEFAULT_PROXY_MODE == "proxy" and CHN_LIST == "0" and USE_GFW_LIST == "0" then
+ --没有启用中国列表和GFW列表时
+ dnsmasq_default_dns = TUN_DNS
+ only_global = 1
+ end
+ if USE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then
+ dnsmasq_default_dns = CHINADNS_DNS
+ USE_CHINADNS_NG = "1"
+ end
+
+ local setflag_4= (NFTFLAG == "1") and "4#inet#passwall#" or ""
+ local setflag_6= (NFTFLAG == "1") and "6#inet#passwall#" or ""
+
+ if not fs.access(CACHE_DNS_PATH) then
+ fs.mkdir(CACHE_DNS_PATH)
+
+ --屏蔽列表
+ if USE_CHINADNS_NG == "0" then
+ if USE_BLOCK_LIST == "1" then
+ for line in io.lines("/usr/share/passwall/rules/block_host") do
+ line = api.get_std_domain(line)
+ if line ~= "" and not line:find("#") then
+ set_domain_address(line, "")
+ end
+ end
+ end
+ end
+
+ local fwd_dns
+ local ipset_flag
+ local no_ipv6
+
+ --始终用国内DNS解析节点域名
+ if true then
+ fwd_dns = LOCAL_DNS
+ if USE_CHINADNS_NG == "1" then
+ fwd_dns = nil
+ else
+ uci:foreach(appname, "nodes", function(t)
+ local function process_address(address)
+ if address == "engage.cloudflareclient.com" then return end
+ if datatypes.hostname(address) then
+ set_domain_dns(address, fwd_dns)
+ set_domain_ipset(address, setflag_4 .. "passwall_vpslist," .. setflag_6 .. "passwall_vpslist6")
+ end
+ end
+ process_address(t.address)
+ process_address(t.download_address)
+ end)
+ log(string.format(" - 节点列表中的域名(vpslist):%s", fwd_dns or "默认"))
+ end
+ end
+
+ --直连(白名单)列表
+ if USE_DIRECT_LIST == "1" then
+ if fs.access("/usr/share/passwall/rules/direct_host") then
+ fwd_dns = LOCAL_DNS
+ if USE_CHINADNS_NG == "1" then
+ fwd_dns = nil
+ end
+ if fwd_dns then
+ --始终用国内DNS解析直连(白名单)列表
+ for line in io.lines("/usr/share/passwall/rules/direct_host") do
+ line = api.get_std_domain(line)
+ if line ~= "" and not line:find("#") then
+ add_excluded_domain(line)
+ set_domain_dns(line, fwd_dns)
+ set_domain_ipset(line, setflag_4 .. "passwall_whitelist," .. setflag_6 .. "passwall_whitelist6")
+ end
+ end
+ log(string.format(" - 域名白名单(whitelist):%s", fwd_dns or "默认"))
+ end
+ end
+ end
+
+ --代理(黑名单)列表
+ if USE_PROXY_LIST == "1" then
+ if fs.access("/usr/share/passwall/rules/proxy_host") then
+ fwd_dns = TUN_DNS
+ if USE_CHINADNS_NG == "1" then
+ fwd_dns = nil
+ end
+ if fwd_dns then
+ --始终使用远程DNS解析代理(黑名单)列表
+ for line in io.lines("/usr/share/passwall/rules/proxy_host") do
+ line = api.get_std_domain(line)
+ if line ~= "" and not line:find("#") then
+ add_excluded_domain(line)
+ local ipset_flag = setflag_4 .. "passwall_blacklist," .. setflag_6 .. "passwall_blacklist6"
+ if NO_PROXY_IPV6 == "1" then
+ set_domain_address(line, "::")
+ ipset_flag = setflag_4 .. "passwall_blacklist"
+ end
+ if REMOTE_FAKEDNS == "1" then
+ ipset_flag = nil
+ end
+ set_domain_dns(line, fwd_dns)
+ set_domain_ipset(line, ipset_flag)
+ end
+ end
+ log(string.format(" - 代理域名表(blacklist):%s", fwd_dns or "默认"))
+ end
+ end
+ end
+
+ --GFW列表
+ if USE_GFW_LIST == "1" then
+ if fs.access("/usr/share/passwall/rules/gfwlist") then
+ fwd_dns = TUN_DNS
+ if USE_CHINADNS_NG == "1" then
+ fwd_dns = nil
+ end
+ if fwd_dns then
+ local ipset_flag = setflag_4 .. "passwall_gfwlist," .. setflag_6 .. "passwall_gfwlist6"
+ if NO_PROXY_IPV6 == "1" then
+ ipset_flag = setflag_4 .. "passwall_gfwlist"
+ end
+ if REMOTE_FAKEDNS == "1" then
+ ipset_flag = nil
+ end
+ local gfwlist_str = sys.exec('cat /usr/share/passwall/rules/gfwlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"')
+ for line in string.gmatch(gfwlist_str, "[^\r\n]+") do
+ if line ~= "" then
+ if NO_PROXY_IPV6 == "1" then
+ set_domain_address(line, "::")
+ end
+ if dnsmasq_default_dns == fwd_dns then
+ fwd_dns = nil
+ else
+ set_domain_dns(line, fwd_dns)
+ end
+ set_domain_ipset(line, ipset_flag)
+ end
+ end
+ log(string.format(" - 防火墙域名表(gfwlist):%s", fwd_dns or "默认"))
+ end
+ end
+ end
+
+ --中国列表
+ if CHN_LIST ~= "0" then
+ if fs.access("/usr/share/passwall/rules/chnlist") then
+ fwd_dns = nil
+ if CHN_LIST == "direct" then
+ fwd_dns = LOCAL_DNS
+ end
+ if CHN_LIST == "proxy" then
+ fwd_dns = TUN_DNS
+ end
+ if USE_CHINADNS_NG == "1" then
+ fwd_dns = nil
+ end
+ if fwd_dns then
+ local ipset_flag = setflag_4 .. "passwall_chnroute," .. setflag_6 .. "passwall_chnroute6"
+ if CHN_LIST == "proxy" then
+ if NO_PROXY_IPV6 == "1" then
+ ipset_flag = setflag_4 .. "passwall_chnroute"
+ end
+ if REMOTE_FAKEDNS == "1" then
+ ipset_flag = nil
+ end
+ end
+ local chnlist_str = sys.exec('cat /usr/share/passwall/rules/chnlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"')
+ for line in string.gmatch(chnlist_str, "[^\r\n]+") do
+ if line ~= "" then
+ if CHN_LIST == "proxy" and NO_PROXY_IPV6 == "1" then
+ set_domain_address(line, "::")
+ end
+ if dnsmasq_default_dns == fwd_dns then
+ fwd_dns = nil
+ else
+ set_domain_dns(line, fwd_dns)
+ end
+ set_domain_ipset(line, ipset_flag)
+ end
+ end
+ log(string.format(" - 中国域名表(chnroute):%s", fwd_dns or "默认"))
+ end
+ end
+ end
+
+ --分流规则
+ if uci:get(appname, TCP_NODE, "protocol") == "_shunt" and USE_CHINADNS_NG == "0" then
+ local t = uci:get_all(appname, TCP_NODE)
+ local default_node_id = t["default_node"] or "_direct"
+ uci:foreach(appname, "shunt_rules", function(s)
+ local _node_id = t[s[".name"]] or "nil"
+ if _node_id ~= "nil" and _node_id ~= "_blackhole" then
+ if _node_id == "_default" then
+ _node_id = default_node_id
+ end
+
+ fwd_dns = nil
+ ipset_flag = nil
+ no_ipv6 = nil
+
+ if _node_id == "_direct" then
+ fwd_dns = LOCAL_DNS
+ if USE_DIRECT_LIST == "1" then
+ ipset_flag = setflag_4 .. "passwall_whitelist," .. setflag_6 .. "passwall_whitelist6"
+ else
+ ipset_flag = setflag_4 .. "passwall_shuntlist," .. setflag_6 .. "passwall_shuntlist6"
+ end
+ else
+ fwd_dns = TUN_DNS
+ ipset_flag = setflag_4 .. "passwall_shuntlist," .. setflag_6 .. "passwall_shuntlist6"
+ if NO_PROXY_IPV6 == "1" then
+ ipset_flag = setflag_4 .. "passwall_shuntlist"
+ no_ipv6 = true
+ end
+ if not only_global then
+ if REMOTE_FAKEDNS == "1" then
+ ipset_flag = nil
+ end
+ end
+ end
+
+ local domain_list = s.domain_list or ""
+ for line in string.gmatch(domain_list, "[^\r\n]+") do
+ if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("geosite:") and not line:find("ext:") then
+ if line:find("domain:") or line:find("full:") then
+ line = string.match(line, ":([^:]+)$")
+ end
+ line = api.get_std_domain(line)
+ add_excluded_domain(line)
+
+ if no_ipv6 then
+ set_domain_address(line, "::")
+ end
+ set_domain_dns(line, fwd_dns)
+ set_domain_ipset(line, ipset_flag)
+ end
+ end
+ if _node_id ~= "_direct" then
+ log(string.format(" - Sing-Box/Xray分流规则(%s):%s", s.remarks, fwd_dns or "默认"))
+ end
+ end
+ end)
+ elseif only_global == 1 and NO_PROXY_IPV6 == "1" then
+ --节点:固定节点
+ --代理模式:全局模式
+ --过滤代理域名 IPv6:启用
+ --禁止解析所有IPv6记录
+ list1["#"] = {
+ dns = {},
+ ipsets = {},
+ address = "::"
+ }
+ end
+
+ if list1 and next(list1) then
+ local address_out = io.open(CACHE_DNS_PATH .. "/000-address.conf", "a")
+ local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a")
+ local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a")
+ local set_name = "ipset"
+ if NFTFLAG == "1" then
+ set_name = "nftset"
+ end
+ for key, value in pairs(list1) do
+ if value.address then
+ local domain = "." .. key
+ if key == "#" then
+ domain = key
+ end
+ address_out:write(string.format("address=/%s/%s", domain, value.address) .. "\n")
+ end
+ if value.dns and #value.dns > 0 then
+ for i, dns in ipairs(value.dns) do
+ server_out:write(string.format("server=/.%s/%s", key, dns) .. "\n")
+ end
+ end
+ if value.ipsets and #value.ipsets > 0 then
+ local ipsets_str = ""
+ for i, ipset in ipairs(value.ipsets) do
+ ipsets_str = ipsets_str .. ipset .. ","
+ end
+ ipsets_str = ipsets_str:sub(1, #ipsets_str - 1)
+ ipset_out:write(string.format("%s=/.%s/%s", set_name, key, ipsets_str) .. "\n")
+ end
+ end
+ address_out:close()
+ server_out:close()
+ ipset_out:close()
+ end
+
+ local f_out = io.open(CACHE_TEXT_FILE, "a")
+ f_out:write(new_text)
+ f_out:close()
+ end
+
+ if USE_CHINADNS_NG == "0" then
+ if api.is_install("procd\\-ujail") then
+ fs.copyr(CACHE_DNS_PATH, TMP_DNSMASQ_PATH)
+ else
+ api.remove(TMP_DNSMASQ_PATH)
+ fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH)
+ end
+ end
+
+ if DNSMASQ_CONF_FILE ~= "nil" then
+ local conf_lines = {}
+ if LISTEN_PORT then
+ --Copy dnsmasq instance
+ local DEFAULT_DNSMASQ_CFGID = sys.exec("echo -n $(uci -q show dhcp.@dnsmasq[0] | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')")
+ for line in io.lines("/tmp/etc/dnsmasq.conf." .. DEFAULT_DNSMASQ_CFGID) do
+ local filter
+ if line:find("passwall") then filter = true end
+ if line:find("ubus") then filter = true end
+ if line:find("dhcp") then filter = true end
+ if line:find("server") then filter = true end
+ if line:find("port") then filter = true end
+ if not filter then
+ tinsert(conf_lines, line)
+ end
+ end
+ tinsert(conf_lines, "port=" .. LISTEN_PORT)
+ else
+ --Modify the default dnsmasq service
+ end
+ if USE_CHINADNS_NG == "0" then
+ tinsert(conf_lines, string.format("conf-dir=%s", TMP_DNSMASQ_PATH))
+ end
+ if dnsmasq_default_dns then
+ for s in string.gmatch(dnsmasq_default_dns, '[^' .. "," .. ']+') do
+ tinsert(conf_lines, string.format("server=%s", s))
+ end
+ tinsert(conf_lines, "all-servers")
+ tinsert(conf_lines, "no-poll")
+ tinsert(conf_lines, "no-resolv")
+ if USE_CHINADNS_NG == "0" then
+ log(string.format(" - 默认:%s", dnsmasq_default_dns))
+ end
+
+ if FLAG == "default" then
+ local f_out = io.open("/tmp/etc/passwall/default_DNS", "a")
+ f_out:write(DEFAULT_DNS)
+ f_out:close()
+ end
+ end
+ if #conf_lines > 0 then
+ local conf_out = io.open(DNSMASQ_CONF_FILE, "a")
+ conf_out:write(table.concat(conf_lines, "\n"))
+ conf_out:close()
+ end
+ end
+
+ if USE_CHINADNS_NG == "0" then
+ log(" - PassWall必须依赖于Dnsmasq,如果你自行配置了错误的DNS流程,将会导致域名(直连/代理域名)分流失效!!!")
+ end
+end
+
+_G.stretch = stretch
+_G.restart = restart
+_G.logic_restart = logic_restart
+_G.copy_instance = copy_instance
+_G.add_rule = add_rule
+
+if arg[1] then
+ local func =_G[arg[1]]
+ if func then
+ func(api.get_function_args(arg))
+ end
+end
diff --git a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh b/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh
deleted file mode 100755
index 999c9ff5a..000000000
--- a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-
-copy_instance() {
- local listen_port dnsmasq_conf
- eval_set_val $@
- [ -s "/tmp/etc/dnsmasq.conf.${DEFAULT_DNSMASQ_CFGID}" ] && {
- cp -r /tmp/etc/dnsmasq.conf.${DEFAULT_DNSMASQ_CFGID} $dnsmasq_conf
- sed -i "/passwall/d" $dnsmasq_conf
- sed -i "/ubus/d" $dnsmasq_conf
- sed -i "/dhcp/d" $dnsmasq_conf
- sed -i "/port=/d" $dnsmasq_conf
- sed -i "/server=/d" $dnsmasq_conf
- }
- echo "port=${listen_port}" >> $dnsmasq_conf
-}
-
-DEFAULT_DNSMASQ_CFGID="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')"
-
-arg1=$1
-shift
-case $arg1 in
-copy_instance)
- copy_instance $@
- ;;
-*) ;;
-esac
diff --git a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua b/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua
deleted file mode 100644
index 4aa982b57..000000000
--- a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua
+++ /dev/null
@@ -1,506 +0,0 @@
-require "luci.sys"
-local api = require "luci.passwall.api"
-local appname = "passwall"
-
-local var = api.get_args(arg)
-local FLAG = var["-FLAG"]
-local TMP_DNSMASQ_PATH = var["-TMP_DNSMASQ_PATH"]
-local DNSMASQ_CONF_FILE = var["-DNSMASQ_CONF_FILE"]
-local DEFAULT_DNS = var["-DEFAULT_DNS"]
-local LOCAL_DNS = var["-LOCAL_DNS"]
-local TUN_DNS = var["-TUN_DNS"]
-local REMOTE_FAKEDNS = var["-REMOTE_FAKEDNS"]
-local USE_DEFAULT_DNS = var["-USE_DEFAULT_DNS"]
-local CHINADNS_DNS = var["-CHINADNS_DNS"]
-local TCP_NODE = var["-TCP_NODE"]
-local USE_DIRECT_LIST = var["-USE_DIRECT_LIST"]
-local USE_PROXY_LIST = var["-USE_PROXY_LIST"]
-local USE_BLOCK_LIST = var["-USE_BLOCK_LIST"]
-local USE_GFW_LIST = var["-USE_GFW_LIST"]
-local CHN_LIST = var["-CHN_LIST"]
-local DEFAULT_PROXY_MODE = var["-DEFAULT_PROXY_MODE"]
-local NO_PROXY_IPV6 = var["-NO_PROXY_IPV6"]
-local NO_LOGIC_LOG = var["-NO_LOGIC_LOG"]
-local NFTFLAG = var["-NFTFLAG"]
-local CACHE_PATH = api.CACHE_PATH
-local CACHE_FLAG = "dnsmasq_" .. FLAG
-local CACHE_DNS_PATH = CACHE_PATH .. "/" .. CACHE_FLAG
-local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt"
-local USE_CHINADNS_NG = "0"
-
-local uci = api.uci
-local sys = api.sys
-local fs = api.fs
-local datatypes = api.datatypes
-
-local list1 = {}
-local excluded_domain = {}
-local excluded_domain_str = "!"
-
-local function log(...)
- if NO_LOGIC_LOG == "1" then
- return
- end
- api.log(...)
-end
-
-local function check_dns(domain, dns)
- if domain == "" or domain:find("#") then
- return false
- end
- if not dns then
- return
- end
- for k,v in ipairs(list1[domain].dns) do
- if dns == v then
- return true
- end
- end
- return false
-end
-
-local function check_ipset(domain, ipset)
- if domain == "" or domain:find("#") then
- return false
- end
- if not ipset then
- return
- end
- for k,v in ipairs(list1[domain].ipsets) do
- if ipset == v then
- return true
- end
- end
- return false
-end
-
-local function set_domain_address(domain, address)
- if domain == "" or domain:find("#") then
- return
- end
- if not list1[domain] then
- list1[domain] = {
- dns = {},
- ipsets = {}
- }
- end
- if not list1[domain].address then
- list1[domain].address = address
- end
-end
-
-local function set_domain_dns(domain, dns)
- if domain == "" or domain:find("#") then
- return
- end
- if not dns then
- return
- end
- if not list1[domain] then
- list1[domain] = {
- dns = {},
- ipsets = {}
- }
- end
- for line in string.gmatch(dns, '[^' .. "," .. ']+') do
- if not check_dns(domain, line) then
- table.insert(list1[domain].dns, line)
- end
- end
-end
-
-local function set_domain_ipset(domain, ipset)
- if domain == "" or domain:find("#") then
- return
- end
- if not ipset then
- return
- end
- if not list1[domain] then
- list1[domain] = {
- dns = {},
- ipsets = {}
- }
- end
- for line in string.gmatch(ipset, '[^' .. "," .. ']+') do
- if not check_ipset(domain, line) then
- table.insert(list1[domain].ipsets, line)
- end
- end
-end
-
-local function add_excluded_domain(domain)
- if domain == "" or domain:find("#") then
- return
- end
- table.insert(excluded_domain, domain)
- excluded_domain_str = excluded_domain_str .. "|" .. domain
-end
-
-local function check_excluded_domain(domain)
- if domain == "" or domain:find("#") then
- return false
- end
- for k,v in ipairs(excluded_domain) do
- if domain:find(v) then
- return true
- end
- end
- return false
-end
-
-local cache_text = ""
-local nodes_address_md5 = luci.sys.exec("echo -n $(uci show passwall | grep '\\.address') | md5sum")
-local new_rules = luci.sys.exec("echo -n $(find /usr/share/passwall/rules -type f | xargs md5sum)")
-local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. REMOTE_FAKEDNS .. USE_DEFAULT_DNS .. CHINADNS_DNS .. USE_DIRECT_LIST .. USE_PROXY_LIST .. USE_BLOCK_LIST .. USE_GFW_LIST .. CHN_LIST .. DEFAULT_PROXY_MODE .. NO_PROXY_IPV6 .. nodes_address_md5 .. new_rules .. NFTFLAG
-if fs.access(CACHE_TEXT_FILE) then
- for line in io.lines(CACHE_TEXT_FILE) do
- cache_text = line
- end
-end
-
-if cache_text ~= new_text then
- api.remove(CACHE_DNS_PATH .. "*")
-end
-
-local dnsmasq_default_dns
-if USE_DEFAULT_DNS ~= "nil" then
- if USE_DEFAULT_DNS == "direct" then
- dnsmasq_default_dns = LOCAL_DNS
- end
- if USE_DEFAULT_DNS == "remote" then
- dnsmasq_default_dns = TUN_DNS
- end
- if USE_DEFAULT_DNS == "remote" and CHN_LIST == "direct" then
- dnsmasq_default_dns = TUN_DNS
- end
-end
-
-local only_global
-if DEFAULT_PROXY_MODE == "proxy" and CHN_LIST == "0" and USE_GFW_LIST == "0" then
- --没有启用中国列表和GFW列表时
- dnsmasq_default_dns = TUN_DNS
- only_global = 1
-end
-if USE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then
- dnsmasq_default_dns = CHINADNS_DNS
- USE_CHINADNS_NG = "1"
-end
-
-local setflag_4= (NFTFLAG == "1") and "4#inet#passwall#" or ""
-local setflag_6= (NFTFLAG == "1") and "6#inet#passwall#" or ""
-
-if not fs.access(CACHE_DNS_PATH) then
- fs.mkdir(CACHE_DNS_PATH)
-
- --屏蔽列表
- if USE_CHINADNS_NG == "0" then
- if USE_BLOCK_LIST == "1" then
- for line in io.lines("/usr/share/passwall/rules/block_host") do
- line = api.get_std_domain(line)
- if line ~= "" and not line:find("#") then
- set_domain_address(line, "")
- end
- end
- end
- end
-
- local fwd_dns
- local ipset_flag
- local no_ipv6
-
- --始终用国内DNS解析节点域名
- if true then
- fwd_dns = LOCAL_DNS
- if USE_CHINADNS_NG == "1" then
- fwd_dns = nil
- else
- uci:foreach(appname, "nodes", function(t)
- local function process_address(address)
- if address == "engage.cloudflareclient.com" then return end
- if datatypes.hostname(address) then
- set_domain_dns(address, fwd_dns)
- set_domain_ipset(address, setflag_4 .. "passwall_vpslist," .. setflag_6 .. "passwall_vpslist6")
- end
- end
- process_address(t.address)
- process_address(t.download_address)
- end)
- log(string.format(" - 节点列表中的域名(vpslist):%s", fwd_dns or "默认"))
- end
- end
-
- --直连(白名单)列表
- if USE_DIRECT_LIST == "1" then
- if fs.access("/usr/share/passwall/rules/direct_host") then
- fwd_dns = LOCAL_DNS
- if USE_CHINADNS_NG == "1" then
- fwd_dns = nil
- end
- if fwd_dns then
- --始终用国内DNS解析直连(白名单)列表
- for line in io.lines("/usr/share/passwall/rules/direct_host") do
- line = api.get_std_domain(line)
- if line ~= "" and not line:find("#") then
- add_excluded_domain(line)
- set_domain_dns(line, fwd_dns)
- set_domain_ipset(line, setflag_4 .. "passwall_whitelist," .. setflag_6 .. "passwall_whitelist6")
- end
- end
- log(string.format(" - 域名白名单(whitelist):%s", fwd_dns or "默认"))
- end
- end
- end
-
- --代理(黑名单)列表
- if USE_PROXY_LIST == "1" then
- if fs.access("/usr/share/passwall/rules/proxy_host") then
- fwd_dns = TUN_DNS
- if USE_CHINADNS_NG == "1" then
- fwd_dns = nil
- end
- if fwd_dns then
- --始终使用远程DNS解析代理(黑名单)列表
- for line in io.lines("/usr/share/passwall/rules/proxy_host") do
- line = api.get_std_domain(line)
- if line ~= "" and not line:find("#") then
- add_excluded_domain(line)
- local ipset_flag = setflag_4 .. "passwall_blacklist," .. setflag_6 .. "passwall_blacklist6"
- if NO_PROXY_IPV6 == "1" then
- set_domain_address(line, "::")
- ipset_flag = setflag_4 .. "passwall_blacklist"
- end
- if REMOTE_FAKEDNS == "1" then
- ipset_flag = nil
- end
- set_domain_dns(line, fwd_dns)
- set_domain_ipset(line, ipset_flag)
- end
- end
- log(string.format(" - 代理域名表(blacklist):%s", fwd_dns or "默认"))
- end
- end
- end
-
- --GFW列表
- if USE_GFW_LIST == "1" then
- if fs.access("/usr/share/passwall/rules/gfwlist") then
- fwd_dns = TUN_DNS
- if USE_CHINADNS_NG == "1" then
- fwd_dns = nil
- end
- if fwd_dns then
- local ipset_flag = setflag_4 .. "passwall_gfwlist," .. setflag_6 .. "passwall_gfwlist6"
- if NO_PROXY_IPV6 == "1" then
- ipset_flag = setflag_4 .. "passwall_gfwlist"
- end
- if REMOTE_FAKEDNS == "1" then
- ipset_flag = nil
- end
- local gfwlist_str = sys.exec('cat /usr/share/passwall/rules/gfwlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"')
- for line in string.gmatch(gfwlist_str, "[^\r\n]+") do
- if line ~= "" then
- if NO_PROXY_IPV6 == "1" then
- set_domain_address(line, "::")
- end
- if dnsmasq_default_dns == fwd_dns then
- fwd_dns = nil
- else
- set_domain_dns(line, fwd_dns)
- end
- set_domain_ipset(line, ipset_flag)
- end
- end
- log(string.format(" - 防火墙域名表(gfwlist):%s", fwd_dns or "默认"))
- end
- end
- end
-
- --中国列表
- if CHN_LIST ~= "0" then
- if fs.access("/usr/share/passwall/rules/chnlist") then
- fwd_dns = nil
- if CHN_LIST == "direct" then
- fwd_dns = LOCAL_DNS
- end
- if CHN_LIST == "proxy" then
- fwd_dns = TUN_DNS
- end
- if USE_CHINADNS_NG == "1" then
- fwd_dns = nil
- end
- if fwd_dns then
- local ipset_flag = setflag_4 .. "passwall_chnroute," .. setflag_6 .. "passwall_chnroute6"
- if CHN_LIST == "proxy" then
- if NO_PROXY_IPV6 == "1" then
- ipset_flag = setflag_4 .. "passwall_chnroute"
- end
- if REMOTE_FAKEDNS == "1" then
- ipset_flag = nil
- end
- end
- local chnlist_str = sys.exec('cat /usr/share/passwall/rules/chnlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"')
- for line in string.gmatch(chnlist_str, "[^\r\n]+") do
- if line ~= "" then
- if CHN_LIST == "proxy" and NO_PROXY_IPV6 == "1" then
- set_domain_address(line, "::")
- end
- if dnsmasq_default_dns == fwd_dns then
- fwd_dns = nil
- else
- set_domain_dns(line, fwd_dns)
- end
- set_domain_ipset(line, ipset_flag)
- end
- end
- log(string.format(" - 中国域名表(chnroute):%s", fwd_dns or "默认"))
- end
- end
- end
-
- --分流规则
- if uci:get(appname, TCP_NODE, "protocol") == "_shunt" and USE_CHINADNS_NG == "0" then
- local t = uci:get_all(appname, TCP_NODE)
- local default_node_id = t["default_node"] or "_direct"
- uci:foreach(appname, "shunt_rules", function(s)
- local _node_id = t[s[".name"]] or "nil"
- if _node_id ~= "nil" and _node_id ~= "_blackhole" then
- if _node_id == "_default" then
- _node_id = default_node_id
- end
-
- fwd_dns = nil
- ipset_flag = nil
- no_ipv6 = nil
-
- if _node_id == "_direct" then
- fwd_dns = LOCAL_DNS
- if USE_DIRECT_LIST == "1" then
- ipset_flag = setflag_4 .. "passwall_whitelist," .. setflag_6 .. "passwall_whitelist6"
- else
- ipset_flag = setflag_4 .. "passwall_shuntlist," .. setflag_6 .. "passwall_shuntlist6"
- end
- else
- fwd_dns = TUN_DNS
- ipset_flag = setflag_4 .. "passwall_shuntlist," .. setflag_6 .. "passwall_shuntlist6"
- if NO_PROXY_IPV6 == "1" then
- ipset_flag = setflag_4 .. "passwall_shuntlist"
- no_ipv6 = true
- end
- if not only_global then
- if REMOTE_FAKEDNS == "1" then
- ipset_flag = nil
- end
- end
- end
-
- local domain_list = s.domain_list or ""
- for line in string.gmatch(domain_list, "[^\r\n]+") do
- if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("geosite:") and not line:find("ext:") then
- if line:find("domain:") or line:find("full:") then
- line = string.match(line, ":([^:]+)$")
- end
- line = api.get_std_domain(line)
- add_excluded_domain(line)
-
- if no_ipv6 then
- set_domain_address(line, "::")
- end
- set_domain_dns(line, fwd_dns)
- set_domain_ipset(line, ipset_flag)
- end
- end
- if _node_id ~= "_direct" then
- log(string.format(" - Sing-Box/Xray分流规则(%s):%s", s.remarks, fwd_dns or "默认"))
- end
- end
- end)
- elseif only_global == 1 and NO_PROXY_IPV6 == "1" then
- --节点:固定节点
- --代理模式:全局模式
- --过滤代理域名 IPv6:启用
- --禁止解析所有IPv6记录
- list1["#"] = {
- dns = {},
- ipsets = {},
- address = "::"
- }
- end
-
- if list1 and next(list1) then
- local address_out = io.open(CACHE_DNS_PATH .. "/000-address.conf", "a")
- local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a")
- local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a")
- local set_name = "ipset"
- if NFTFLAG == "1" then
- set_name = "nftset"
- end
- for key, value in pairs(list1) do
- if value.address then
- local domain = "." .. key
- if key == "#" then
- domain = key
- end
- address_out:write(string.format("address=/%s/%s", domain, value.address) .. "\n")
- end
- if value.dns and #value.dns > 0 then
- for i, dns in ipairs(value.dns) do
- server_out:write(string.format("server=/.%s/%s", key, dns) .. "\n")
- end
- end
- if value.ipsets and #value.ipsets > 0 then
- local ipsets_str = ""
- for i, ipset in ipairs(value.ipsets) do
- ipsets_str = ipsets_str .. ipset .. ","
- end
- ipsets_str = ipsets_str:sub(1, #ipsets_str - 1)
- ipset_out:write(string.format("%s=/.%s/%s", set_name, key, ipsets_str) .. "\n")
- end
- end
- address_out:close()
- server_out:close()
- ipset_out:close()
- end
-
- local f_out = io.open(CACHE_TEXT_FILE, "a")
- f_out:write(new_text)
- f_out:close()
-end
-
-if USE_CHINADNS_NG == "0" then
- if api.is_install("procd\\-ujail") then
- fs.copyr(CACHE_DNS_PATH, TMP_DNSMASQ_PATH)
- else
- api.remove(TMP_DNSMASQ_PATH)
- fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH)
- end
-end
-
-if DNSMASQ_CONF_FILE ~= "nil" then
- local conf_out = io.open(DNSMASQ_CONF_FILE, "a")
- if USE_CHINADNS_NG == "0" then
- conf_out:write(string.format("conf-dir=%s", TMP_DNSMASQ_PATH) .. "\n")
- end
- if dnsmasq_default_dns then
- for s in string.gmatch(dnsmasq_default_dns, '[^' .. "," .. ']+') do
- conf_out:write(string.format("server=%s", s) .. "\n")
- end
- conf_out:write("all-servers" .. "\n")
- conf_out:write("no-poll" .. "\n")
- conf_out:write("no-resolv" .. "\n")
- conf_out:close()
- if USE_CHINADNS_NG == "0" then
- log(string.format(" - 默认:%s", dnsmasq_default_dns))
- end
-
- if FLAG == "default" then
- local f_out = io.open("/tmp/etc/passwall/default_DNS", "a")
- f_out:write(DEFAULT_DNS)
- f_out:close()
- end
- end
-end
-
-if USE_CHINADNS_NG == "0" then
- log(" - PassWall必须依赖于Dnsmasq,如果你自行配置了错误的DNS流程,将会导致域名(直连/代理域名)分流失效!!!")
-end
diff --git a/luci-app-passwall/root/usr/share/passwall/iptables.sh b/luci-app-passwall/root/usr/share/passwall/iptables.sh
index f59105cf8..06c9e3871 100755
--- a/luci-app-passwall/root/usr/share/passwall/iptables.sh
+++ b/luci-app-passwall/root/usr/share/passwall/iptables.sh
@@ -2,6 +2,7 @@
DIR="$(cd "$(dirname "$0")" && pwd)"
MY_PATH=$DIR/iptables.sh
+IPSET_LOCALLIST="passwall_locallist"
IPSET_LANLIST="passwall_lanlist"
IPSET_VPSLIST="passwall_vpslist"
IPSET_SHUNTLIST="passwall_shuntlist"
@@ -11,6 +12,7 @@ IPSET_BLACKLIST="passwall_blacklist"
IPSET_WHITELIST="passwall_whitelist"
IPSET_BLOCKLIST="passwall_blocklist"
+IPSET_LOCALLIST6="passwall_locallist6"
IPSET_LANLIST6="passwall_lanlist6"
IPSET_VPSLIST6="passwall_vpslist6"
IPSET_SHUNTLIST6="passwall_shuntlist6"
@@ -320,23 +322,22 @@ load_acl() {
echolog " - ${msg}不代理所有 UDP 端口"
fi
}
-
+
+ local dns_redirect
if ([ -n "$tcp_port" ] && [ -n "${tcp_proxy_mode}" ]) || ([ -n "$udp_port" ] && [ -n "${udp_proxy_mode}" ]); then
- [ -n "$dns_redirect_port" ] && {
- $ipt_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN
- $ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null
- $ipt_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN
- $ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null
- $ipt_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port
- $ip6t_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port 2>/dev/null
- $ipt_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port
- $ip6t_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port 2>/dev/null
- }
+ [ -n "${dns_redirect_port}" ] && dns_redirect=${dns_redirect_port}
else
- $ipt_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN
- $ip6t_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null
- $ipt_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN
- $ip6t_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null
+ [ -n "${DIRECT_DNSMASQ_PORT}" ] && dns_redirect=${DIRECT_DNSMASQ_PORT}
+ fi
+ if [ -n "${dns_redirect}" ]; then
+ $ipt_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN
+ $ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null
+ $ipt_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN
+ $ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null
+ $ipt_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} $(dst $IPSET_LOCALLIST) --dport 53 -j REDIRECT --to-ports ${dns_redirect}
+ $ip6t_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} $(dst $IPSET_LOCALLIST) --dport 53 -j REDIRECT --to-ports ${dns_redirect} 2>/dev/null
+ $ipt_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} $(dst $IPSET_LOCALLIST) --dport 53 -j REDIRECT --to-ports ${dns_redirect}
+ $ip6t_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} $(dst $IPSET_LOCALLIST) --dport 53 -j REDIRECT --to-ports ${dns_redirect} 2>/dev/null
fi
[ -n "$tcp_port" -o -n "$udp_port" ] && {
@@ -468,7 +469,7 @@ load_acl() {
unset ipt_tmp ipt_j _ipt_source msg msg2
done
unset enabled sid remarks sources use_global_config use_direct_list use_proxy_list use_block_list use_gfw_list chn_list tcp_proxy_mode udp_proxy_mode dns_redirect_port tcp_no_redir_ports udp_no_redir_ports tcp_proxy_drop_ports udp_proxy_drop_ports tcp_redir_ports udp_redir_ports tcp_node udp_node interface
- unset tcp_port udp_port tcp_node_remark udp_node_remark _acl_list use_shunt_tcp use_shunt_udp
+ unset tcp_port udp_port tcp_node_remark udp_node_remark _acl_list use_shunt_tcp use_shunt_udp dns_redirect
done
}
@@ -505,10 +506,11 @@ load_acl() {
$ip6t_m -A PSW $(comment "默认") -p udp --dport 53 -j RETURN 2>/dev/null
$ipt_m -A PSW $(comment "默认") -p tcp --dport 53 -j RETURN
$ip6t_m -A PSW $(comment "默认") -p tcp --dport 53 -j RETURN 2>/dev/null
- $ipt_n -A PSW_DNS $(comment "默认") -p udp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
- $ip6t_n -A PSW_DNS $(comment "默认") -p udp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
- $ipt_n -A PSW_DNS $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
- $ip6t_n -A PSW_DNS $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
+ #Only hijack when dest address is local IP
+ $ipt_n -A PSW_DNS $(comment "默认") -p udp $(dst $IPSET_LOCALLIST) --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
+ $ip6t_n -A PSW_DNS $(comment "默认") -p udp $(dst $IPSET_LOCALLIST6) --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
+ $ipt_n -A PSW_DNS $(comment "默认") -p tcp $(dst $IPSET_LOCALLIST) --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
+ $ip6t_n -A PSW_DNS $(comment "默认") -p tcp $(dst $IPSET_LOCALLIST6) --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
}
fi
@@ -762,6 +764,7 @@ filter_node() {
add_firewall_rule() {
echolog "开始加载防火墙规则..."
+ ipset -! create $IPSET_LOCALLIST nethash maxelem 1048576
ipset -! create $IPSET_LANLIST nethash maxelem 1048576
ipset -! create $IPSET_VPSLIST nethash maxelem 1048576
ipset -! create $IPSET_SHUNTLIST nethash maxelem 1048576 timeout 172800
@@ -771,6 +774,7 @@ add_firewall_rule() {
ipset -! create $IPSET_WHITELIST nethash maxelem 1048576 timeout 172800
ipset -! create $IPSET_BLOCKLIST nethash maxelem 1048576 timeout 172800
+ ipset -! create $IPSET_LOCALLIST6 nethash family inet6 maxelem 1048576
ipset -! create $IPSET_LANLIST6 nethash family inet6 maxelem 1048576
ipset -! create $IPSET_VPSLIST6 nethash family inet6 maxelem 1048576
ipset -! create $IPSET_SHUNTLIST6 nethash family inet6 maxelem 1048576 timeout 172800
@@ -869,6 +873,14 @@ add_firewall_rule() {
echolog " - [$?]解析并加入[分流节点] GeoIP 到 IPSET 完成"
fi
}
+
+ ipset -! -R <<-EOF
+ $(ip address show | grep -w "inet" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/^/add $IPSET_LOCALLIST /")
+ EOF
+
+ ipset -! -R <<-EOF
+ $(ip address show | grep -w "inet6" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/^/add $IPSET_LOCALLIST6 /")
+ EOF
#局域网IP列表
ipset -! -R <<-EOF
@@ -1118,6 +1130,7 @@ add_firewall_rule() {
if ([ "$TCP_NODE" != "nil" ] && [ -n "${LOCALHOST_TCP_PROXY_MODE}" ]) || ([ "$UDP_NODE" != "nil" ] && [ -n "${LOCALHOST_UDP_PROXY_MODE}" ]); then
[ -n "$DNS_REDIRECT_PORT" ] && {
+ #Only hijack when dest address is local IP
$ipt_n -A OUTPUT $(comment "PSW") -p udp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
$ip6t_n -A OUTPUT $(comment "PSW") -p udp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
$ipt_n -A OUTPUT $(comment "PSW") -p tcp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
@@ -1328,6 +1341,7 @@ del_firewall_rule() {
ip -6 rule del fwmark 1 table 100 2>/dev/null
ip -6 route del local ::/0 dev lo table 100 2>/dev/null
+ destroy_ipset $IPSET_LOCALLIST
destroy_ipset $IPSET_LANLIST
destroy_ipset $IPSET_VPSLIST
destroy_ipset $IPSET_SHUNTLIST
@@ -1337,6 +1351,7 @@ del_firewall_rule() {
destroy_ipset $IPSET_BLOCKLIST
destroy_ipset $IPSET_WHITELIST
+ destroy_ipset $IPSET_LOCALLIST6
destroy_ipset $IPSET_LANLIST6
destroy_ipset $IPSET_VPSLIST6
destroy_ipset $IPSET_SHUNTLIST6
diff --git a/luci-app-passwall/root/usr/share/passwall/nftables.sh b/luci-app-passwall/root/usr/share/passwall/nftables.sh
index dd1717bed..76703bcc8 100755
--- a/luci-app-passwall/root/usr/share/passwall/nftables.sh
+++ b/luci-app-passwall/root/usr/share/passwall/nftables.sh
@@ -3,6 +3,7 @@
DIR="$(cd "$(dirname "$0")" && pwd)"
MY_PATH=$DIR/nftables.sh
NFTABLE_NAME="inet passwall"
+NFTSET_LOCALLIST="passwall_locallist"
NFTSET_LANLIST="passwall_lanlist"
NFTSET_VPSLIST="passwall_vpslist"
NFTSET_SHUNTLIST="passwall_shuntlist"
@@ -12,6 +13,7 @@ NFTSET_BLACKLIST="passwall_blacklist"
NFTSET_WHITELIST="passwall_whitelist"
NFTSET_BLOCKLIST="passwall_blocklist"
+NFTSET_LOCALLIST6="passwall_locallist6"
NFTSET_LANLIST6="passwall_lanlist6"
NFTSET_VPSLIST6="passwall_vpslist6"
NFTSET_SHUNTLIST6="passwall_shuntlist6"
@@ -371,22 +373,21 @@ load_acl() {
fi
}
+ local dns_redirect
if ([ -n "$tcp_port" ] && [ -n "${tcp_proxy_mode}" ]) || ([ -n "$udp_port" ] && [ -n "${udp_proxy_mode}" ]); then
- [ -n "$dns_redirect_port" ] && {
- nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
- }
+ [ -n "${dns_redirect_port}" ] && dns_redirect=${dns_redirect_port}
else
- nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\""
- nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\""
+ [ -n "${DIRECT_DNSMASQ_PORT}" ] && dns_redirect=${DIRECT_DNSMASQ_PORT}
+ fi
+ if [ -n "${dns_redirect}" ]; then
+ nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\""
+ nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\""
+ nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\""
+ nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\""
+ nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp ${_ipt_source} udp dport 53 ip daddr @$NFTSET_LOCALLIST counter redirect to :${dns_redirect} comment \"$remarks\""
+ nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp ${_ipt_source} tcp dport 53 ip daddr @$NFTSET_LOCALLIST counter redirect to :${dns_redirect} comment \"$remarks\""
+ nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp ${_ipt_source} udp dport 53 ip6 daddr @$NFTSET_LOCALLIST6 counter redirect to :${dns_redirect} comment \"$remarks\""
+ nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 ip6 daddr @$NFTSET_LOCALLIST6 counter redirect to :${dns_redirect} comment \"$remarks\""
fi
[ -n "$tcp_port" -o -n "$udp_port" ] && {
@@ -524,7 +525,7 @@ load_acl() {
unset nft_chain nft_j _ipt_source msg msg2
done
unset enabled sid remarks sources use_global_config use_direct_list use_proxy_list use_block_list use_gfw_list chn_list tcp_proxy_mode udp_proxy_mode dns_redirect_port tcp_no_redir_ports udp_no_redir_ports tcp_proxy_drop_ports udp_proxy_drop_ports tcp_redir_ports udp_redir_ports tcp_node udp_node interface
- unset tcp_port udp_port tcp_node_remark udp_node_remark _acl_list use_shunt_tcp use_shunt_udp
+ unset tcp_port udp_port tcp_node_remark udp_node_remark _acl_list use_shunt_tcp use_shunt_udp dns_redirect
done
}
@@ -554,14 +555,15 @@ load_acl() {
if ([ "$TCP_NODE" != "nil" ] && [ -n "${TCP_PROXY_MODE}" ]) || ([ "$UDP_NODE" != "nil" ] && [ -n "${UDP_PROXY_MODE}" ]); then
[ -n "$DNS_REDIRECT_PORT" ] && {
+ #Only hijack when dest address is local IP
nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp udp dport 53 counter return comment \"默认\""
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp udp dport 53 counter return comment \"默认\""
nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp tcp dport 53 counter return comment \"默认\""
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp tcp dport 53 counter return comment \"默认\""
- nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\""
- nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\""
- nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\""
- nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\""
+ nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp udp dport 53 ip daddr @$NFTSET_LOCALLIST counter redirect to :$DNS_REDIRECT_PORT comment \"默认\""
+ nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp tcp dport 53 ip daddr @$NFTSET_LOCALLIST counter redirect to :$DNS_REDIRECT_PORT comment \"默认\""
+ nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp udp dport 53 ip daddr @$NFTSET_LOCALLIST6 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\""
+ nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp tcp dport 53 ip daddr @$NFTSET_LOCALLIST6 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\""
}
fi
@@ -832,6 +834,7 @@ add_firewall_rule() {
gen_nft_tables
gen_nftset $NFTSET_VPSLIST ipv4_addr 0 0
gen_nftset $NFTSET_GFW ipv4_addr "2d" 0
+ gen_nftset $NFTSET_LOCALLIST ipv4_addr 0 "-1"
gen_nftset $NFTSET_LANLIST ipv4_addr 0 "-1" $(gen_lanlist)
if [ -f $RULES_PATH/chnroute.nft ] && [ -s $RULES_PATH/chnroute.nft ] && [ $(awk 'END{print NR}' $RULES_PATH/chnroute.nft) -ge 8 ]; then
#echolog "使用缓存加载chnroute..."
@@ -846,6 +849,7 @@ add_firewall_rule() {
gen_nftset $NFTSET_VPSLIST6 ipv6_addr 0 0
gen_nftset $NFTSET_GFW6 ipv6_addr "2d" 0
+ gen_nftset $NFTSET_LOCALLIST6 ipv6_addr 0 "-1"
gen_nftset $NFTSET_LANLIST6 ipv6_addr 0 "-1" $(gen_lanlist_6)
if [ -f $RULES_PATH/chnroute6.nft ] && [ -s $RULES_PATH/chnroute6.nft ] && [ $(awk 'END{print NR}' $RULES_PATH/chnroute6.nft) -ge 8 ]; then
#echolog "使用缓存加载chnroute6..."
@@ -945,6 +949,9 @@ add_firewall_rule() {
fi
}
+ insert_nftset $NFTSET_LOCALLIST "-1" $(ip address show | grep -w "inet" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/ /\n/g")
+ insert_nftset $NFTSET_LOCALLIST6 "-1" $(ip address show | grep -w "inet6" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/ /\n/g")
+
# 忽略特殊IP段
local lan_ifname lan_ip
lan_ifname=$(uci -q -p /tmp/state get network.lan.ifname)
@@ -1185,6 +1192,7 @@ add_firewall_rule() {
if ([ "$TCP_NODE" != "nil" ] && [ -n "${LOCALHOST_TCP_PROXY_MODE}" ]) || ([ "$UDP_NODE" != "nil" ] && [ -n "${LOCALHOST_UDP_PROXY_MODE}" ]); then
[ -n "$DNS_REDIRECT_PORT" ] && {
+ #Only hijack when dest address is local IP
nft "add rule $NFTABLE_NAME nat_output ip protocol udp oif lo udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW\""
nft "add rule $NFTABLE_NAME nat_output ip protocol tcp oif lo tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW\""
nft "add rule $NFTABLE_NAME nat_output meta l4proto udp oif lo udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW\""
@@ -1393,6 +1401,7 @@ del_firewall_rule() {
ip -6 rule del fwmark 1 table 100 2>/dev/null
ip -6 route del local ::/0 dev lo table 100 2>/dev/null
+ destroy_nftset $NFTSET_LOCALLIST
destroy_nftset $NFTSET_LANLIST
destroy_nftset $NFTSET_VPSLIST
destroy_nftset $NFTSET_SHUNTLIST
@@ -1402,6 +1411,7 @@ del_firewall_rule() {
destroy_nftset $NFTSET_BLOCKLIST
destroy_nftset $NFTSET_WHITELIST
+ destroy_nftset $NFTSET_LOCALLIST6
destroy_nftset $NFTSET_LANLIST6
destroy_nftset $NFTSET_VPSLIST6
destroy_nftset $NFTSET_SHUNTLIST6
diff --git a/luci-app-ubuntu2/Makefile b/luci-app-ubuntu2/Makefile
new file mode 100644
index 000000000..3a7c00de1
--- /dev/null
+++ b/luci-app-ubuntu2/Makefile
@@ -0,0 +1,24 @@
+
+
+include $(TOPDIR)/rules.mk
+
+PKG_VERSION:=1.0.3-20241215
+PKG_RELEASE:=
+
+LUCI_TITLE:=LuCI support for Ubuntu2
+LUCI_PKGARCH:=all
+LUCI_DEPENDS:=+lsblk +docker +dockerd +luci-lib-taskd
+
+define Package/luci-app-ubuntu2/conffiles
+/etc/config/ubuntu2
+endef
+
+define Package/luci-app-ubuntu2/prerm
+#!/bin/sh
+/usr/libexec/istorec/ubuntu2.sh stop
+exit 0
+endef
+
+include $(TOPDIR)/feeds/luci/luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/luci-app-ubuntu2/luasrc/controller/ubuntu2.lua b/luci-app-ubuntu2/luasrc/controller/ubuntu2.lua
new file mode 100755
index 000000000..41eb7c3fb
--- /dev/null
+++ b/luci-app-ubuntu2/luasrc/controller/ubuntu2.lua
@@ -0,0 +1,7 @@
+
+module("luci.controller.ubuntu2", package.seeall)
+
+function index()
+ entry({"admin", "services", "ubuntu2"}, alias("admin", "services", "ubuntu2", "config"), _("Ubuntu2"), 30).dependent = true
+ entry({"admin", "services", "ubuntu2", "config"}, cbi("ubuntu2"))
+end
diff --git a/luci-app-ubuntu2/luasrc/model/cbi/ubuntu2.lua b/luci-app-ubuntu2/luasrc/model/cbi/ubuntu2.lua
new file mode 100644
index 000000000..754d44358
--- /dev/null
+++ b/luci-app-ubuntu2/luasrc/model/cbi/ubuntu2.lua
@@ -0,0 +1,63 @@
+--[[
+LuCI - Lua Configuration Interface
+]]--
+
+local taskd = require "luci.model.tasks"
+local docker = require "luci.docker"
+local ubuntu2_model = require "luci.model.ubuntu2"
+local m, s, o
+
+m = taskd.docker_map("ubuntu2", "ubuntu2", "/usr/libexec/istorec/ubuntu2.sh",
+ translate("Ubuntu2"),
+ translate("Ubuntu2 is a high-Performance ubuntu with web remote desktop. [username: abc, password is empty]")
+ .. translate("Official website:") .. ' https://www.kasmweb.com')
+
+local dk = docker.new({socket_path="/var/run/docker.sock"})
+local dockerd_running = dk:_ping().code == 200
+local docker_info = dockerd_running and dk:info().body or {}
+local docker_aspace = 0
+if docker_info.DockerRootDir then
+ local statvfs = nixio.fs.statvfs(docker_info.DockerRootDir)
+ docker_aspace = statvfs and (statvfs.bavail * statvfs.bsize) or 0
+end
+
+s = m:section(SimpleSection, translate("Service Status"), translate("Ubuntu2 status:"))
+s:append(Template("ubuntu2/status"))
+
+s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
+s.addremove=false
+s.anonymous=true
+
+o = s:option(Value, "https_port", translate("HTTPS Port").."*")
+o.default = "3001"
+o.datatype = "port"
+
+o = s:option(Value, "image_name", translate("Image").."*")
+o.rmempty = false
+o.datatype = "string"
+o:value("linkease/desktop-ubuntu2-standard-arm64:latest", "Standard-ARM64")
+o:value("linkease/desktop-ubuntu2-standard-amd64:latest", "Standard-AMD64")
+if "x86_64" == docker_info.Architecture then
+ o.default = "linkease/desktop-ubuntu2-standard-amd64:latest"
+else
+ o.default = "linkease/desktop-ubuntu2-standard-arm64:latest"
+end
+
+o = s:option(Value, "password", "PASSWORD")
+o.password = true
+o.datatype = "string"
+
+local blocks = ubuntu2_model.blocks()
+local home = ubuntu2_model.home()
+
+o = s:option(Value, "config_path", translate("Config path").."*")
+o.rmempty = false
+o.datatype = "string"
+
+local paths, default_path = ubuntu2_model.find_paths(blocks, home, "Configs")
+for _, val in pairs(paths) do
+ o:value(val, val)
+end
+o.default = default_path
+
+return m
diff --git a/luci-app-ubuntu2/luasrc/model/ubuntu2.lua b/luci-app-ubuntu2/luasrc/model/ubuntu2.lua
new file mode 100644
index 000000000..ca73ae84a
--- /dev/null
+++ b/luci-app-ubuntu2/luasrc/model/ubuntu2.lua
@@ -0,0 +1,55 @@
+local util = require "luci.util"
+local jsonc = require "luci.jsonc"
+
+local ubuntu2 = {}
+
+ubuntu2.blocks = function()
+ local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
+ local vals = {}
+ if f then
+ local ret = f:read("*all")
+ f:close()
+ local obj = jsonc.parse(ret)
+ for _, val in pairs(obj["blockdevices"]) do
+ local fsize = val["fssize"]
+ if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
+ -- fsize > 1G
+ vals[#vals+1] = val["mountpoint"]
+ end
+ end
+ end
+ return vals
+end
+
+ubuntu2.home = function()
+ local uci = require "luci.model.uci".cursor()
+ local home_dirs = {}
+ home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
+ home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
+ home_dirs["Public"] = uci:get_first("quickstart", "main", "pub_dir", home_dirs["main_dir"].."/Public")
+ home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["Public"].."/Downloads")
+ home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
+ return home_dirs
+end
+
+ubuntu2.find_paths = function(blocks, home_dirs, path_name)
+ local default_path = ''
+ local configs = {}
+
+ default_path = home_dirs[path_name] .. "/Ubuntu2"
+ if #blocks == 0 then
+ table.insert(configs, default_path)
+ else
+ for _, val in pairs(blocks) do
+ table.insert(configs, val .. "/" .. path_name .. "/Ubuntu2")
+ end
+ local without_conf_dir = "/root/" .. path_name .. "/Ubuntu2"
+ if default_path == without_conf_dir then
+ default_path = configs[1]
+ end
+ end
+
+ return configs, default_path
+end
+
+return ubuntu2
diff --git a/luci-app-ubuntu2/luasrc/view/ubuntu2/status.htm b/luci-app-ubuntu2/luasrc/view/ubuntu2/status.htm
new file mode 100644
index 000000000..b28901828
--- /dev/null
+++ b/luci-app-ubuntu2/luasrc/view/ubuntu2/status.htm
@@ -0,0 +1,31 @@
+<%
+local util = require "luci.util"
+local container_status = util.trim(util.exec("/usr/libexec/istorec/ubuntu2.sh status"))
+local container_install = (string.len(container_status) > 0)
+local container_running = container_status == "running"
+-%>
+
+
+
+ <% if container_running then %>
+
+ <% else %>
+
+ <% end %>
+
+
+<%
+if container_running then
+ local port=util.trim(util.exec("/usr/libexec/istorec/ubuntu2.sh port"))
+ if port == "" then
+ port="8096"
+ end
+-%>
+
+
+
+
+
+
+
+<% end %>
diff --git a/luci-app-ubuntu2/po/zh-cn/ubuntu2.po b/luci-app-ubuntu2/po/zh-cn/ubuntu2.po
new file mode 100644
index 000000000..5f03c0997
--- /dev/null
+++ b/luci-app-ubuntu2/po/zh-cn/ubuntu2.po
@@ -0,0 +1,38 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+msgid "Official website:"
+msgstr "官方网站:"
+
+msgid "Ubuntu2 is a high-Performance ubuntu with web remote desktop. [username: abc, password is empty]"
+msgstr "Ubuntu2 是带浏览器桌面的高性能 Ubuntu. [用户名: abc, 密码为空]。"
+
+msgid "Config path"
+msgstr "配置文件路径"
+
+msgid "HTTPS Port"
+msgstr "HTTPS 端口"
+
+msgid "Service Status"
+msgstr "服务状态"
+
+msgid "Ubuntu2 status:"
+msgstr "Ubuntu2 的状态信息如下:"
+
+msgid "Setup"
+msgstr "安装配置"
+
+msgid "The following parameters will only take effect during installation or upgrade:"
+msgstr "以下参数只在安装或者升级时才会生效:"
+
+msgid "Status"
+msgstr "状态"
+
+msgid "Ubuntu2 is running"
+msgstr "Ubuntu2 运行中"
+
+msgid "Ubuntu2 is not running"
+msgstr "Ubuntu2 未运行"
+
+msgid "Open Ubuntu2"
+msgstr "打开 Ubuntu2"
diff --git a/luci-app-ubuntu2/po/zh_Hans b/luci-app-ubuntu2/po/zh_Hans
new file mode 120000
index 000000000..41451e4a1
--- /dev/null
+++ b/luci-app-ubuntu2/po/zh_Hans
@@ -0,0 +1 @@
+zh-cn
\ No newline at end of file
diff --git a/luci-app-ubuntu2/root/etc/config/ubuntu2 b/luci-app-ubuntu2/root/etc/config/ubuntu2
new file mode 100644
index 000000000..1ef2ec380
--- /dev/null
+++ b/luci-app-ubuntu2/root/etc/config/ubuntu2
@@ -0,0 +1,3 @@
+config main
+ # option 'config_path' ''
+
diff --git a/luci-app-ubuntu2/root/usr/libexec/istorec/ubuntu2.sh b/luci-app-ubuntu2/root/usr/libexec/istorec/ubuntu2.sh
new file mode 100755
index 000000000..574174700
--- /dev/null
+++ b/luci-app-ubuntu2/root/usr/libexec/istorec/ubuntu2.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Author Xiaobao(xiaobao@linkease.com)
+
+ACTION=${1}
+shift 1
+
+do_install() {
+ local https_port=`uci get ubuntu2.@main[0].https_port 2>/dev/null`
+ local image_name=`uci get ubuntu2.@main[0].image_name 2>/dev/null`
+ local config=`uci get ubuntu2.@main[0].config_path 2>/dev/null`
+ if [ -z ${IMAGE_NAME} ]; then
+ local arch=`uname -m`
+ if [ "$arch" = "x86_64" ]; then
+ IMAGE_NAME=linkease/desktop-ubuntu2-standard-amd64:latest
+ else
+ IMAGE_NAME=linkease/desktop-ubuntu2-standard-arm64:latest
+ fi
+ fi
+
+ echo "docker pull ${image_name}"
+ docker pull ${image_name}
+ docker rm -f ubuntu2
+
+ if [ -z "$config" ]; then
+ echo "config path is empty!"
+ exit 1
+ fi
+
+ # not conflict with jellyfin
+ [ -z "$https_port" ] && https_port=3001
+
+ local cmd="docker run --restart=unless-stopped -d --user 0:0 -e START_DOCKER=false -v \"$config:/config\" \
+ --privileged --device /dev/fuse --security-opt apparmor=unconfined --shm-size=512m \
+ -v /var/run/docker.sock:/var/run/docker.sock \
+ --dns=172.17.0.1 \
+ -p $https_port:3001 "
+
+ if [ -d /dev/dri ]; then
+ cmd="$cmd\
+ --device /dev/dri:/dev/dri "
+ fi
+
+ local tz="`uci get system.@system[0].zonename | sed 's/ /_/g'`"
+ [ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
+
+ cmd="$cmd -v /mnt:/mnt"
+ mountpoint -q /mnt && cmd="$cmd:rslave"
+ cmd="$cmd --name ubuntu2 \"$image_name\""
+
+ echo "$cmd"
+ eval "$cmd"
+}
+
+usage() {
+ echo "usage: $0 sub-command"
+ echo "where sub-command is one of:"
+ echo " install Install the ubuntu2"
+ echo " upgrade Upgrade the ubuntu2"
+ echo " rm/start/stop/restart Remove/Start/Stop/Restart the ubuntu2"
+ echo " status Ubuntu2 status"
+ echo " port Ubuntu2 port"
+}
+
+case ${ACTION} in
+ "install")
+ do_install
+ ;;
+ "upgrade")
+ do_install
+ ;;
+ "rm")
+ docker rm -f ubuntu2
+ ;;
+ "start" | "stop" | "restart")
+ docker ${ACTION} ubuntu2
+ ;;
+ "status")
+ docker ps --all -f 'name=^/ubuntu2$' --format '{{.State}}'
+ ;;
+ "port")
+ docker ps --all -f 'name=^/ubuntu2$' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*->3001/tcp' | sed 's/0.0.0.0:\([0-9]*\)->.*/\1/'
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac
diff --git a/luci-app-ubuntu2/root/usr/share/rpcd/acl.d/luci-app-ubuntu2.json b/luci-app-ubuntu2/root/usr/share/rpcd/acl.d/luci-app-ubuntu2.json
new file mode 100644
index 000000000..9013d6b96
--- /dev/null
+++ b/luci-app-ubuntu2/root/usr/share/rpcd/acl.d/luci-app-ubuntu2.json
@@ -0,0 +1,11 @@
+{
+ "luci-app-ubuntu2": {
+ "description": "Grant UCI access for luci-app-ubuntu2",
+ "read": {
+ "uci": [ "ubuntu2" ]
+ },
+ "write": {
+ "uci": [ "ubuntu2" ]
+ }
+ }
+}