range.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package addrgen
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/big"
  6. "math/rand"
  7. "net/netip"
  8. "strings"
  9. "github.com/SenseUnit/dtlspipe/randpool"
  10. )
  11. type AddrRange struct {
  12. base *big.Int
  13. size *big.Int
  14. v6 bool
  15. }
  16. var _ AddrGen = &AddrRange{}
  17. func NewAddrRange(start, end netip.Addr) (*AddrRange, error) {
  18. if start.BitLen() != end.BitLen() {
  19. return nil, errors.New("addr bit length mismatch - one of them is IPv4, another is IPv6")
  20. }
  21. if end.Less(start) {
  22. return NewAddrRange(end, start)
  23. }
  24. base := new(big.Int)
  25. base.SetBytes(start.AsSlice())
  26. upper := new(big.Int)
  27. upper.SetBytes(end.AsSlice())
  28. size := new(big.Int)
  29. size.Sub(upper, base)
  30. size.Add(size, big.NewInt(1))
  31. return &AddrRange{
  32. base: base,
  33. size: size,
  34. v6: start.BitLen() == 128,
  35. }, nil
  36. }
  37. func NewAddrRangeFromPrefix(pfx netip.Prefix) (*AddrRange, error) {
  38. if !pfx.IsValid() {
  39. return nil, errors.New("invalid prefix")
  40. }
  41. pfx = pfx.Masked()
  42. addr := pfx.Addr()
  43. base := new(big.Int)
  44. base.SetBytes(addr.AsSlice())
  45. pfxPower := addr.BitLen() - pfx.Bits()
  46. size := big.NewInt(1)
  47. size.Lsh(size, uint(pfxPower))
  48. return &AddrRange{
  49. base: base,
  50. size: size,
  51. v6: addr.BitLen() == 128,
  52. }, nil
  53. }
  54. func (ar *AddrRange) Addr() string {
  55. res := new(big.Int)
  56. randpool.Borrow(func(r *rand.Rand) {
  57. res.Rand(r, ar.size)
  58. })
  59. res.Add(ar.base, res)
  60. var resArr [16]byte
  61. resSlice := resArr[:]
  62. if !ar.v6 {
  63. resSlice = resSlice[:4]
  64. }
  65. res.FillBytes(resSlice)
  66. resAddr, ok := netip.AddrFromSlice(resSlice[:])
  67. if !ok {
  68. panic("can't parse address from slice")
  69. }
  70. return resAddr.String()
  71. }
  72. func (ar *AddrRange) Power() *big.Int {
  73. res := new(big.Int)
  74. res.Set(ar.size)
  75. return res
  76. }
  77. func ParseAddrRangeSpec(spec string) (AddrGen, error) {
  78. switch {
  79. case strings.Contains(spec, "/"):
  80. pfx, err := netip.ParsePrefix(spec)
  81. if err != nil {
  82. return nil, fmt.Errorf("unable to parse prefix %q: %w", spec, err)
  83. }
  84. if pfx.IsSingleIP() {
  85. return SingleAddr(pfx.Addr().String()), nil
  86. }
  87. r, err := NewAddrRangeFromPrefix(pfx)
  88. if err != nil {
  89. return nil, fmt.Errorf("unable to parse range spec %q: %w", spec, err)
  90. }
  91. return r, nil
  92. case strings.Contains(spec, ".."):
  93. parts := strings.SplitN(spec, "..", 2)
  94. start, err := netip.ParseAddr(parts[0])
  95. if err != nil {
  96. return nil, fmt.Errorf("unable to parse addr %q: %w", parts[0], err)
  97. }
  98. end, err := netip.ParseAddr(parts[1])
  99. if err != nil {
  100. return nil, fmt.Errorf("unable to parse addr %q: %w", parts[1], err)
  101. }
  102. r, err := NewAddrRange(start, end)
  103. if err != nil {
  104. return nil, fmt.Errorf("invalid range spec %q: %w", spec, err)
  105. }
  106. return r, nil
  107. }
  108. return SingleAddr(spec), nil
  109. }