72 lines
1.1 KiB
Go
Raw Normal View History

2022-03-21 17:39:10 -07:00
package randomip
import (
"math/rand"
"net"
2022-03-22 15:16:22 +01:00
"github.com/pkg/errors"
"github.com/projectdiscovery/iputil"
2022-03-21 17:39:10 -07:00
)
2022-03-22 15:16:22 +01:00
const (
maxIterations = 255
)
2022-03-21 17:39:10 -07:00
2022-03-22 15:16:22 +01:00
func GetRandomIPWithCidr(cidr string) (net.IP, error) {
if !iputil.IsCIDR(cidr) {
return nil, errors.Errorf("%s is not a valid cidr", cidr)
2022-03-21 17:39:10 -07:00
}
2022-03-22 15:16:22 +01:00
baseIp, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
2022-03-21 17:39:10 -07:00
}
2022-03-22 15:16:22 +01:00
switch {
case iputil.IsIPv4(baseIp.String()):
return getRandomIP(ipnet, 4), nil
case iputil.IsIPv6(baseIp.String()):
return getRandomIP(ipnet, 16), nil
default:
return nil, errors.New("invalid base ip")
}
2022-03-21 17:39:10 -07:00
}
2022-03-22 15:16:22 +01:00
func getRandomIP(ipnet *net.IPNet, size int) net.IP {
ip := ipnet.IP
var iteration int
2022-03-21 17:39:10 -07:00
2022-03-22 15:16:22 +01:00
for iteration < maxIterations {
iteration++
ones, _ := ipnet.Mask.Size()
quotient := ones / 8
remainder := ones % 8
var r []byte
switch size {
case 4, 16:
r = make([]byte, size)
default:
return ip
}
2022-03-21 17:39:10 -07:00
2022-03-22 15:16:22 +01:00
rand.Read(r)
2022-03-21 17:39:10 -07:00
2022-03-22 15:16:22 +01:00
for i := 0; i <= quotient; i++ {
if i == quotient {
shifted := byte(r[i]) >> remainder
r[i] = ^ipnet.IP[i] & shifted
} else {
r[i] = ipnet.IP[i]
}
2022-03-21 17:39:10 -07:00
}
2022-03-22 15:16:22 +01:00
ip = r
2022-03-21 17:39:10 -07:00
2022-03-22 15:16:22 +01:00
if !ip.Equal(ipnet.IP) {
break
}
2022-03-21 17:39:10 -07:00
}
return ip
}