-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathipaddress.go
More file actions
79 lines (67 loc) · 2.13 KB
/
ipaddress.go
File metadata and controls
79 lines (67 loc) · 2.13 KB
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
package wireguardhttps
import (
"encoding/binary"
"fmt"
"net"
)
type IPNotInSubnetError struct {
Network net.IPNet
IP net.IP
}
func (i *IPNotInSubnetError) Error() string {
return fmt.Sprintf("%v is not in subnet %v", i.IP, i.Network)
}
type IPsExhaustedError struct {
Network net.IPNet
}
func (i *IPsExhaustedError) Error() string {
return fmt.Sprintf("%v is out of IP addresses", i.Network)
}
// AddressRange provides methods for assigning IP addresses within a subnet.
type AddressRange struct {
Network net.IPNet
}
func (a *AddressRange) Start() net.IP {
return a.Network.IP
}
// Next returns the next IP address within a subnet given the last IP address.
// It will fail with an error if the IP address in not within the subnet, or if the subnet has run out of IP addresses.
// Callers should prevent IP address conflicts by ensuring only one IP address can be assigned at a time in a subnet, such as by using a `sync.Mutex` before checking the IP address data store and unlocking it after updating the data store with the newly allocated IP.
func (a *AddressRange) Next(current net.IP) (net.IP, error) {
if !a.Network.Contains(current) {
return nil, &IPNotInSubnetError{
Network: a.Network,
IP: current,
}
}
if current.Equal(a.Finish()) {
return nil, &IPsExhaustedError{
Network: a.Network,
}
}
ip := make(net.IP, 4)
next := binary.BigEndian.Uint32(current) + 1
binary.BigEndian.PutUint32(ip, next)
return ip, nil
}
// Addresses returns all IP addresses within a CIDR.
func (a *AddressRange) Addresses() []net.IP {
addresses := []net.IP{}
start := binary.BigEndian.Uint32(a.Start())
finish := binary.BigEndian.Uint32(a.Finish())
// Don't allocate the VPN server's IP address to client devices
for i := start + 1; i <= finish; i++ {
ip := make(net.IP, 4)
binary.BigEndian.PutUint32(ip, i)
addresses = append(addresses, ip)
}
return addresses
}
func (a *AddressRange) Finish() net.IP {
mask := binary.BigEndian.Uint32(a.Network.Mask)
start := binary.BigEndian.Uint32(a.Start())
finish := (start & mask) | (mask ^ 0xffffffff)
ip := make(net.IP, 4)
binary.BigEndian.PutUint32(ip, finish)
return ip
}