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
| // ClientIP implements a best effort algorithm to return the real client IP, it parses
// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy.
// Use X-Forwarded-For before X-Real-Ip as nginx uses X-Real-Ip with the proxy's IP.
func (c *Context) ClientIP() string {
if c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil {
for _, header := range c.engine.RemoteIPHeaders {
ipChain := filterIPsFromUntrustedProxies(c.requestHeader(header), c.Request, c.engine)
if len(ipChain) > 0 {
return ipChain[0]
}
}
}
if c.engine.AppEngine {
if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
return addr
}
}
ip, _ := getTransportPeerIPForRequest(c.Request)
return ip
}
func filterIPsFromUntrustedProxies(XForwardedForHeader string, req *http.Request, e *Engine) []string {
var items, out []string
if XForwardedForHeader != "" {
items = strings.Split(XForwardedForHeader, ",")
} else {
return []string{}
}
if peerIP, err := getTransportPeerIPForRequest(req); err == nil {
items = append(items, peerIP)
}
for i := len(items) - 1; i >= 0; i-- {
item := strings.TrimSpace(items[i])
ip := net.ParseIP(item)
if ip == nil {
return out
}
out = prependString(ip.String(), out)
if !isTrustedProxy(ip, e) {
return out
}
// out = prependString(ip.String(), out)
}
return out
}
func isTrustedProxy(ip net.IP, e *Engine) bool {
for _, trustedProxy := range e.TrustedProxies {
if _, ipnet, err := net.ParseCIDR(trustedProxy); err == nil {
if ipnet.Contains(ip) {
return true
}
continue
}
if proxyIP := net.ParseIP(trustedProxy); proxyIP != nil {
if proxyIP.Equal(ip) {
return true
}
continue
}
if addrs, err := e.lookupHost(trustedProxy); err == nil {
for _, proxyAddr := range addrs {
proxyIP := net.ParseIP(proxyAddr)
if proxyIP == nil {
continue
}
if proxyIP.Equal(ip) {
return true
}
}
}
}
return false
}
func prependString(ip string, ipList []string) []string {
ipList = append(ipList, "")
copy(ipList[1:], ipList)
ipList[0] = string(ip)
return ipList
}
func getTransportPeerIPForRequest(req *http.Request) (string, error) {
var err error
if ip, _, err := net.SplitHostPort(strings.TrimSpace(req.RemoteAddr)); err == nil {
return ip, nil
}
return "", err
}
|