52 lines
1.1 KiB
Go
52 lines
1.1 KiB
Go
package common
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math/big"
|
|
"net"
|
|
)
|
|
|
|
func iptouint(ip net.IP) uint32 {
|
|
ip = ip.To4()
|
|
return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
|
|
}
|
|
|
|
func toip(num uint32) string {
|
|
return fmt.Sprintf("%d.%d.%d.%d",
|
|
(num>>24)&255,
|
|
(num>>16)&255,
|
|
(num>>8)&255,
|
|
num&255)
|
|
}
|
|
|
|
func seed() int64 {
|
|
var n int64
|
|
if err := binary.Read(rand.Reader, binary.LittleEndian, &n); err != nil {
|
|
return 1337
|
|
}
|
|
return n
|
|
}
|
|
|
|
// per-cidr linear congruential generator for efficient randomized target ip ordering, ty claude
|
|
func LCG(cidr string, out chan<- string) {
|
|
// lcg constants
|
|
const a uint64 = 1664525
|
|
const c uint64 = 1013904223
|
|
|
|
_, ipnet, _ := net.ParseCIDR(cidr)
|
|
start := iptouint(ipnet.IP)
|
|
ones, bits := ipnet.Mask.Size()
|
|
addrcount := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
|
|
|
|
x := uint64(seed()) ^ uint64(start) // seed for unique randomization per execution
|
|
m := uint64(addrcount.Uint64())
|
|
|
|
for i := uint64(0); i < m; i++ {
|
|
x = (a*x + c) % (1 << 32) // mod of full 32bit addr count
|
|
ip := toip(uint32((x % m) + uint64(start)))
|
|
out <- ip
|
|
}
|
|
}
|