calculated_remote.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package nebula
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "math"
  6. "net"
  7. "net/netip"
  8. "strconv"
  9. "github.com/gaissmai/bart"
  10. "github.com/slackhq/nebula/config"
  11. )
  12. // This allows us to "guess" what the remote might be for a host while we wait
  13. // for the lighthouse response. See "lighthouse.calculated_remotes" in the
  14. // example config file.
  15. type calculatedRemote struct {
  16. ipNet netip.Prefix
  17. mask netip.Prefix
  18. port uint32
  19. }
  20. func newCalculatedRemote(cidr, maskCidr netip.Prefix, port int) (*calculatedRemote, error) {
  21. if maskCidr.Addr().BitLen() != cidr.Addr().BitLen() {
  22. return nil, fmt.Errorf("invalid mask: %s for cidr: %s", maskCidr, cidr)
  23. }
  24. masked := maskCidr.Masked()
  25. if port < 0 || port > math.MaxUint16 {
  26. return nil, fmt.Errorf("invalid port: %d", port)
  27. }
  28. return &calculatedRemote{
  29. ipNet: maskCidr,
  30. mask: masked,
  31. port: uint32(port),
  32. }, nil
  33. }
  34. func (c *calculatedRemote) String() string {
  35. return fmt.Sprintf("CalculatedRemote(mask=%v port=%d)", c.ipNet, c.port)
  36. }
  37. func (c *calculatedRemote) ApplyV4(addr netip.Addr) *V4AddrPort {
  38. // Combine the masked bytes of the "mask" IP with the unmasked bytes of the overlay IP
  39. maskb := net.CIDRMask(c.mask.Bits(), c.mask.Addr().BitLen())
  40. mask := binary.BigEndian.Uint32(maskb[:])
  41. b := c.mask.Addr().As4()
  42. maskAddr := binary.BigEndian.Uint32(b[:])
  43. b = addr.As4()
  44. intAddr := binary.BigEndian.Uint32(b[:])
  45. return &V4AddrPort{(maskAddr & mask) | (intAddr & ^mask), c.port}
  46. }
  47. func (c *calculatedRemote) ApplyV6(addr netip.Addr) *V6AddrPort {
  48. mask := net.CIDRMask(c.mask.Bits(), c.mask.Addr().BitLen())
  49. maskAddr := c.mask.Addr().As16()
  50. calcAddr := addr.As16()
  51. ap := V6AddrPort{Port: c.port}
  52. maskb := binary.BigEndian.Uint64(mask[:8])
  53. maskAddrb := binary.BigEndian.Uint64(maskAddr[:8])
  54. calcAddrb := binary.BigEndian.Uint64(calcAddr[:8])
  55. ap.Hi = (maskAddrb & maskb) | (calcAddrb & ^maskb)
  56. maskb = binary.BigEndian.Uint64(mask[8:])
  57. maskAddrb = binary.BigEndian.Uint64(maskAddr[8:])
  58. calcAddrb = binary.BigEndian.Uint64(calcAddr[8:])
  59. ap.Lo = (maskAddrb & maskb) | (calcAddrb & ^maskb)
  60. return &ap
  61. }
  62. func NewCalculatedRemotesFromConfig(c *config.C, k string) (*bart.Table[[]*calculatedRemote], error) {
  63. value := c.Get(k)
  64. if value == nil {
  65. return nil, nil
  66. }
  67. calculatedRemotes := new(bart.Table[[]*calculatedRemote])
  68. rawMap, ok := value.(map[any]any)
  69. if !ok {
  70. return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value)
  71. }
  72. for rawKey, rawValue := range rawMap {
  73. rawCIDR, ok := rawKey.(string)
  74. if !ok {
  75. return nil, fmt.Errorf("config `%s` has invalid key (type %T): %v", k, rawKey, rawKey)
  76. }
  77. cidr, err := netip.ParsePrefix(rawCIDR)
  78. if err != nil {
  79. return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
  80. }
  81. entry, err := newCalculatedRemotesListFromConfig(cidr, rawValue)
  82. if err != nil {
  83. return nil, fmt.Errorf("config '%s.%s': %w", k, rawCIDR, err)
  84. }
  85. calculatedRemotes.Insert(cidr, entry)
  86. }
  87. return calculatedRemotes, nil
  88. }
  89. func newCalculatedRemotesListFromConfig(cidr netip.Prefix, raw any) ([]*calculatedRemote, error) {
  90. rawList, ok := raw.([]any)
  91. if !ok {
  92. return nil, fmt.Errorf("calculated_remotes entry has invalid type: %T", raw)
  93. }
  94. var l []*calculatedRemote
  95. for _, e := range rawList {
  96. c, err := newCalculatedRemotesEntryFromConfig(cidr, e)
  97. if err != nil {
  98. return nil, fmt.Errorf("calculated_remotes entry: %w", err)
  99. }
  100. l = append(l, c)
  101. }
  102. return l, nil
  103. }
  104. func newCalculatedRemotesEntryFromConfig(cidr netip.Prefix, raw any) (*calculatedRemote, error) {
  105. rawMap, ok := raw.(map[any]any)
  106. if !ok {
  107. return nil, fmt.Errorf("invalid type: %T", raw)
  108. }
  109. rawValue := rawMap["mask"]
  110. if rawValue == nil {
  111. return nil, fmt.Errorf("missing mask: %v", rawMap)
  112. }
  113. rawMask, ok := rawValue.(string)
  114. if !ok {
  115. return nil, fmt.Errorf("invalid mask (type %T): %v", rawValue, rawValue)
  116. }
  117. maskCidr, err := netip.ParsePrefix(rawMask)
  118. if err != nil {
  119. return nil, fmt.Errorf("invalid mask: %s", rawMask)
  120. }
  121. var port int
  122. rawValue = rawMap["port"]
  123. if rawValue == nil {
  124. return nil, fmt.Errorf("missing port: %v", rawMap)
  125. }
  126. switch v := rawValue.(type) {
  127. case int:
  128. port = v
  129. case string:
  130. port, err = strconv.Atoi(v)
  131. if err != nil {
  132. return nil, fmt.Errorf("invalid port: %s: %w", v, err)
  133. }
  134. default:
  135. return nil, fmt.Errorf("invalid port (type %T): %v", rawValue, rawValue)
  136. }
  137. return newCalculatedRemote(cidr, maskCidr, port)
  138. }