diff --git a/agentflow/Makefile b/agentflow/Makefile new file mode 100644 index 00000000..d24ddd49 --- /dev/null +++ b/agentflow/Makefile @@ -0,0 +1,75 @@ +# +# Copyright (C) 2026 jjm2473@gmail.com +# +# This is free software, licensed under the GNU General Public License v3. +# + +include $(TOPDIR)/rules.mk + +AGENTFLOW_ARCH_x86_64:=amd64 +AGENTFLOW_ARCH_aarch64:=arm64 +AGENTFLOW_ARCH:=$(AGENTFLOW_ARCH_$(ARCH)) + +AGENTFLOW_HASH_x86_64:=8ba4f42dc45a38ee54d9716cbe39201bb3d9e947c4a6075d9d7af999ab5d098e +AGENTFLOW_HASH_aarch64:=beb19ca378ea1f15a90a907c4de3244353188cf01287b85bfea68b80b1ed8925 + +PKG_NAME:=agentflow +PKG_VERSION:=0.3.0-20260824-c588d794 +PKG_RELEASE:=1 + +AGENTFLOW_SOURCE:=agentflow-linux-$(AGENTFLOW_ARCH) +AGENTFLOW_DOWNLOAD:=$(PKG_NAME)-$(PKG_VERSION)-linux-$(AGENTFLOW_ARCH) +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_BUILD_PARALLEL:=1 +PKG_USE_MIPS16:=0 +STRIP:=true +RSTRIP:=: + +include $(INCLUDE_DIR)/package.mk + +define Download/agentflow + URL:=https://fw.koolcenter.com/binary/geili/agentflow/build/ + URL_FILE:=$(AGENTFLOW_SOURCE) + FILE:=$(AGENTFLOW_DOWNLOAD) + HASH:=skip +endef + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=AgentFlow + DEPENDS:=@(x86_64||aarch64) +git +mise + URL:=https://agentflow.geili.ai/ +endef + +define Package/$(PKG_NAME)/description + AgentFlow provides a Web UI for orchestrating coding agents and workflows. +endef + +define Package/$(PKG_NAME)/conffiles +/etc/config/agentflow +endef + +define Build/Prepare + $(INSTALL_DIR) $(PKG_BUILD_DIR) + $(CP) $(DL_DIR)/$(AGENTFLOW_DOWNLOAD) $(PKG_BUILD_DIR)/agentflow +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin $(1)/etc/init.d $(1)/etc/uci-defaults $(1)/etc/config + $(INSTALL_BIN) $(PKG_BUILD_DIR)/agentflow $(1)/usr/bin/agentflow + $(INSTALL_BIN) ./files/agentflow.init $(1)/etc/init.d/agentflow + $(INSTALL_BIN) ./files/agentflow.uci-default $(1)/etc/uci-defaults/09-agentflow + $(INSTALL_CONF) ./files/agentflow.config $(1)/etc/config/agentflow +endef + +$(eval $(call Download,agentflow)) +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/agentflow/files/agentflow.config b/agentflow/files/agentflow.config new file mode 100644 index 00000000..5d44907d --- /dev/null +++ b/agentflow/files/agentflow.config @@ -0,0 +1,5 @@ +config agentflow + option enabled '0' + option data_dir '' + option host '0.0.0.0' + option port '9000' diff --git a/agentflow/files/agentflow.init b/agentflow/files/agentflow.init new file mode 100644 index 00000000..76a7a8ac --- /dev/null +++ b/agentflow/files/agentflow.init @@ -0,0 +1,51 @@ +#!/bin/sh /etc/rc.common + +START=93 +USE_PROCD=1 + +get_config() { + config_get_bool enabled "$1" enabled 0 + config_get data_dir "$1" data_dir "" + config_get host "$1" host "0.0.0.0" + config_get port "$1" port "9000" +} + +set_mise_env() { + procd_set_param env \ + "$@" \ + MISE_INSTALLS_DIR="$data_dir/globalmise/mise-installs" \ + MISE_DATA_DIR="$data_dir/globalmise/mise-data" \ + MISE_CACHE_DIR="$data_dir/globalmise/mise-cache" \ + MISE_STATE_DIR="$data_dir/globalmise/mise-state" \ + NPM_CONFIG_CACHE="$data_dir/globalmise/npm-cache" \ + NPM_CONFIG_USERCONFIG="$data_dir/globalmise/.npmrc" \ + PATH="$data_dir/globalmise/mise-data/shims:$PATH" +} + +start_service() { + config_load agentflow + config_foreach get_config agentflow + [ "$enabled" = 1 ] || return 1 + + [ -x /usr/bin/agentflow ] || { + logger -t agentflow "missing executable: /usr/bin/agentflow" + return 1 + } + mkdir -p "$data_dir" || return 1 + + logger -t agentflow "starting AgentFlow on $host:$port" + procd_open_instance + procd_set_param command /usr/bin/agentflow + set_mise_env \ + "AGENT_FLOW_DATA=$data_dir/data" \ + "AGENT_FLOW_HOST=$host" \ + "AGENT_FLOW_PORT=$port" + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_set_param respawn + procd_close_instance +} + +service_triggers() { + procd_add_reload_trigger "agentflow" +} diff --git a/agentflow/files/agentflow.uci-default b/agentflow/files/agentflow.uci-default new file mode 100644 index 00000000..ff88295b --- /dev/null +++ b/agentflow/files/agentflow.uci-default @@ -0,0 +1,21 @@ +#!/bin/sh +[ ! -f "/usr/share/ucitrack/luci-app-agentflow.json" ] && { + cat > /usr/share/ucitrack/luci-app-agentflow.json << EEOF +{ + "config": "agentflow", + "init": "agentflow" +} +EEOF +} + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@agentflow[-1] + add ucitrack agentflow + set ucitrack.@agentflow[-1].init=agentflow + commit ucitrack +EOF + +/etc/init.d/agentflow enable +/etc/init.d/agentflow start + +exit 0 diff --git a/luci-app-agentflow/Makefile b/luci-app-agentflow/Makefile new file mode 100644 index 00000000..f5d112ca --- /dev/null +++ b/luci-app-agentflow/Makefile @@ -0,0 +1,28 @@ +# +# Copyright (C) 2008-2014 The LuCI Team +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=AgentFlow +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 +LUCI_DEPENDS:=+agentflow +luci-compat +LUCI_MINIFY_CSS:=0 +LUCI_MINIFY_JS:=0 + +define Package/luci-app-agentflow/conffiles +/etc/config/agentflow +endef + +define Package/luci-app-agentflow/postrm +#!/bin/sh +rm -f /tmp/luci-indexcache +exit 0 +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-agentflow/luasrc/controller/agentflow.lua b/luci-app-agentflow/luasrc/controller/agentflow.lua new file mode 100644 index 00000000..0b3db98f --- /dev/null +++ b/luci-app-agentflow/luasrc/controller/agentflow.lua @@ -0,0 +1,29 @@ +local http = require "luci.http" + +module("luci.controller.agentflow", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/agentflow") then + return + end + + local page = entry({"admin", "services", "agentflow"}, cbi("agentflow"), _("AgentFlow"), 100) + page.dependent = true + entry({"admin", "services", "agentflow_status"}, call("agentflow_status")) +end + +function agentflow_status() + local sys = require "luci.sys" + local uci = require "luci.model.uci".cursor() + local port = tonumber(uci:get_first("agentflow", "agentflow", "port")) or 9000 + if port < 1 or port > 65535 then + port = 9000 + end + + local status = { + running = (sys.call("pidof agentflow >/dev/null") == 0), + port = port + } + http.prepare_content("application/json") + http.write_json(status) +end diff --git a/luci-app-agentflow/luasrc/model/agentflow.lua b/luci-app-agentflow/luasrc/model/agentflow.lua new file mode 100644 index 00000000..aff07a2f --- /dev/null +++ b/luci-app-agentflow/luasrc/model/agentflow.lua @@ -0,0 +1,48 @@ +local jsonc = require "luci.jsonc" + +local agentflow = {} + +agentflow.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 and obj["blockdevices"] or {}) do + local fsize = val["fssize"] + if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then + vals[#vals + 1] = val["mountpoint"] + end + end + end + return vals +end + +agentflow.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") + return home_dirs +end + +agentflow.find_paths = function(blocks, home_dirs) + local default_path = home_dirs["Configs"] .. "/AgentFlow" + local paths = {} + + if #blocks == 0 then + table.insert(paths, default_path) + else + for _, val in pairs(blocks) do + table.insert(paths, val .. "/Configs/AgentFlow") + end + if default_path == "/root/Configs/AgentFlow" then + default_path = paths[1] + end + end + + return paths, default_path +end + +return agentflow diff --git a/luci-app-agentflow/luasrc/model/cbi/agentflow.lua b/luci-app-agentflow/luasrc/model/cbi/agentflow.lua new file mode 100644 index 00000000..3fa03818 --- /dev/null +++ b/luci-app-agentflow/luasrc/model/cbi/agentflow.lua @@ -0,0 +1,32 @@ +local m, s + +m = Map("agentflow", translate("AgentFlow"), translate("AgentFlow provides a Web UI for orchestrating coding agents and workflows.")) +m:section(SimpleSection).template = "agentflow/status" + +s = m:section(TypedSection, "agentflow", translate("Global settings")) +s.addremove = false +s.anonymous = true + +s:option(Flag, "enabled", translate("Enable")).rmempty = false + +local agentflow_model = require "luci.model.agentflow" +local blocks = agentflow_model.blocks() +local home = agentflow_model.home() + +local data_dir = s:option(Value, "data_dir", translate("Data directory")) +data_dir.rmempty = false +data_dir.description = translate("Required. AgentFlow stores its configuration, database and workspace data under this directory.") + +local paths, default_path = agentflow_model.find_paths(blocks, home) +for _, val in pairs(paths) do + data_dir:value(val, val) +end +data_dir.default = default_path + +local port = s:option(Value, "port", translate("Listen port")) +port.default = "9000" +port.rmempty = false +port.datatype = "port" +port.description = translate("Port for the AgentFlow HTTP server.") + +return m diff --git a/luci-app-agentflow/luasrc/view/agentflow/status.htm b/luci-app-agentflow/luasrc/view/agentflow/status.htm new file mode 100644 index 00000000..6747f6e1 --- /dev/null +++ b/luci-app-agentflow/luasrc/view/agentflow/status.htm @@ -0,0 +1,20 @@ + + +
+ <%:Status%> +

