mirror of
https://gitee.com/samwaf/SamWaf.git
synced 2026-10-31 02:01:44 +08:00
136 lines
4.7 KiB
Go
136 lines
4.7 KiB
Go
package wafenginecore
|
||
|
||
import (
|
||
"SamWaf/common/zlog"
|
||
"SamWaf/global"
|
||
"SamWaf/innerbean"
|
||
"SamWaf/model"
|
||
"SamWaf/model/wafenginmodel"
|
||
"SamWaf/wafproxy"
|
||
"context"
|
||
"crypto/tls"
|
||
"net"
|
||
"net/http"
|
||
"net/url"
|
||
"strconv"
|
||
"time"
|
||
)
|
||
|
||
func (waf *WafEngine) ProxyHTTP(w http.ResponseWriter, r *http.Request, host string, remoteUrl *url.URL, clientIp string, ctx context.Context, weblog innerbean.WebLog, hostTarget *wafenginmodel.HostSafe) {
|
||
|
||
//检测是否启动负载
|
||
if hostTarget.Host.IsEnableLoadBalance > 0 {
|
||
lb := &hostTarget.LoadBalanceRuntime
|
||
(*lb).Mux.Lock()
|
||
defer (*lb).Mux.Unlock()
|
||
|
||
if len(hostTarget.LoadBalanceLists) > 0 && len(hostTarget.LoadBalanceRuntime.RevProxies) == 0 {
|
||
for addrIndex, loadBalance := range hostTarget.LoadBalanceLists {
|
||
//初始化后端负载
|
||
zlog.Debug("HTTP REQUEST", weblog.REQ_UUID, weblog.URL, "未初始化")
|
||
transport, customHeaders := waf.createTransport(r, host, 1, loadBalance, hostTarget)
|
||
customConfig := map[string]string{}
|
||
customConfig["IsTransBackDomain"] = strconv.Itoa(hostTarget.Host.IsTransBackDomain)
|
||
proxy := wafproxy.NewSingleHostReverseProxyCustomHeader(remoteUrl, customHeaders, customConfig)
|
||
proxy.Transport = transport
|
||
proxy.ModifyResponse = waf.modifyResponse()
|
||
proxy.ErrorHandler = waf.errorResponse()
|
||
hostTarget.LoadBalanceRuntime.RevProxies = append(hostTarget.LoadBalanceRuntime.RevProxies, proxy)
|
||
|
||
// 初始化策略相关信息
|
||
switch hostTarget.Host.LoadBalanceStage {
|
||
case 1: // 加权轮询(WRR)
|
||
hostTarget.LoadBalanceRuntime.WeightRoundRobinBalance.Add(addrIndex, loadBalance.Weight)
|
||
break
|
||
case 2: // IPHash
|
||
hostTarget.LoadBalanceRuntime.IpHashBalance.Add(strconv.Itoa(addrIndex), 1)
|
||
break
|
||
default:
|
||
http.Error(w, "Invalid Load Balance Stage", http.StatusBadRequest)
|
||
}
|
||
}
|
||
}
|
||
proxyIndex := waf.getProxyIndex(host, clientIp, hostTarget)
|
||
if proxyIndex == -1 {
|
||
http.Error(w, "No Available BackServer", http.StatusBadRequest)
|
||
return
|
||
}
|
||
proxy := hostTarget.LoadBalanceRuntime.RevProxies[proxyIndex]
|
||
if proxy != nil {
|
||
// 添加转发耗时记录
|
||
if wafCtx, ok := ctx.Value("waf_context").(innerbean.WafHttpContextData); ok && wafCtx.Weblog != nil {
|
||
forwardStart := time.Now().UnixNano() / 1e6
|
||
defer func() {
|
||
wafCtx.Weblog.ForwardCost = time.Now().UnixNano()/1e6 - forwardStart
|
||
}()
|
||
}
|
||
proxy.ServeHTTP(w, r.WithContext(ctx))
|
||
} else {
|
||
http.Error(w, "No Available Server", http.StatusBadRequest)
|
||
}
|
||
|
||
} else {
|
||
transport, customHeaders := waf.createTransport(r, host, 0, model.LoadBalance{}, hostTarget)
|
||
customConfig := map[string]string{}
|
||
customConfig["IsTransBackDomain"] = strconv.Itoa(hostTarget.Host.IsTransBackDomain)
|
||
proxy := wafproxy.NewSingleHostReverseProxyCustomHeader(remoteUrl, customHeaders, customConfig)
|
||
proxy.Transport = transport
|
||
proxy.ModifyResponse = waf.modifyResponse()
|
||
proxy.ErrorHandler = waf.errorResponse()
|
||
|
||
// 添加转发耗时记录
|
||
if wafCtx, ok := ctx.Value("waf_context").(innerbean.WafHttpContextData); ok && wafCtx.Weblog != nil {
|
||
forwardStart := time.Now().UnixNano() / 1e6
|
||
defer func() {
|
||
wafCtx.Weblog.ForwardCost = time.Now().UnixNano()/1e6 - forwardStart
|
||
}()
|
||
}
|
||
|
||
proxy.ServeHTTP(w, r.WithContext(ctx))
|
||
}
|
||
}
|
||
|
||
func (waf *WafEngine) createTransport(r *http.Request, host string, isEnableLoadBalance int, loadBalance model.LoadBalance, hostTarget *wafenginmodel.HostSafe) (*http.Transport, map[string]string) {
|
||
customHeaders := map[string]string{}
|
||
var transport *http.Transport
|
||
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||
dialer := net.Dialer{
|
||
Timeout: time.Duration(global.GCONFIG_RECORD_CONNECT_TIME_OUT) * time.Second,
|
||
KeepAlive: time.Duration(global.GCONFIG_RECORD_KEEPALIVE_TIME_OUT) * time.Second,
|
||
}
|
||
if isEnableLoadBalance > 0 {
|
||
conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(loadBalance.Remote_ip, strconv.Itoa(loadBalance.Remote_port)))
|
||
if err == nil {
|
||
return conn, nil
|
||
}
|
||
} else {
|
||
if hostTarget.Host.Remote_ip != "" {
|
||
conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(hostTarget.Host.Remote_ip, strconv.Itoa(hostTarget.Host.Remote_port)))
|
||
if err == nil {
|
||
return conn, nil
|
||
}
|
||
}
|
||
}
|
||
|
||
return dialer.DialContext(ctx, network, addr)
|
||
}
|
||
|
||
if r.TLS != nil {
|
||
// 增加https标识
|
||
customHeaders["X-FORWARDED-PROTO"] = "https"
|
||
transport = &http.Transport{
|
||
TLSClientConfig: &tls.Config{
|
||
InsecureSkipVerify: hostTarget.Host.InsecureSkipVerify == 1,
|
||
GetCertificate: waf.GetCertificateFunc,
|
||
},
|
||
DialContext: dialContext,
|
||
}
|
||
} else {
|
||
transport = &http.Transport{
|
||
DialContext: dialContext,
|
||
}
|
||
}
|
||
transport.ResponseHeaderTimeout = time.Duration(hostTarget.Host.ResponseTimeOut) * time.Second
|
||
return transport, customHeaders
|
||
}
|