]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | // Package cidr is a collection of assorted utilities for computing |
2 | // network and host addresses within network ranges. | |
3 | // | |
4 | // It expects a CIDR-type address structure where addresses are divided into | |
5 | // some number of prefix bits representing the network and then the remaining | |
6 | // suffix bits represent the host. | |
7 | // | |
8 | // For example, it can help to calculate addresses for sub-networks of a | |
9 | // parent network, or to calculate host addresses within a particular prefix. | |
10 | // | |
11 | // At present this package is prioritizing simplicity of implementation and | |
12 | // de-prioritizing speed and memory usage. Thus caution is advised before | |
13 | // using this package in performance-critical applications or hot codepaths. | |
14 | // Patches to improve the speed and memory usage may be accepted as long as | |
15 | // they do not result in a significant increase in code complexity. | |
16 | package cidr | |
17 | ||
18 | import ( | |
19 | "fmt" | |
20 | "math/big" | |
21 | "net" | |
22 | ) | |
23 | ||
24 | // Subnet takes a parent CIDR range and creates a subnet within it | |
25 | // with the given number of additional prefix bits and the given | |
26 | // network number. | |
27 | // | |
28 | // For example, 10.3.0.0/16, extended by 8 bits, with a network number | |
29 | // of 5, becomes 10.3.5.0/24 . | |
30 | func Subnet(base *net.IPNet, newBits int, num int) (*net.IPNet, error) { | |
31 | ip := base.IP | |
32 | mask := base.Mask | |
33 | ||
34 | parentLen, addrLen := mask.Size() | |
35 | newPrefixLen := parentLen + newBits | |
36 | ||
37 | if newPrefixLen > addrLen { | |
38 | return nil, fmt.Errorf("insufficient address space to extend prefix of %d by %d", parentLen, newBits) | |
39 | } | |
40 | ||
41 | maxNetNum := uint64(1<<uint64(newBits)) - 1 | |
42 | if uint64(num) > maxNetNum { | |
43 | return nil, fmt.Errorf("prefix extension of %d does not accommodate a subnet numbered %d", newBits, num) | |
44 | } | |
45 | ||
46 | return &net.IPNet{ | |
47 | IP: insertNumIntoIP(ip, num, newPrefixLen), | |
48 | Mask: net.CIDRMask(newPrefixLen, addrLen), | |
49 | }, nil | |
50 | } | |
51 | ||
52 | // Host takes a parent CIDR range and turns it into a host IP address with | |
53 | // the given host number. | |
54 | // | |
55 | // For example, 10.3.0.0/16 with a host number of 2 gives 10.3.0.2. | |
56 | func Host(base *net.IPNet, num int) (net.IP, error) { | |
57 | ip := base.IP | |
58 | mask := base.Mask | |
59 | ||
60 | parentLen, addrLen := mask.Size() | |
61 | hostLen := addrLen - parentLen | |
62 | ||
63 | maxHostNum := uint64(1<<uint64(hostLen)) - 1 | |
64 | ||
65 | numUint64 := uint64(num) | |
66 | if num < 0 { | |
67 | numUint64 = uint64(-num) - 1 | |
68 | num = int(maxHostNum - numUint64) | |
69 | } | |
70 | ||
71 | if numUint64 > maxHostNum { | |
72 | return nil, fmt.Errorf("prefix of %d does not accommodate a host numbered %d", parentLen, num) | |
73 | } | |
74 | ||
75 | return insertNumIntoIP(ip, num, 32), nil | |
76 | } | |
77 | ||
78 | // AddressRange returns the first and last addresses in the given CIDR range. | |
79 | func AddressRange(network *net.IPNet) (net.IP, net.IP) { | |
80 | // the first IP is easy | |
81 | firstIP := network.IP | |
82 | ||
83 | // the last IP is the network address OR NOT the mask address | |
84 | prefixLen, bits := network.Mask.Size() | |
85 | if prefixLen == bits { | |
86 | // Easy! | |
87 | // But make sure that our two slices are distinct, since they | |
88 | // would be in all other cases. | |
89 | lastIP := make([]byte, len(firstIP)) | |
90 | copy(lastIP, firstIP) | |
91 | return firstIP, lastIP | |
92 | } | |
93 | ||
94 | firstIPInt, bits := ipToInt(firstIP) | |
95 | hostLen := uint(bits) - uint(prefixLen) | |
96 | lastIPInt := big.NewInt(1) | |
97 | lastIPInt.Lsh(lastIPInt, hostLen) | |
98 | lastIPInt.Sub(lastIPInt, big.NewInt(1)) | |
99 | lastIPInt.Or(lastIPInt, firstIPInt) | |
100 | ||
101 | return firstIP, intToIP(lastIPInt, bits) | |
102 | } | |
103 | ||
104 | // AddressCount returns the number of distinct host addresses within the given | |
105 | // CIDR range. | |
106 | // | |
107 | // Since the result is a uint64, this function returns meaningful information | |
108 | // only for IPv4 ranges and IPv6 ranges with a prefix size of at least 65. | |
109 | func AddressCount(network *net.IPNet) uint64 { | |
110 | prefixLen, bits := network.Mask.Size() | |
111 | return 1 << (uint64(bits) - uint64(prefixLen)) | |
112 | } |