-
Notifications
You must be signed in to change notification settings - Fork 0
/
ip.go
160 lines (145 loc) · 3.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
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
157
158
159
160
package wgpg
import (
"bytes"
"math/big"
"net"
"sort"
"github.com/pkg/errors"
)
var ip4in6prefix = [12]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
type IP struct {
Addr [16]byte
AddrLen uint8
PrefixLen uint8
}
func ParseIP(text string) (IP, error) {
var ret IP
err := ret.UnmarshalText([]byte(text))
return ret, err
}
func (i *IP) UnmarshalText(text []byte) error {
var err error
ip, ipnet, err := net.ParseCIDR(string(bytes.TrimSpace(text)))
if err != nil {
return err
}
ones, bits := ipnet.Mask.Size()
if ones == 0 && bits == 0 {
return errors.Errorf("Bad netmask: ones: %d, bits: %d", ones, bits)
}
i.AddrLen, i.PrefixLen = uint8(bits), uint8(ones)
*i = i.setBytes(ip)
return err
}
func (i IP) NetIP() net.IP {
if bytes.HasPrefix(i.Addr[:], ip4in6prefix[:]) {
return net.IP(i.Addr[12:])
} else {
return net.IP(i.Addr[16-i.AddrLen/8:])
}
}
func (i IP) NetMask() net.IPMask {
return net.CIDRMask(int(i.PrefixLen), int(i.AddrLen))
}
func (i IP) Network() IP {
network := i.NetIP().Mask(i.NetMask())
return i.setBytes(network)
}
func (i IP) String() string {
return (&net.IPNet{
IP: i.NetIP(),
Mask: i.NetMask(),
}).String()
}
func (i IP) Contains(ip IP) bool {
ipnet := net.IPNet{
IP: i.NetIP(),
Mask: i.NetMask(),
}
return ipnet.Contains(ip.NetIP())
}
func (i IP) IPSet() IPSet {
return IPSet{i}
}
func (i IP) Range() (IP, IP) {
start := i.Network()
end := i.Network()
var mask [16]byte
copy(mask[16-start.AddrLen/8:], end.NetMask())
for k := range end.Addr {
end.Addr[k] |= ^mask[k]
}
return start, end
}
func (i IP) Host() IP {
i.PrefixLen = i.AddrLen
return i
}
func (i IP) BigInt() *big.Int {
return new(big.Int).SetBytes(i.NetIP())
}
func (i IP) setBytes(b []byte) IP {
if i.AddrLen/8 <= 4 {
copy(i.Addr[:], ip4in6prefix[:])
}
copy(i.Addr[16-len(b):], b)
return i
}
type IPSet []IP
func (i IPSet) String() string {
var buf bytes.Buffer
var sep string
for _, ip := range i {
buf.WriteString(sep)
buf.WriteString(ip.String())
sep = ", "
}
return buf.String()
}
func (i *IPSet) UnmarshalText(text []byte) error {
s := bytes.Split(text, []byte{','})
for _, iptext := range s {
var ip IP
if err := ip.UnmarshalText(iptext); err != nil {
return err
}
*i = append(*i, ip)
}
i.Sort()
return nil
}
func (is IPSet) Sort() IPSet {
sort.Slice(is, is.Less)
return is
}
func (is IPSet) Less(i, j int) bool {
// sort v4 before v6
ai := is[i].AddrLen
aj := is[j].AddrLen
if ai != aj {
return ai < aj
}
// sort more specific before less specific
li := ai - is[i].PrefixLen
lj := aj - is[j].PrefixLen
if li != lj {
return li < lj
}
// sort by address
return bytes.Compare(is[i].Addr[:], is[j].Addr[:]) == -1
}
func GetIP(start, end IP, n int) (ip IP, err error) {
sip := start.BigInt()
eip := end.BigInt()
nip := new(big.Int)
nip.Add(sip, big.NewInt(int64(n)))
if nip.Cmp(eip) != -1 {
return IP{}, errors.Errorf("Out of Addresses: %d < %d < %d", sip, nip, eip)
}
return start.setBytes(nip.Bytes()), nil
}
func (i IPSet) Copy() IPSet {
ret := make(IPSet, len(i))
copy(ret, i)
return ret
}