diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua index 111934582..e12665b39 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua @@ -45,11 +45,29 @@ o = s:option(Value, "console_port", translate("Console Port"), translate( o.default = "1188" o:depends("balancing_enable", true) +---- Health Check Type +o = s:option(ListValue, "health_check_type", translate("Health Check Type")) +o:value("tcp", "TCP") +o:value("passwall_logic", translate("Availability test") .. string.format("(passwall %s)", translate("Inner implement"))) +o:depends("balancing_enable", true) + +---- Health Check Inter +o = s:option(Value, "health_check_inter", translate("Health Check Inter"), translate("Units:seconds")) +o.default = "10" +o:depends("balancing_enable", true) + +o = s:option(DummyValue, "health_check_tips", " ") +o.rawhtml = true +o.cfgvalue = function(t, n) + return string.format('%s', translate("When the availability test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid.")) +end +o:depends("health_check_type", "passwall_logic") + -- [[ Balancing Settings ]]-- s = m:section(TypedSection, "haproxy_config", "", "" .. translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") .. - "\n" .. translate("Note that the node configuration parameters for load balancing must be consistent, otherwise problems can arise!") .. + "\n" .. translate("Note that the node configuration parameters for load balancing must be consistent when use TCP health check type, otherwise it cannot be used normally!") .. "") s.template = "cbi/tblsection" s.sortable = true diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index df8508604..f525dcfe5 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -694,11 +694,23 @@ msgstr "在浏览器输入路由IP加端口访问,如:192.168.1.1:1188" msgid "Haproxy Port" msgstr "负载均衡端口" +msgid "Health Check Type" +msgstr "健康检查类型" + +msgid "Inner implement" +msgstr "内置实现" + +msgid "Health Check Inter" +msgstr "健康检查节点间隔时间" + +msgid "When the availability test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid." +msgstr "当使用可用性测试时,负载均衡节点将转换成Socks节点。下面的节点列表自定义时必须为Socks节点,否则健康检查将无效。" + msgid "Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group." msgstr "添加节点,指定出口功能是为多WAN用户准备的。负载比重范围1-256。多个主服务器可以负载均衡,备用只有在主服务器离线时才会启用!可以设置多个组,负载均衡端口相同则为一组。" -msgid "Note that the node configuration parameters for load balancing must be consistent, otherwise problems can arise!" -msgstr "注意,负载均衡的节点配置参数必须一致,否则会出问题!" +msgid "Note that the node configuration parameters for load balancing must be consistent when use TCP health check type, otherwise it cannot be used normally!" +msgstr "注意,当使用TCP健康检查时负载均衡的节点配置参数必须一致,否则无法正常使用!" msgid "Node" msgstr "节点" diff --git a/luci-app-passwall/root/usr/share/passwall/haproxy.lua b/luci-app-passwall/root/usr/share/passwall/haproxy.lua index 5e9d22554..3dd63d1d2 100644 --- a/luci-app-passwall/root/usr/share/passwall/haproxy.lua +++ b/luci-app-passwall/root/usr/share/passwall/haproxy.lua @@ -17,10 +17,24 @@ function get_ip_port_from(str) return result_ip, result_port end +local new_port +local function get_new_port() + if new_port then + new_port = tonumber(sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port %s tcp)", appname, new_port + 1))) + else + new_port = tonumber(sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port auto tcp)", appname))) + end + return new_port +end + local var = api.get_args(arg) local haproxy_path = var["-path"] local haproxy_conf = var["-conf"] +local health_check_type = uci:get(appname, "@global_haproxy[0]", "health_check_type") or "tcp" +local health_check_inter = uci:get(appname, "@global_haproxy[0]", "health_check_inter") or "10" +health_check_inter = tonumber(health_check_inter) * 1000 + log("HAPROXY 负载均衡...") fs.mkdir(haproxy_path) local haproxy_file = haproxy_path .. "/" .. haproxy_conf @@ -30,9 +44,9 @@ local f_out = io.open(haproxy_file, "a") local haproxy_config = [[ global log 127.0.0.1 local2 - chroot %s maxconn 60000 stats socket %s/haproxy.sock +%s daemon defaults @@ -57,31 +71,59 @@ resolvers mydns nameserver dns1 127.0.0.1:53 resolve_retries 3 timeout retry 3s - hold valid 10s + hold valid 30s ]] -f_out:write(string.format(haproxy_config, haproxy_path, haproxy_path)) +f_out:write(string.format(haproxy_config, haproxy_path, health_check_type == "passwall_logic" and string.format([[ + external-check + insecure-fork-wanted +]]) or "" +)) local listens = {} uci:foreach(appname, "haproxy_config", function(t) if t.enabled == "1" then + local server_remark local server_address local server_port local lbss = t.lbss local listen_port = tonumber(t.haproxy_port) or 0 local server_node = uci:get_all(appname, lbss) if server_node and server_node.address and server_node.port then + server_remark = server_node.address .. ":" .. server_node.port server_address = server_node.address server_port = server_node.port + if health_check_type == "passwall_logic" then + if server_node.type ~= "Socks" then + local relay_port = server_node.port + new_port = get_new_port() + local config_file = string.format("haproxy_%s_%s.json", t[".name"], new_port) + sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null', + appname, + string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s", + new_port, --flag + server_node[".name"], --node + "127.0.0.1", --bind + new_port, --socks port + config_file --config file + ) + ) + ) + server_address = "127.0.0.1" + server_port = new_port + end + end else server_address, server_port = get_ip_port_from(lbss) + server_remark = server_address .. ":" .. server_port end if server_address and server_port and listen_port > 0 then if not listens[listen_port] then listens[listen_port] = {} end + t.server_remark = server_remark t.server_address = server_address t.server_port = server_port table.insert(listens[listen_port], t) @@ -109,12 +151,19 @@ listen %s balance roundrobin ]], port, port)) - for i, o in ipairs(listens[port]) do - local server = o.server_address .. ":" .. o.server_port - local remark = server:gsub("%[", ""):gsub("%]", "") + if health_check_type == "passwall_logic" then f_out:write(string.format([[ - server %s %s weight %s check resolvers mydns inter 1500 rise 1 fall 3 %s -]], remark, server, o.lbweight, o.backup == "1" and "backup" or "")) + option external-check + external-check command "/usr/share/passwall/haproxy_check.sh" +]], port, port)) + end + + for i, o in ipairs(listens[port]) do + local remark = o.server_remark + local server = o.server_address .. ":" .. o.server_port + f_out:write(string.format([[ + server %s %s weight %s check resolvers mydns inter %s rise 1 fall 3 %s +]], remark, server, o.lbweight, health_check_inter, o.backup == "1" and "backup" or "")) if o.export ~= "0" then sys.call(string.format("/usr/share/passwall/app.sh add_ip2route %s %s", o.server_address, o.export)) diff --git a/luci-app-passwall/root/usr/share/passwall/haproxy_check.sh b/luci-app-passwall/root/usr/share/passwall/haproxy_check.sh new file mode 100755 index 000000000..870ffb575 --- /dev/null +++ b/luci-app-passwall/root/usr/share/passwall/haproxy_check.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +listen_address=$1 +listen_port=$2 +server_address=$3 +server_port=$4 +status=$(/usr/bin/curl -I -o /dev/null -skL -x socks5h://${server_address}:${server_port} --connect-timeout 3 --retry 3 -w %{http_code} "https://www.google.com/generate_204") +case "$status" in + 204|\ + 200) + status=200 + ;; +esac +return_code=1 +if [ "$status" = "200" ]; then + return_code=0 +fi +exit ${return_code}