Path: blob/dev/pkg/protocols/common/randomip/randomip.go
2072 views
package randomip12import (3"crypto/rand"4"net"56"github.com/pkg/errors"7iputil "github.com/projectdiscovery/utils/ip"8randutil "github.com/projectdiscovery/utils/rand"9)1011const (12maxIterations = 25513)1415func GetRandomIPWithCidr(cidrs ...string) (net.IP, error) {16if len(cidrs) == 0 {17return nil, errors.Errorf("must specify at least one cidr")18}1920randIdx, err := randutil.IntN(len(cidrs))21if err != nil {22return nil, err23}2425cidr := cidrs[randIdx]2627if !iputil.IsCIDR(cidr) {28return nil, errors.Errorf("%s is not a valid cidr", cidr)29}3031baseIp, ipnet, err := net.ParseCIDR(cidr)32if err != nil {33return nil, err34}3536switch {37case ipnet.Mask[len(ipnet.Mask)-1] == 255:38return baseIp, nil39case iputil.IsIPv4(baseIp.String()):40return getRandomIP(ipnet, 4), nil41case iputil.IsIPv6(baseIp.String()):42return getRandomIP(ipnet, 16), nil43default:44return nil, errors.New("invalid base ip")45}46}4748func getRandomIP(ipnet *net.IPNet, size int) net.IP {49ip := ipnet.IP50var iteration int5152for iteration < maxIterations {53iteration++54ones, _ := ipnet.Mask.Size()55quotient := ones / 856remainder := ones % 857var r []byte58switch size {59case 4, 16:60r = make([]byte, size)61default:62return ip63}6465_, err := rand.Read(r)66if err != nil {67break68}6970for i := 0; i <= quotient; i++ {71if i == quotient {72shifted := byte(r[i]) >> remainder73r[i] = ipnet.IP[i] + (^ipnet.IP[i] & shifted)74} else {75r[i] = ipnet.IP[i]76}77}7879ip = r8081if !ip.Equal(ipnet.IP) {82break83}84}8586return ip87}888990