-
Notifications
You must be signed in to change notification settings - Fork 2
/
ip.go
81 lines (67 loc) · 1.72 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
package ipformat
import (
"errors"
"net"
"net/http"
"strconv"
"strings"
)
// IP details about the IP address
type IP struct {
Address string // Original/full notation passed in
Parts []string
TypeV6 bool
Range bool
CIDR int64
}
// ReadUserIP gets the users IP address from the request
// @TODO: fix this to handle IPS properly building on logic from https://husobee.github.io/golang/ip-address/2015/12/17/remote-ip-go.html
func ReadUserIP(r *http.Request) string {
IPAddress := r.Header.Get("X-Forwarded-For")
if IPAddress != "" {
IPS := strings.Split(IPAddress, ",")
IPAddress = IPS[0]
}
if IPAddress == "" {
IPAddress = r.Header.Get("X-Real-IP")
}
if IPAddress == "" {
IPAddress, _, _ = net.SplitHostPort(r.RemoteAddr)
}
return IPAddress
}
// New creates the internal IP struct
func New(ipString string) (IP, error) {
var ip IP
// Set what the user sent us
ip.Address = ipString
//TODO: use regex validation?
// check to see if its already an ipv6
colonCount := strings.Count(ip.Address, ":")
ip.TypeV6 = colonCount >= 2
if colonCount > 7 || colonCount == 1 {
return IP{}, errors.New("not a valid ip address")
}
//TODO: validate against "ip - ip"
// Check if its a range
ip.Range = strings.Contains(ip.Address, "/")
// Grab the cidr
cidrParts := strings.Split(ip.Address, "/")
if ip.Range {
var err error
ip.CIDR, err = strconv.ParseInt(cidrParts[1], 10, 64)
if err != nil {
return IP{}, errors.New("cannot parse cidr notation")
}
}
if len(cidrParts) > 2 {
return IP{}, errors.New("not a valid ip address cidr notation")
}
// Split the parts
if ip.TypeV6 {
ip.Parts = strings.Split(cidrParts[0], ":")
} else {
ip.Parts = strings.Split(cidrParts[0], ".")
}
return ip, nil
}