forked from andybalholm/redwood
-
Notifications
You must be signed in to change notification settings - Fork 0
/
iprange.go
139 lines (124 loc) · 2.74 KB
/
iprange.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
package main
import (
"fmt"
"net"
"strconv"
"strings"
)
// An IPRange represents a range of IP addresses.
type IPRange struct {
first, last net.IP
}
func (r IPRange) String() string {
return fmt.Sprintf("%s-%s", r.first, r.last)
}
// ParseIPRange parses s as an IP address range. It accepts ranges in the following forms:
// "10.1.10.0-10.1.10.255", "10.1.10.0-255", and "10.1.10.0/24".
func ParseIPRange(s string) (r IPRange, err error) {
defer func() {
// Make sure the IPv4 addresses are in 4-byte form.
if r.first != nil && r.last != nil {
if f4 := r.first.To4(); f4 != nil {
r.first = f4
}
if f4 := r.last.To4(); f4 != nil {
r.last = f4
}
}
}()
_, n, err := net.ParseCIDR(s)
if err == nil {
r.first = n.IP
r.last = make(net.IP, len(n.IP))
for i, b := range n.IP {
r.last[i] = b | ^n.Mask[i]
}
return r, nil
}
err = nil
dash := strings.Index(s, "-")
if dash == -1 {
err = fmt.Errorf("%q is not a valid IP address range", s)
return
}
r.first = net.ParseIP(s[:dash])
if r.first == nil {
err = fmt.Errorf("%q does not begin with a valid IP address", s)
return
}
last := s[dash+1:]
r.last = net.ParseIP(last)
if r.last != nil {
return
}
lastByte, err := strconv.ParseUint(last, 10, 8)
if err != nil {
err = fmt.Errorf("%q does not end with a valid IP address or byte value", s)
return
}
r.last = make(net.IP, len(r.first))
copy(r.last, r.first)
r.last[len(r.last)-1] = byte(lastByte)
return
}
func (r IPRange) Contains(addr net.IP) bool {
if a4 := addr.To4(); a4 != nil {
addr = a4
}
if len(addr) != len(r.first) {
return false
}
for i := range addr {
if addr[i] < r.first[i] {
return false
}
if addr[i] > r.first[i] {
break
}
}
for i := range addr {
if addr[i] > r.last[i] {
return false
}
if addr[i] < r.last[i] {
break
}
}
return true
}
type rangeToGroup struct {
r IPRange
group string
}
// An IPMap maps IP addresses and ranges to ACL names.
type IPMap struct {
addresses map[string][]string
ranges []rangeToGroup
}
// add adds an address/ACL mapping.
func (m *IPMap) add(addr, acl string) error {
if m.addresses == nil {
m.addresses = make(map[string][]string)
}
if ip := net.ParseIP(addr); ip != nil {
s := ip.String()
m.addresses[s] = append(m.addresses[s], acl)
return nil
}
r, err := ParseIPRange(addr)
if err != nil {
return fmt.Errorf("invalid IP address or range: %s", addr)
}
m.ranges = append(m.ranges, rangeToGroup{r, acl})
return nil
}
// matches returns a list of the ACLs that addr belongs to.
func (m *IPMap) matches(addr net.IP) (result []string) {
result = append(result, m.addresses[addr.String()]...)
for _, r := range m.ranges {
if r.r.Contains(addr) {
result = append(result, r.group)
}
}
return result
}