-
Notifications
You must be signed in to change notification settings - Fork 345
/
net.go
156 lines (135 loc) · 3.43 KB
/
net.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package net
import (
"net"
"net/http"
"net/netip"
"strings"
"go4.org/netipx"
)
// strip port from addresses with hostname, ipv4 or ipv6
func stripPort(address string) string {
if h, _, err := net.SplitHostPort(address); err == nil {
return h
}
return address
}
func parse(addr string) net.IP {
if addr != "" {
res := net.ParseIP(stripPort(addr))
return res
}
return nil
}
// RemoteAddr returns the remote address of the client. When the
// 'X-Forwarded-For' header is set, then it is used instead. This is
// how most often proxies behave. Wikipedia shows the format
// https://en.wikipedia.org/wiki/X-Forwarded-For#Format
//
// Example:
//
// X-Forwarded-For: client, proxy1, proxy2
func RemoteAddr(r *http.Request) netip.Addr {
xff := r.Header.Get("X-Forwarded-For")
if xff != "" {
s, _, _ := strings.Cut(xff, ",")
if addr, err := netip.ParseAddr(stripPort(s)); err == nil {
return addr
}
}
addr, _ := netip.ParseAddr(stripPort(r.RemoteAddr))
return addr
}
// RemoteHost is *deprecated* use RemoteAddr
func RemoteHost(r *http.Request) net.IP {
ffs := r.Header.Get("X-Forwarded-For")
ff, _, _ := strings.Cut(ffs, ",")
if ffh := parse(ff); ffh != nil {
return ffh
}
return parse(r.RemoteAddr)
}
// RemoteAddrFromLast returns the remote address of the client. When
// the 'X-Forwarded-For' header is set, then it is used instead. This
// is known to be true for AWS Application LoadBalancer. AWS docs
// https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
//
// Example:
//
// X-Forwarded-For: ip-address-1, ip-address-2, client-ip-address
func RemoteAddrFromLast(r *http.Request) netip.Addr {
ffs := r.Header.Get("X-Forwarded-For")
if ffs == "" {
addr, _ := netip.ParseAddr(stripPort(r.RemoteAddr))
return addr
}
last := ffs
if i := strings.LastIndex(ffs, ","); i != -1 {
last = ffs[i+1:]
}
addr, err := netip.ParseAddr(stripPort(strings.TrimSpace(last)))
if err != nil {
addr, _ := netip.ParseAddr(stripPort(r.RemoteAddr))
return addr
}
return addr
}
// RemoteHostFromLast is *deprecated* use RemoteAddrFromLast instead
func RemoteHostFromLast(r *http.Request) net.IP {
ffs := r.Header.Get("X-Forwarded-For")
ffa := strings.Split(ffs, ",")
ff := ffa[len(ffa)-1]
if ff != "" {
if ip := parse(strings.TrimSpace(ff)); ip != nil {
return ip
}
}
return parse(r.RemoteAddr)
}
// IPNets is *deprecated* use netipx.IPSet instead
type IPNets []*net.IPNet
// Contain is *deprecated* use netipx.IPSet.Contains() instead
func (nets IPNets) Contain(ip net.IP) bool {
for _, net := range nets {
if net.Contains(ip) {
return true
}
}
return false
}
// ParseCIDRs is *deprecated* use ParseIPCIDRs.
func ParseCIDRs(cidrs []string) (nets IPNets, err error) {
for _, cidr := range cidrs {
if !strings.Contains(cidr, "/") {
cidr += "/32"
}
_, net, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
}
nets = append(nets, net)
}
return nets, nil
}
// ParseIPCIDRs returns a valid IPSet in case there is no parsing
// error.
func ParseIPCIDRs(cidrs []string) (*netipx.IPSet, error) {
var b netipx.IPSetBuilder
for _, w := range cidrs {
if strings.Contains(w, "/") {
pref, err := netip.ParsePrefix(w)
if err != nil {
return nil, err
}
b.AddPrefix(pref)
} else if addr, err := netip.ParseAddr(w); err != nil {
return nil, err
} else {
b.Add(addr)
}
}
ips, err := b.IPSet()
if err != nil {
return nil, err
}
return ips, nil
}