forked from aerogo/aero
-
Notifications
You must be signed in to change notification settings - Fork 0
/
IP.go
88 lines (69 loc) · 2.06 KB
/
IP.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
// Copyright (c) 2018 Shen Sheng
// Copyright (c) 2019 Eduard Urbach
package aero
import (
"net"
"net/http"
"strings"
)
// CIDR = Classless Inter-Domain Routing.
// Here we'll get the private CIDR blocks.
var privateCIDRs = getPrivateCIDRs()
// isPrivateAddress checks if the address is under private CIDR blocks.
func isPrivateAddress(address string) (bool, error) {
ipAddress := net.ParseIP(address)
if ipAddress == nil {
return false, ErrAddressNotValid
}
for _, cidr := range privateCIDRs {
if cidr.Contains(ipAddress) {
return true, nil
}
}
return false, nil
}
// getPrivateCIDRs returns the list of private CIDR blocks.
func getPrivateCIDRs() []*net.IPNet {
maxCidrBlocks := []string{
"127.0.0.1/8", // localhost
"10.0.0.0/8", // 24-bit block
"172.16.0.0/12", // 20-bit block
"192.168.0.0/16", // 16-bit block
"169.254.0.0/16", // link local address
"::1/128", // localhost IPv6
"fc00::/7", // unique local address IPv6
"fe80::/10", // link local address IPv6
}
cidrs := make([]*net.IPNet, len(maxCidrBlocks))
for i, maxCidrBlock := range maxCidrBlocks {
_, cidr, _ := net.ParseCIDR(maxCidrBlock)
cidrs[i] = cidr
}
return cidrs
}
// realIP returns the client's real public IP address from http request headers.
func realIP(r *http.Request) string {
xForwardedFor := r.Header.Get(forwardedForHeader)
// Check the list of IP addresses in the X-Forwarded-For
// header and return the first global address, if available.
for _, address := range strings.Split(xForwardedFor, ",") {
address = strings.TrimSpace(address)
isPrivate, err := isPrivateAddress(address)
if err == nil && !isPrivate {
return address
}
}
// Return the X-Real-Ip header, if available.
xRealIP := r.Header.Get(realIPHeader)
if xRealIP != "" {
return xRealIP
}
// If both headers failed, return the remote IP.
remoteIP := r.RemoteAddr
// If there is a colon in the remote address,
// remove the port number.
if strings.ContainsRune(remoteIP, ':') {
remoteIP, _, _ = net.SplitHostPort(remoteIP)
}
return remoteIP
}