Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/protocols/common/randomip/randomip.go
2072 views
1
package randomip
2
3
import (
4
"crypto/rand"
5
"net"
6
7
"github.com/pkg/errors"
8
iputil "github.com/projectdiscovery/utils/ip"
9
randutil "github.com/projectdiscovery/utils/rand"
10
)
11
12
const (
13
maxIterations = 255
14
)
15
16
func GetRandomIPWithCidr(cidrs ...string) (net.IP, error) {
17
if len(cidrs) == 0 {
18
return nil, errors.Errorf("must specify at least one cidr")
19
}
20
21
randIdx, err := randutil.IntN(len(cidrs))
22
if err != nil {
23
return nil, err
24
}
25
26
cidr := cidrs[randIdx]
27
28
if !iputil.IsCIDR(cidr) {
29
return nil, errors.Errorf("%s is not a valid cidr", cidr)
30
}
31
32
baseIp, ipnet, err := net.ParseCIDR(cidr)
33
if err != nil {
34
return nil, err
35
}
36
37
switch {
38
case ipnet.Mask[len(ipnet.Mask)-1] == 255:
39
return baseIp, nil
40
case iputil.IsIPv4(baseIp.String()):
41
return getRandomIP(ipnet, 4), nil
42
case iputil.IsIPv6(baseIp.String()):
43
return getRandomIP(ipnet, 16), nil
44
default:
45
return nil, errors.New("invalid base ip")
46
}
47
}
48
49
func getRandomIP(ipnet *net.IPNet, size int) net.IP {
50
ip := ipnet.IP
51
var iteration int
52
53
for iteration < maxIterations {
54
iteration++
55
ones, _ := ipnet.Mask.Size()
56
quotient := ones / 8
57
remainder := ones % 8
58
var r []byte
59
switch size {
60
case 4, 16:
61
r = make([]byte, size)
62
default:
63
return ip
64
}
65
66
_, err := rand.Read(r)
67
if err != nil {
68
break
69
}
70
71
for i := 0; i <= quotient; i++ {
72
if i == quotient {
73
shifted := byte(r[i]) >> remainder
74
r[i] = ipnet.IP[i] + (^ipnet.IP[i] & shifted)
75
} else {
76
r[i] = ipnet.IP[i]
77
}
78
}
79
80
ip = r
81
82
if !ip.Equal(ipnet.IP) {
83
break
84
}
85
}
86
87
return ip
88
}
89
90