+ <%:Collecting data...%> +

+
diff --git a/luci-app-agentflow/po/zh-cn/agentflow.po b/luci-app-agentflow/po/zh-cn/agentflow.po new file mode 100644 index 00000000..adda11a5 --- /dev/null +++ b/luci-app-agentflow/po/zh-cn/agentflow.po @@ -0,0 +1,41 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "AgentFlow" +msgstr "AgentFlow" + +msgid "AgentFlow provides a Web UI for orchestrating coding agents and workflows." +msgstr "AgentFlow 提供用于编排编码智能体和工作流的 Web 管理界面。" + +msgid "Click to open AgentFlow" +msgstr "点击打开 AgentFlow" + +msgid "Collecting data..." +msgstr "正在获取数据……" + +msgid "Data directory" +msgstr "数据目录" + +msgid "Enable" +msgstr "启用" + +msgid "Global settings" +msgstr "全局设置" + +msgid "Listen port" +msgstr "监听端口" + +msgid "Port for the AgentFlow HTTP server." +msgstr "AgentFlow HTTP 服务的端口号。" + +msgid "Required. AgentFlow stores its configuration, database and workspace data under this directory." +msgstr "必需。AgentFlow 在此目录中保存配置、数据库和工作区数据。" + +msgid "Status" +msgstr "状态" + +msgid "The AgentFlow service is not running." +msgstr "AgentFlow 服务未运行。" + +msgid "The AgentFlow service is running." +msgstr "AgentFlow 服务运行中。" diff --git a/luci-app-agentflow/po/zh_Hans b/luci-app-agentflow/po/zh_Hans new file mode 120000 index 00000000..41451e4a --- /dev/null +++ b/luci-app-agentflow/po/zh_Hans @@ -0,0 +1 @@ +zh-cn \ No newline at end of file diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 29f2e2c2..62738c38 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=26.8.27 -PKG_RELEASE:=104 +PKG_RELEASE:=105 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/controller/passwall2.lua b/luci-app-passwall2/luasrc/controller/passwall2.lua index 87495e5d..fa5eac52 100644 --- a/luci-app-passwall2/luasrc/controller/passwall2.lua +++ b/luci-app-passwall2/luasrc/controller/passwall2.lua @@ -685,6 +685,8 @@ function rollback_rules() local geo_dir = (uci_get("@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/") fs.move(bak_dir .. arg_type .. ".dat", geo_dir .. arg_type .. ".dat") fs.rmdir(bak_dir) + uci_set("@global[0]", "flush_set", "1") + uci_save(true) http_write_json_ok() end diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua index 626df1ed..5613523e 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua @@ -164,6 +164,22 @@ node_socks_bind_local:depends({ node = "", ["!reverse"] = true }) s:tab("DNS", translate("DNS")) +o = s:taboption("DNS", ListValue, "direct_dns_protocol", translate("Direct DNS Protocol")) +o:value("", translate("Auto")) +--o:value("tcp", "TCP") +o:value("udp", "UDP") + +o = s:taboption("DNS", Value, "direct_dns", translate("Direct DNS")) +o.datatype = "or(ipaddr,ipaddrport(1))" +o.default = "223.5.5.5" +o:value("223.5.5.5") +o:value("223.6.6.6") +o:value("114.114.114.114") +o:value("119.29.29.29") +o:value("180.76.76.76") +o:depends("direct_dns_protocol", "tcp") +o:depends("direct_dns_protocol", "udp") + o = s:taboption("DNS", ListValue, "direct_dns_query_strategy", translate("Direct Query Strategy")) o.default = "UseIP" o:value("UseIP") diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua index 5f5e293a..b20cb459 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/1_sing-box.lua @@ -419,6 +419,10 @@ if singbox_tags:find("with_quic") then o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } o:depends({ hysteria2_realms = "1" }) + o = s:option(Flag, "hysteria2_realm_upnp", translate("Enable") .. " UPnP/NAT-PMP", translate("Enable UPnP/NAT-PMP port mapping on your gateway to improve hole punching success.")) + o.default = "0" + o:depends({ hysteria2_realms = "1" }) + o = s:option(Value, "hysteria2_auth_password", translate("Auth Password")) o.password = true o:depends({ protocol = "hysteria2"}) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/2_xray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/2_xray.lua index e0d75ec3..a7af606e 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/2_xray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/2_xray.lua @@ -355,6 +355,10 @@ o = s:option(DynamicList, "hysteria2_realm_stun", translate("Realm STUN")) o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } o:depends({ hysteria2_realms = "1" }) +o = s:option(Flag, "hysteria2_realm_upnp", translate("Enable") .. " UPnP/NAT-PMP", translate("Enable UPnP/NAT-PMP port mapping on your gateway to improve hole punching success.")) +o.default = "0" +o:depends({ hysteria2_realms = "1" }) + o = s:option(Value, "hysteria2_auth_password", translate("Auth Password")) o.password = true o:depends({ protocol = "hysteria2"}) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/1_sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/1_sing-box.lua index 1b1aa00e..4550426a 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/1_sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/1_sing-box.lua @@ -183,6 +183,10 @@ if singbox_tags:find("with_quic") then o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } o:depends({ hysteria2_realms = "1" }) + o = s:option(Flag, "hysteria2_realm_upnp", translate("Enable") .. " UPnP/NAT-PMP", translate("Enable UPnP/NAT-PMP port mapping on your gateway to improve hole punching success.")) + o.default = "0" + o:depends({ hysteria2_realms = "1" }) + o = s:option(ListValue, "hysteria2_obfs_type", translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/2_xray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/2_xray.lua index f875bce2..6db31a19 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/2_xray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/2_xray.lua @@ -148,6 +148,10 @@ o = s:option(DynamicList, "hysteria2_realm_stun", translate("Realm STUN")) o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } o:depends({ hysteria2_realms = "1" }) +o = s:option(Flag, "hysteria2_realm_upnp", translate("Enable") .. " UPnP/NAT-PMP", translate("Enable UPnP/NAT-PMP port mapping on your gateway to improve hole punching success.")) +o.default = "0" +o:depends({ hysteria2_realms = "1" }) + o = s:option(ListValue, "hysteria2_obfs_type", translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") diff --git a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index 60ca9297..7edf3221 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -68,13 +68,6 @@ local function convert_geofile() end local function convert(file_path, prefix, tags) if next(tags) and fs.access(file_path) then - local md5_file = GEO_VAR.TO_SRS_PATH .. prefix .. ".dat.md5" - local new_md5 = sys.exec("md5sum " .. file_path .. " 2>/dev/null | awk '{print $1}'"):gsub("\n", "") - local old_md5 = sys.exec("[ -f " .. md5_file .. " ] && head -n 1 " .. md5_file .. " | tr -d ' \t\n' || echo ''") - if new_md5 ~= "" and new_md5 ~= old_md5 then - sys.call("printf '%s' " .. new_md5 .. " > " .. md5_file) - sys.call("rm -rf " .. GEO_VAR.TO_SRS_PATH .. prefix .. "-*.srs" ) - end for k in pairs(tags) do geo_convert_srs({ ["geo_path"] = file_path, @@ -624,6 +617,7 @@ function gen_outbound(flag, node, tag, proxy_table) realm.scheme = nil realm.address = nil realm.port = nil + realm.port_mapping = (node.hysteria2_realm_upnp == "1") and { enabled = true } or nil return realm end return nil @@ -980,6 +974,7 @@ function gen_config_server(node) realm.address = nil realm.port = nil realm.stun_domain_resolver = "direct" + realm.port_mapping = (node.hysteria2_realm_upnp == "1") and { enabled = true } or nil return realm end return nil @@ -1122,6 +1117,8 @@ function gen_config(var) local dns_listen_port = var["dns_listen_port"] local direct_dns_udp_server = var["direct_dns_udp_server"] local direct_dns_udp_port = var["direct_dns_udp_port"] + local direct_dns_tcp_server = var["direct_dns_tcp_server"] + local direct_dns_tcp_port = var["direct_dns_tcp_port"] local direct_dns_query_strategy = var["direct_dns_query_strategy"] local direct_ipset = var["direct_ipset"] local direct_nftset = var["direct_nftset"] @@ -1834,10 +1831,18 @@ function gen_config(var) server_port = tonumber(direct_dns_udp_port) or 53, detour = "direct", }) + elseif direct_dns_tcp_server then + table.insert(dns.servers, { + tag = "direct", + type = "tcp", + server = direct_dns_tcp_server, + server_port = tonumber(direct_dns_tcp_port) or 53, + detour = "direct", + }) end for i, v in pairs(GLOBAL.DNS_SERVER) do - if direct_dns_udp_server then + if direct_dns_udp_server or direct_dns_tcp_server then v.server.domain_resolver = "direct" end table.insert(dns.servers, v.server) @@ -1902,7 +1907,7 @@ function gen_config(var) end end - if direct_dns_udp_server then + if direct_dns_udp_server or direct_dns_tcp_server then local nodes_domain = {} local nodes_domain_text = sys.exec('uci show passwall2 | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u') string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w) @@ -2089,6 +2094,7 @@ function gen_config(var) fakedns_dns_rule.query_type = { "A", "AAAA" } end fakedns_dns_rule.server = fakedns_tag + fakedns_dns_rule.rewrite_ttl = 1 fakedns_dns_rule.disable_cache = true fakedns_dns_rule.client_subnet = nil table.insert(dns.rules, fakedns_dns_rule) @@ -2125,7 +2131,7 @@ function gen_config(var) query_type = dns_rule_query_type, server = fakedns_tag, disable_cache = true, - rewrite_ttl = tonumber(remote_rewrite_ttl) + rewrite_ttl = 1 } table.insert(dns.rules, fakedns_dns_rule) end diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index d9ac06a7..5995737e 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -318,7 +318,8 @@ function gen_outbound(flag, node, tag, proxy_table) type = "realm", settings = { url = url, - stunServers = stun + stunServers = stun, + portMapping = (node.hysteria2_realm_upnp == "1") and { enabled = true } or nil } } udp[#udp+1] = r @@ -788,7 +789,8 @@ function gen_config_server(node) type = "realm", settings = { url = url, - stunServers = stun + stunServers = stun, + portMapping = (node.hysteria2_realm_upnp == "1") and { enabled = true } or nil } } udp[#udp+1] = r @@ -887,6 +889,8 @@ function gen_config(var) local dns_listen_port = var["dns_listen_port"] local direct_dns_udp_server = var["direct_dns_udp_server"] local direct_dns_udp_port = var["direct_dns_udp_port"] + local direct_dns_tcp_server = var["direct_dns_tcp_server"] + local direct_dns_tcp_port = var["direct_dns_tcp_port"] local direct_dns_query_strategy = var["direct_dns_query_strategy"] local direct_ipset = var["direct_ipset"] local direct_nftset = var["direct_nftset"] @@ -1560,13 +1564,24 @@ function gen_config(var) port = tonumber(direct_dns_udp_port) or 53, queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" } - - if _direct_dns.address then - table.insert(dns_servers, { - outboundTag = "direct", - server = _direct_dns - }) + table.insert(dns_servers, { + outboundTag = "direct", + server = _direct_dns + }) + elseif direct_dns_tcp_server then + if api.is_ipv6(direct_dns_tcp_server) then + direct_dns_tcp_server = api.get_ipv6_full(direct_dns_tcp_server) end + _direct_dns = { + tag = direct_dns_tag, + address = "tcp://" .. direct_dns_tcp_server .. ":" .. tonumber(direct_dns_tcp_port) or 53, + port = tonumber(direct_dns_tcp_port) or 53, + queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" + } + table.insert(dns_servers, { + outboundTag = "direct", + server = _direct_dns + }) end if next(GLOBAL.DNS_HOSTNAME) then @@ -1687,7 +1702,7 @@ function gen_config(var) }) end - if direct_dns_udp_server then + if direct_dns_udp_server or direct_dns_tcp_server then local domain = {} local nodes_domain_text = sys.exec('uci show passwall2 | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u') string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w) diff --git a/luci-app-passwall2/luasrc/view/passwall2/cbi/footer.htm b/luci-app-passwall2/luasrc/view/passwall2/cbi/footer.htm index cd0f1609..21667b2b 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/cbi/footer.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/cbi/footer.htm @@ -23,8 +23,8 @@ local map = self.map <% if luci.http.formvalue("cbi.apply") == "1" and map.is_js_luci then -%>