From 2b0f1aa628c595256f7b85ffc0e4b8abc50257b7 Mon Sep 17 00:00:00 2001 From: xiaorouji <60100640+xiaorouji@users.noreply.github.com> Date: Mon, 27 Mar 2023 18:26:14 +0800 Subject: [PATCH] luci: refactoring haproxy function --- luci-app-passwall/Makefile | 2 +- .../root/usr/share/passwall/app.sh | 107 +----------- .../root/usr/share/passwall/haproxy.lua | 152 ++++++++++++++++++ 3 files changed, 159 insertions(+), 102 deletions(-) create mode 100644 luci-app-passwall/root/usr/share/passwall/haproxy.lua diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index 0d947c5e1..8eeaf490b 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=4.61 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh index 55b2fd36b..6bdc9a03e 100755 --- a/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/luci-app-passwall/root/usr/share/passwall/app.sh @@ -1213,108 +1213,10 @@ delete_ip2route() { } start_haproxy() { - local haproxy_path haproxy_file item items lport sort_items - - [ "$(config_t_get global_haproxy balancing_enable 0)" != "1" ] && return - echolog "HAPROXY 负载均衡..." - haproxy_path=${TMP_PATH}/haproxy - mkdir -p "${haproxy_path}" - haproxy_file=${haproxy_path}/config.cfg - cat <<-EOF > "${haproxy_file}" - global - log 127.0.0.1 local2 - chroot ${haproxy_path} - maxconn 60000 - stats socket ${haproxy_path}/haproxy.sock - daemon - - defaults - mode tcp - log global - option tcplog - option dontlognull - option http-server-close - #option forwardfor except 127.0.0.0/8 - option redispatch - retries 2 - timeout http-request 10s - timeout queue 1m - timeout connect 10s - timeout client 1m - timeout server 1m - timeout http-keep-alive 10s - timeout check 10s - maxconn 3000 - - EOF - - items=$(uci show ${CONFIG} | grep "=haproxy_config" | cut -d '.' -sf 2 | cut -d '=' -sf 1) - for item in $items; do - lport=$(config_n_get ${item} haproxy_port 0) - [ "${lport}" = "0" ] && echolog " - 丢弃1个明显无效的节点" && continue - sort_items="${sort_items}${IFS}${lport} ${item}" - done - - items=$(echo "${sort_items}" | sort -n | cut -d ' ' -sf 2) - - unset lport - local haproxy_port lbss lbweight export backup remark - local msg bip bport hasvalid bbackup failcount interface - for item in ${items}; do - unset haproxy_port bbackup - - eval $(uci -q show "${CONFIG}.${item}" | cut -d '.' -sf 3-) - [ "$enabled" = "1" ] || continue - get_ip_port_from "$lbss" bip bport 1 - - [ -z "$haproxy_port" ] || [ -z "$bip" ] && echolog " - 丢弃1个明显无效的节点" && continue - [ "$backup" = "1" ] && bbackup="backup" - remark=$(echo $bip | sed "s/\[//g" | sed "s/\]//g") - - [ "$lport" = "${haproxy_port}" ] || { - hasvalid="1" - lport=${haproxy_port} - echolog " + 入口 0.0.0.0:${lport}..." - cat <<-EOF >> "${haproxy_file}" - listen $lport - mode tcp - bind 0.0.0.0:$lport - EOF - } - - cat <<-EOF >> "${haproxy_file}" - server $remark:$bport $bip:$bport weight $lbweight check inter 1500 rise 1 fall 3 $bbackup - EOF - - if [ "$export" != "0" ]; then - add_ip2route ${bip} ${export} > /dev/null 2>&1 & - fi - - haproxy_items="${haproxy_items}${IFS}${bip}:${bport}" - echolog " | - 出口节点:${bip}:${bport},权重:${lbweight}" - done - - # 控制台配置 - local console_port=$(config_t_get global_haproxy console_port) - local console_user=$(config_t_get global_haproxy console_user) - local console_password=$(config_t_get global_haproxy console_password) - local auth="" - [ -n "$console_user" ] && [ -n "$console_password" ] && auth="stats auth $console_user:$console_password" - cat <<-EOF >> "${haproxy_file}" - - listen console - bind 0.0.0.0:$console_port - mode http - stats refresh 30s - stats uri / - stats admin if TRUE - $auth - EOF - - [ "${hasvalid}" != "1" ] && echolog " - 没有发现任何有效节点信息,不启动。" && return 0 - ln_run "$(first_type haproxy)" haproxy "/dev/null" -f "${haproxy_file}" - echolog " * 控制台端口:${console_port}/,${auth:-公开}" + haproxy_conf="config.cfg" + lua $APP_PATH/haproxy.lua -path ${haproxy_path} -conf ${haproxy_conf} + ln_run "$(first_type haproxy)" haproxy "/dev/null" -f "${haproxy_path}/${haproxy_conf}" } kill_all() { @@ -1701,6 +1603,9 @@ mkdir -p /tmp/etc $TMP_PATH $TMP_BIN_PATH $TMP_SCRIPT_FUNC_PATH $TMP_ID_PATH $TM arg1=$1 shift case $arg1 in +add_ip2route) + add_ip2route $@ + ;; get_new_port) get_new_port $@ ;; diff --git a/luci-app-passwall/root/usr/share/passwall/haproxy.lua b/luci-app-passwall/root/usr/share/passwall/haproxy.lua new file mode 100644 index 000000000..30a650a9a --- /dev/null +++ b/luci-app-passwall/root/usr/share/passwall/haproxy.lua @@ -0,0 +1,152 @@ +#!/usr/bin/lua + +local api = require ("luci.passwall.api") +local appname = api.appname +local fs = api.fs +local jsonc = api.jsonc +local uci = api.uci +local sys = api.sys + +if uci:get_first(appname, 'global_haproxy', "balancing_enable", 0) ~= 1 then + return +end + +local log = function(...) + local result = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ") + local f, err = io.open("/tmp/log/passwall.log", "a") + if f and err == nil then + f:write(result .. "\n") + f:close() + end +end + +function get_ip_port_from(str) + local result_port = sys.exec("echo -n " .. str .. " | sed -n 's/^.*[:#]\\([0-9]*\\)$/\\1/p'") + local result_ip = sys.exec(string.format("__host=%s;__varport=%s;", str, result_port) .. "echo -n ${__host%%${__varport:+[:#]${__varport}*}}") + return result_ip, result_port +end + +local var = api.get_args(arg) +local haproxy_path = var["-path"] +local haproxy_conf = var["-conf"] + +log("HAPROXY 负载均衡...") +fs.mkdir(haproxy_path) +local haproxy_file = haproxy_path .. "/" .. haproxy_conf + +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 + daemon + +defaults + mode tcp + log global + option tcplog + option dontlognull + option http-server-close + #option forwardfor except 127.0.0.0/8 + option redispatch + retries 2 + timeout http-request 10s + timeout queue 1m + timeout connect 10s + timeout client 1m + timeout server 1m + timeout http-keep-alive 10s + timeout check 10s + maxconn 3000 + +resolvers mydns + nameserver dns1 127.0.0.1:53 + resolve_retries 3 + timeout retry 3s + hold valid 10s + +]] + +f_out:write(string.format(haproxy_config, haproxy_path, haproxy_path)) + +local listens = {} + +uci:foreach(appname, "haproxy_config", function(t) + if t.enabled == "1" then + 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_address = server_node.address + server_port = server_node.port + else + server_address, server_port = get_ip_port_from(lbss) + end + if server_address and server_port and listen_port > 0 then + if not listens[listen_port] then + listens[listen_port] = {} + end + t.server_address = server_address + t.server_port = server_port + table.insert(listens[listen_port], t) + else + log(" - 丢弃1个明显无效的节点") + end + end +end) + +local sortTable = {} +for i in pairs(listens) do + if i ~= nil then + table.insert(sortTable, i) + end +end +table.sort(sortTable, function(a,b) return (a < b) end) + +for i, port in pairs(sortTable) do + log(" + 入口 0.0.0.0:%s..." % port) + + f_out:write(string.format([[ +listen %s + bind 0.0.0.0:%s + mode tcp + 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("%]", "") + 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 "")) + + if o.export ~= "0" then + sys.call(string.format("/usr/share/passwall/app.sh add_ip2route %s %s", o.server_address, o.export)) + end + + log(string.format(" | - 出口节点:%s:%s,权重:%s", o.server_address, o.server_port, o.lbweight)) + end +end + +--控制台配置 +local console_port = uci:get(appname, "@global_haproxy[0]", "console_port") +local console_user = uci:get(appname, "@global_haproxy[0]", "console_user") +local console_password = uci:get(appname, "@global_haproxy[0]", "console_password") +local str = [[ +listen console + bind 0.0.0.0:%s + mode http + stats refresh 30s + stats uri / + stats admin if TRUE + %s +]] +f_out:write(string.format(str, console_port, (console_user and console_user ~= "" and console_password and console_password ~= "") and "stats auth " .. console_user .. ":" .. console_password or "")) +log(string.format(" * 控制台端口:%s", console_port)) + +f_out:close()