mirror of
https://github.com/wikiZ/RedGuard
synced 2026-06-08 18:18:32 +00:00
157 lines
4.9 KiB
Go
157 lines
4.9 KiB
Go
/**
|
|
* @Author 风起
|
|
* @contact: onlyzaliks@gmail.com
|
|
* @File: ProxyHandler.go
|
|
* @Time: 2022/5/5 16:53
|
|
**/
|
|
|
|
package core
|
|
|
|
import (
|
|
"RedGuard/lib"
|
|
"crypto/tls"
|
|
"github.com/wxnacy/wgo/arrays"
|
|
"io"
|
|
"math/rand"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
_addressArray []string // By request list
|
|
_startUp sync.Mutex // mutex lock
|
|
_hostProxy = make(map[string]*httputil.ReverseProxy) // Used to cache httputil.ReverseProxy
|
|
)
|
|
|
|
type baseHandle struct{}
|
|
|
|
func NewProxy(proxyURL string, dropType bool) (*httputil.ReverseProxy, error) {
|
|
destinationURL, err := url.Parse(proxyURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
proxy := httputil.NewSingleHostReverseProxy(destinationURL)
|
|
// dropType Check whether the response to the request is changed
|
|
if dropType {
|
|
proxy.ModifyResponse = modifyResponse() // Modifies the response to the request
|
|
}
|
|
return proxy, nil
|
|
}
|
|
|
|
func modifyResponse() func(*http.Response) error {
|
|
return func(resp *http.Response) error {
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close() // Direct shutdown response
|
|
}(resp.Body)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// ProxyRequestHandler A reverse proxy processes HTTP requests
|
|
func (h *baseHandle) ServeHTTP(write http.ResponseWriter, req *http.Request) {
|
|
host := &req.Host
|
|
// Obtain the domain name and target map
|
|
hostTarget := lib.JsonToMap(lib.ReadConfig(
|
|
"proxy",
|
|
"HostTarget",
|
|
lib.InitConfig()),
|
|
)
|
|
// Determine the URL to be redirected to
|
|
redirectURL := lib.ReadConfig("proxy", "Redirect", lib.InitConfig())
|
|
// Read the configuration file to check whether DROP is enabled
|
|
isDrop, _ := strconv.ParseBool(lib.ReadConfig("proxy", "DROP", lib.InitConfig()))
|
|
ip := lib.ConvertIP(req.RemoteAddr) // IP address of the host that initiates the request
|
|
// Check whether the host is verified
|
|
if IPHash := lib.EncodeMD5(ip); arrays.ContainsString(_addressArray, IPHash) == -1 {
|
|
logger.Noticef("[REQUEST] %s %s", req.Method, req.RequestURI)
|
|
// Request filtering method
|
|
if !ProxyFilterManger(req) {
|
|
goto LOOK // Redirect to the specified site
|
|
}
|
|
logger.Noticef("[REQUEST] %s - %s", ip, req.UserAgent())
|
|
_addressArray = append(_addressArray, IPHash) // Add to the list after verification for the first time
|
|
}
|
|
// Fetch directly from cache
|
|
if fn, ok := _hostProxy[*host]; ok {
|
|
fn.ServeHTTP(write, req)
|
|
return
|
|
}
|
|
// Check whether the domain name is in the whitelist
|
|
if target, ok := hostTarget[*host]; ok {
|
|
proxy, err := NewProxy(target, false)
|
|
if err != nil {
|
|
logger.Error("Proxy Exception")
|
|
}
|
|
_hostProxy[*host] = proxy // Into the cache
|
|
proxy.ServeHTTP(write, req)
|
|
return
|
|
}
|
|
|
|
LOOK:
|
|
req.URL.Path = "/" // Url rewriting
|
|
// condition is not met, the element is removed from the slice
|
|
// Output The URL of each request for this IP address
|
|
if len(_addressArray) > 0 {
|
|
_addressArray = _addressArray[:len(_addressArray)-1]
|
|
}
|
|
// Determine whether to redirect or intercept intercepted traffic
|
|
proxy, _ := NewProxy(redirectURL, isDrop)
|
|
// TODO: Maybe we need a little optimization here, right?
|
|
if isDrop {
|
|
// DROP Request
|
|
logger.Alertf("[DROP] Source IP: %s", ip)
|
|
} else {
|
|
// REDIRECT Request
|
|
logger.Alertf("[REDIRECT] Source IP: %s -> Destination Site: %s", ip, redirectURL)
|
|
}
|
|
// Unauthorized access is redirected to the specified URL
|
|
proxy.ServeHTTP(write, req)
|
|
}
|
|
|
|
// ProxyManger Initialize the reverse proxy and pass in the address of the real back-end service
|
|
// handle all requests to your server using the proxy
|
|
// @param action string reverse proxy listening port type
|
|
// @param port string reverse proxy listening port
|
|
// @param pattern string pattern associated with the listening port type
|
|
func ProxyManger(action, port, pattern string) {
|
|
_startUp.Lock() // 我知道这可能是一个bug哈哈哈,但是它可能不影响什么,就不修了。
|
|
handle := &baseHandle{}
|
|
http.Handle(pattern, handle)
|
|
// Cancels the validity verification of the destination TLS certificate
|
|
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
}
|
|
// Disable client connection caching to connection pools
|
|
http.DefaultTransport.(*http.Transport).DisableKeepAlives = true
|
|
rand.Seed(time.Now().UnixNano())
|
|
server := &http.Server{
|
|
Addr: port, // proxy port
|
|
Handler: handle, // Cache structure
|
|
TLSConfig: &tls.Config{
|
|
CipherSuites: lib.MicsSlice([]uint16{
|
|
0x0005, 0x000a, 0x002f,
|
|
0x0035, 0x003c, 0x009c,
|
|
0x009d, 0xc011, 0xc012,
|
|
0xc013, 0xc014, 0xc027,
|
|
0xc02f, 0xc030, 0xcca8,
|
|
}, rand.Intn(2)+1),
|
|
},
|
|
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 1),
|
|
}
|
|
logger.Warningf("Proxy Listen Port %s (%s)", port, action)
|
|
_startUp.Unlock()
|
|
if action == "HTTPS" {
|
|
// HTTPS reverse proxy
|
|
_ = server.ListenAndServeTLS(
|
|
"cert-rsa/ca.crt", // rsa cert crt
|
|
"cert-rsa/ca.key", // rsa cert key
|
|
)
|
|
} else {
|
|
_ = server.ListenAndServe() // HTTP reverse proxy
|
|
}
|
|
}
|