-
Notifications
You must be signed in to change notification settings - Fork 258
/
proxy_handler.go
109 lines (88 loc) · 2.05 KB
/
proxy_handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package main
import (
"net"
"net/http"
"strings"
"github.com/contentsquare/chproxy/config"
)
const (
xForwardedForHeader = "X-Forwarded-For"
xRealIPHeader = "X-Real-Ip"
forwardedHeader = "Forwarded"
)
type ProxyHandler struct {
proxy *config.Proxy
}
func NewProxyHandler(proxy *config.Proxy) *ProxyHandler {
return &ProxyHandler{
proxy: proxy,
}
}
func (m *ProxyHandler) GetRemoteAddr(r *http.Request) string {
if m.proxy.Enable {
var addr string
if m.proxy.Header != "" {
addr = r.Header.Get(m.proxy.Header)
} else {
addr = parseDefaultProxyHeaders(r)
}
if isValidAddr(addr) {
return addr
}
}
return r.RemoteAddr
}
// isValidAddr checks if the Addr is a valid IP or IP:port.
func isValidAddr(addr string) bool {
if addr == "" {
return false
}
ip, _, err := net.SplitHostPort(addr)
if err != nil {
return net.ParseIP(addr) != nil
}
return net.ParseIP(ip) != nil
}
func parseDefaultProxyHeaders(r *http.Request) string {
var addr string
if fwd := r.Header.Get(xForwardedForHeader); fwd != "" {
addr = extractFirstMatchFromIPList(fwd)
} else if fwd := r.Header.Get(xRealIPHeader); fwd != "" {
addr = extractFirstMatchFromIPList(fwd)
} else if fwd := r.Header.Get(forwardedHeader); fwd != "" {
// See: https://tools.ietf.org/html/rfc7239.
addr = parseForwardedHeader(fwd)
}
return addr
}
func extractFirstMatchFromIPList(ipList string) string {
if ipList == "" {
return ""
}
s := strings.Index(ipList, ",")
if s == -1 {
s = len(ipList)
}
return ipList[:s]
}
func parseForwardedHeader(fwd string) string {
splits := strings.Split(fwd, ";")
if len(splits) == 0 {
return ""
}
for _, split := range splits {
trimmed := strings.TrimSpace(split)
if strings.HasPrefix(strings.ToLower(trimmed), "for=") {
forSplits := strings.Split(trimmed, ",")
if len(forSplits) == 0 {
return ""
}
addr := forSplits[0][4:]
trimmedAddr := strings.
NewReplacer("\"", "", "[", "", "]", "").
Replace(addr) // If IpV6, remove brackets and quotes.
return trimmedAddr
}
}
return ""
}