New Upstream Release - golang-github-c-robinson-iplib
Ready changes
Summary
Merged new upstream version: 1.0.6 (was: 1.0.4).
Resulting package
Built on 2023-03-28T03:43 (took 4m18s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases golang-github-c-robinson-iplib-dev
Lintian Result
Diff
diff --git a/README.md b/README.md
index bbb211f..228084f 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ It includes:
Some simple tools for performing common tasks against IP objects:
- compare two addresses
+- make a copy of a net.IP address
- get the delta between two addresses
- sort
- decrement or increment addresses
diff --git a/debian/changelog b/debian/changelog
index ebedf3e..c05f369 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+golang-github-c-robinson-iplib (1.0.6-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Tue, 28 Mar 2023 03:39:44 -0000
+
golang-github-c-robinson-iplib (1.0.3-3) unstable; urgency=medium
* Add patch to avoid test failures on 32-bit archs (adding an explicit
diff --git a/debian/patches/0001-workaround-test-failure-on-32-bit-archs.patch b/debian/patches/0001-workaround-test-failure-on-32-bit-archs.patch
index 60cc045..ada8ed8 100644
--- a/debian/patches/0001-workaround-test-failure-on-32-bit-archs.patch
+++ b/debian/patches/0001-workaround-test-failure-on-32-bit-archs.patch
@@ -13,9 +13,11 @@ Add an explicit cast to avoid the issue, until the upstream issue has been
commented on.
Bug: https://github.com/c-robinson/iplib/issues/11
---- a/iplib_test.go
-+++ b/iplib_test.go
-@@ -359,7 +359,7 @@ func TestDeltaIP(t *testing.T) {
+Index: golang-github-c-robinson-iplib.git/iplib_test.go
+===================================================================
+--- golang-github-c-robinson-iplib.git.orig/iplib_test.go
++++ golang-github-c-robinson-iplib.git/iplib_test.go
+@@ -371,7 +371,7 @@ func TestDeltaIP(t *testing.T) {
func TestDeltaIPMaxValue(t *testing.T) {
i := DeltaIP(net.ParseIP("2001:db8::"), net.ParseIP("2001:db8:1234:5678::"))
if i != MaxIPv4 {
diff --git a/hostmask.go b/hostmask.go
index 12faab3..f00c83a 100644
--- a/hostmask.go
+++ b/hostmask.go
@@ -18,25 +18,25 @@ import (
// 2001:db8:1234:5678::1. Here is a Net6 object eing initialized without a
// hostmask:
//
-// n := NewNet6(2001:db8::, 56, 0)
-// Address 2001:db8::
-// Netmask ffff:ffff:ffff:ff00:0000:0000:0000:0000
-// Hostmask 0000:0000:0000:0000:0000:0000:0000:0000
-// First 2001:0db8:0000:0000:0000:0000:0000:0000
-// Last 2001:0db8:0000:00ff:ffff:ffff:ffff:ffff
-// Count 4722366482869645213696
+// n := NewNet6(2001:db8::, 56, 0)
+// Address 2001:db8::
+// Netmask ffff:ffff:ffff:ff00:0000:0000:0000:0000
+// Hostmask 0000:0000:0000:0000:0000:0000:0000:0000
+// First 2001:0db8:0000:0000:0000:0000:0000:0000
+// Last 2001:0db8:0000:00ff:ffff:ffff:ffff:ffff
+// Count 4722366482869645213696
//
// This creates a block with 4.7 sextillion usable addresses. Below is he same
// block with a hostmask of /60. The mask is applied from the rightmost byte,
// leaving 12 unmasked bits for a total of 4096 allocatable addresses:
//
-// n:= NewNet6(2001:db8::, 56, 60)
-// Address 2001:db8::
-// Netmask ffff:ffff:ffff:ff00:0000:0000:0000:0000
-// Hostmask 0000:0000:0000:0000:0fff:ffff:ffff:ffff
-// First 2001:0db8:0000:0000:0000:0000:0000:0000
-// Last 2001:0db8:0000:00ff:f000:0000:0000:0000
-// Count 4096
+// n:= NewNet6(2001:db8::, 56, 60)
+// Address 2001:db8::
+// Netmask ffff:ffff:ffff:ff00:0000:0000:0000:0000
+// Hostmask 0000:0000:0000:0000:0fff:ffff:ffff:ffff
+// First 2001:0db8:0000:0000:0000:0000:0000:0000
+// Last 2001:0db8:0000:00ff:f000:0000:0000:0000
+// Count 4096
//
// In the first example the second IP address of the netblock is 2001:db8::1,
// in the second example it is 2001:db8:0:1::
@@ -45,15 +45,15 @@ import (
// within those bytes are still blocked out left-to-right, so that address
// incrementing/decrementing makes sense to the end user, as shown here:
//
-// BINARY Base16 Base10 Example Max16 Max10
-// 0000 0000 0x00 0 /56 0xFF 255
-// 1000 0000 0x80 128 /57 0x7F 127
-// 1100 0000 0xC0 192 /58 0x3F 63
-// 1110 0000 0xE0 224 /59 0x1F 31
-// 1111 0000 0xF0 240 /60 0x0F 15
-// 1111 1000 0xF8 248 /61 0x07 7
-// 1111 1100 0xFC 252 /62 0x03 3
-// 1111 1110 0xFE 254 /63 0x01 1
+// BINARY Base16 Base10 Example Max16 Max10
+// 0000 0000 0x00 0 /56 0xFF 255
+// 1000 0000 0x80 128 /57 0x7F 127
+// 1100 0000 0xC0 192 /58 0x3F 63
+// 1110 0000 0xE0 224 /59 0x1F 31
+// 1111 0000 0xF0 240 /60 0x0F 15
+// 1111 1000 0xF8 248 /61 0x07 7
+// 1111 1100 0xFC 252 /62 0x03 3
+// 1111 1110 0xFE 254 /63 0x01 1
//
// A hostmask of /1 will block out the left-most bit of the 16th byte
// while a /8 will block the entire 16th byte.
@@ -209,7 +209,7 @@ func IncrementIP6WithinHostmask(ip net.IP, hm HostMask, count *big.Int) (net.IP,
// inside the hostmask are set, an empty net.IP{} and an ErrAddressOutOfRange
// will be returned
func NextIP6WithinHostmask(ip net.IP, hm HostMask) (net.IP, error) {
- xip := getCloneIP(ip)
+ xip := CopyIP(ip)
for i := len(xip) - 1; i >= 0; i-- {
if hm[i] == 0xff {
@@ -237,7 +237,7 @@ func NextIP6WithinHostmask(ip net.IP, hm HostMask) (net.IP, error) {
// If bits inside the hostmask are set, an empty net.IP{} and an
// ErrAddressOutOfRange will be returned
func PreviousIP6WithinHostmask(ip net.IP, hm HostMask) (net.IP, error) {
- xip := getCloneIP(ip)
+ xip := CopyIP(ip)
bb, bbpos := hm.BoundaryByte()
bbmax := 0xff - bb
diff --git a/iplib.go b/iplib.go
index a90b24a..696f715 100644
--- a/iplib.go
+++ b/iplib.go
@@ -47,7 +47,7 @@ import (
const (
// MaxIPv4 is the max size of a uint32, also the IPv4 address space
- MaxIPv4 = 1<<32 - 1
+ MaxIPv4 uint32 = 1<<32 - 1
// IP4Version is the label returned by IPv4 addresses
IP4Version = 4
@@ -138,6 +138,15 @@ func CompareNets(a, b Net) int {
return 1
}
+// CopyIP creates a new net.IP object containing the same data as the supplied
+// net.IP (e.g. creates a new array and duplicates the contents)
+func CopyIP(ip net.IP) net.IP {
+ var xip []byte
+ xip = make([]byte, len(ip))
+ copy(xip, ip)
+ return xip
+}
+
// DecrementIPBy returns a net.IP that is lower than the supplied net.IP by
// the supplied integer value. If you underflow the IP space it will return
// the zero address.
@@ -445,9 +454,9 @@ func IsAllZeroes(ip net.IP) bool {
func NextIP(ip net.IP) net.IP {
var xip []byte
if EffectiveVersion(ip) == IP4Version {
- xip = getCloneIP(ForceIP4(ip))
+ xip = CopyIP(ForceIP4(ip))
} else {
- xip = getCloneIP(ip)
+ xip = CopyIP(ip)
}
for i := len(xip) - 1; i >= 0; i-- {
@@ -466,9 +475,9 @@ func NextIP(ip net.IP) net.IP {
func PreviousIP(ip net.IP) net.IP {
var xip []byte
if EffectiveVersion(ip) == IP4Version {
- xip = getCloneIP(ForceIP4(ip))
+ xip = CopyIP(ForceIP4(ip))
} else {
- xip = getCloneIP(ip)
+ xip = CopyIP(ip)
}
for i := len(xip) - 1; i >= 0; i-- {
@@ -530,10 +539,3 @@ func getCloneBigInt(z *big.Int) *big.Int {
nz := new(big.Int)
return nz.Set(z)
}
-
-func getCloneIP(ip net.IP) net.IP {
- var xip []byte
- xip = make([]byte, len(ip))
- copy(xip, ip)
- return xip
-}
diff --git a/iplib_test.go b/iplib_test.go
index 8593b3b..8a2bb68 100644
--- a/iplib_test.go
+++ b/iplib_test.go
@@ -3,10 +3,22 @@ package iplib
import (
"math/big"
"net"
+ "reflect"
"sort"
"testing"
)
+func TestCopyIP(t *testing.T) {
+ ipa := net.ParseIP("192.168.23.5")
+ ipb := CopyIP(ipa)
+ if reflect.ValueOf(ipa).Pointer() == reflect.ValueOf(ipb).Pointer() {
+ t.Errorf("CopyIP() failed to copy (copied IP shares pointer with original)!")
+ }
+ if CompareIPs(ipa, ipb) != 0 {
+ t.Errorf("CopyIP() failed to copy (value of copied IP does not match original)!")
+ }
+}
+
var IPTests = []struct {
ipaddr net.IP
next net.IP
diff --git a/net4.go b/net4.go
index 60d2921..33e74a3 100644
--- a/net4.go
+++ b/net4.go
@@ -1,7 +1,9 @@
package iplib
import (
+ "crypto/rand"
"math"
+ "math/big"
"net"
"sync"
)
@@ -106,7 +108,7 @@ func (n Net4) Enumerate(size, offset int) []net.IP {
// Handle edge-case mask sizes
if count == 1 { // Count() returns 1 if host-bits == 0
- return []net.IP{getCloneIP(n.IPNet.IP)}
+ return []net.IP{CopyIP(n.IPNet.IP)}
}
addrs := make([]net.IP, size)
@@ -209,7 +211,12 @@ func (n Net4) NextIP(ip net.IP) (net.IP, error) {
// NextNet takes a CIDR mask-size as an argument and attempts to create a new
// Net object just after the current Net, at the requested mask length
func (n Net4) NextNet(masklen int) Net4 {
- return NewNet4(NextIP(n.BroadcastAddress()), masklen)
+ l, _ := n.Mask().Size()
+ nextIP := NextIP(n.BroadcastAddress())
+ if masklen < l {
+ nextIP = IncrementIP4By(nextIP, uint32(math.Pow(2, 32-float64(masklen)))-2)
+ }
+ return NewNet4(nextIP, masklen)
}
// PreviousIP takes a net.IP as an argument and attempts to decrement it by
@@ -245,6 +252,13 @@ func (n Net4) PreviousNet(masklen int) Net4 {
return NewNet4(PreviousIP(n.IP()), masklen)
}
+// RandomIP returns a random address from this Net4. It uses crypto/rand and
+// *big.Int so is not the most performant implementation possible
+func (n Net4) RandomIP() net.IP {
+ z, _ := rand.Int(rand.Reader, big.NewInt(int64(n.Count())))
+ return IncrementIP4By(n.IP(), uint32(z.Uint64()))
+}
+
// String returns the CIDR notation of the enclosed network e.g. 192.168.0.1/24
func (n Net4) String() string {
return n.IPNet.String()
diff --git a/net4_test.go b/net4_test.go
index cc599e4..fd8d176 100644
--- a/net4_test.go
+++ b/net4_test.go
@@ -389,9 +389,11 @@ var incr4SubnetTests = []struct {
netmask int
next Net4
}{
+ {Net4FromStr("192.168.0.0/24"), 21, Net4FromStr("192.168.8.0/21")},
+ {Net4FromStr("192.168.0.0/24"), 22, Net4FromStr("192.168.4.0/22")},
+ {Net4FromStr("192.168.0.0/24"), 23, Net4FromStr("192.168.2.0/23")},
{Net4FromStr("192.168.0.0/24"), 24, Net4FromStr("192.168.1.0/24")},
{Net4FromStr("192.168.0.0/24"), 25, Net4FromStr("192.168.1.0/25")},
- {Net4FromStr("192.168.0.0/24"), 23, Net4FromStr("192.168.0.0/23")},
{Net4FromStr("255.255.255.0/24"), 24, Net4FromStr("255.255.255.0/24")},
}
@@ -626,9 +628,17 @@ func TestNet4_ContainsNet(t *testing.T) {
}
}
+func TestNet4_RandomIP(t *testing.T) {
+ for i, tt := range containsNet4Tests {
+ rip := tt.ipn1.RandomIP()
+ if !tt.ipn1.Contains(rip) {
+ t.Errorf("[%d] address %s not in %s", i, rip, tt.ipn1)
+ }
+ }
+}
+
func TestNet4_Is4in6(t *testing.T) {
nf := Net4FromStr("192.168.0.0./16")
- //nf := NewNet4(ForceIP4(net.ParseIP("192.168.0.0")), 16)
if nf.Is4in6() != false {
t.Errorf("should be false for '192.168.0.0/16'")
}
diff --git a/net6.go b/net6.go
index d5257e4..584f421 100644
--- a/net6.go
+++ b/net6.go
@@ -1,6 +1,7 @@
package iplib
import (
+ "crypto/rand"
"math"
"math/big"
"net"
@@ -147,13 +148,13 @@ func (n Net6) Enumerate(size, offset int) []net.IP {
// workload in this way simply ensures that we [a] can dynamically expand
// our worker-pool based on request size; and [b] don't have to worry
// about exhausting some upper bound of goroutines -- enumerate requests
- // are limited to MaxInt32, so we won't generate more than 32768
+ // are limited to MaxUint32, so we won't generate more than 65536
limit := uint32(65535)
pos := uint32(0)
wg := sync.WaitGroup{}
for pos < count {
incr := limit
- if limit > count - pos {
+ if limit > count-pos {
incr = count - pos
}
wg.Add(1)
@@ -173,7 +174,7 @@ func (n Net6) Enumerate(size, offset int) []net.IP {
// FirstAddress returns the first usable address for the represented network
func (n Net6) FirstAddress() net.IP {
- return getCloneIP(n.IP())
+ return CopyIP(n.IP())
}
// LastAddress returns the last usable address for the represented network
@@ -248,6 +249,13 @@ func (n Net6) PreviousNet(masklen int) Net6 {
return NewNet6(xip, masklen, hmlen)
}
+// RandomIP returns a random address from this Net6. It uses crypto/rand and
+// so is not the most performant implementation possible
+func (n Net6) RandomIP() net.IP {
+ z, _ := rand.Int(rand.Reader, n.Count())
+ return IncrementIP6By(n.FirstAddress(), z)
+}
+
// String returns the CIDR notation of the enclosed network e.g. 2001:db8::/16
func (n Net6) String() string {
return n.IPNet.String()
diff --git a/net6_test.go b/net6_test.go
index 408908f..01b7fe3 100644
--- a/net6_test.go
+++ b/net6_test.go
@@ -752,6 +752,16 @@ func TestNet6_ContainsNet(t *testing.T) {
}
}
+func TestNet6_RandomIP(t *testing.T) {
+ for i, tt := range containsNet6Tests {
+ _, ipn, _ := ParseCIDR(tt.netblock1)
+ rip := ipn.(Net6).RandomIP()
+ if !ipn.Contains(rip) {
+ t.Errorf("[%d] address %s not in %s", i, rip, ipn)
+ }
+ }
+}
+
var controlsTests = []struct {
ipn Net6
addrs map[string]bool
Debdiff
File lists identical (after any substitutions)
No differences were encountered in the control files