tree4.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package cidr
  2. import (
  3. "net"
  4. "github.com/slackhq/nebula/iputil"
  5. )
  6. type Node struct {
  7. left *Node
  8. right *Node
  9. parent *Node
  10. value interface{}
  11. }
  12. type Tree4 struct {
  13. root *Node
  14. }
  15. const (
  16. startbit = iputil.VpnIp(0x80000000)
  17. )
  18. func NewTree4() *Tree4 {
  19. tree := new(Tree4)
  20. tree.root = &Node{}
  21. return tree
  22. }
  23. func (tree *Tree4) AddCIDR(cidr *net.IPNet, val interface{}) {
  24. bit := startbit
  25. node := tree.root
  26. next := tree.root
  27. ip := iputil.Ip2VpnIp(cidr.IP)
  28. mask := iputil.Ip2VpnIp(cidr.Mask)
  29. // Find our last ancestor in the tree
  30. for bit&mask != 0 {
  31. if ip&bit != 0 {
  32. next = node.right
  33. } else {
  34. next = node.left
  35. }
  36. if next == nil {
  37. break
  38. }
  39. bit = bit >> 1
  40. node = next
  41. }
  42. // We already have this range so update the value
  43. if next != nil {
  44. node.value = val
  45. return
  46. }
  47. // Build up the rest of the tree we don't already have
  48. for bit&mask != 0 {
  49. next = &Node{}
  50. next.parent = node
  51. if ip&bit != 0 {
  52. node.right = next
  53. } else {
  54. node.left = next
  55. }
  56. bit >>= 1
  57. node = next
  58. }
  59. // Final node marks our cidr, set the value
  60. node.value = val
  61. }
  62. // Finds the first match, which may be the least specific
  63. func (tree *Tree4) Contains(ip iputil.VpnIp) (value interface{}) {
  64. bit := startbit
  65. node := tree.root
  66. for node != nil {
  67. if node.value != nil {
  68. return node.value
  69. }
  70. if ip&bit != 0 {
  71. node = node.right
  72. } else {
  73. node = node.left
  74. }
  75. bit >>= 1
  76. }
  77. return value
  78. }
  79. // Finds the most specific match
  80. func (tree *Tree4) MostSpecificContains(ip iputil.VpnIp) (value interface{}) {
  81. bit := startbit
  82. node := tree.root
  83. for node != nil {
  84. if node.value != nil {
  85. value = node.value
  86. }
  87. if ip&bit != 0 {
  88. node = node.right
  89. } else {
  90. node = node.left
  91. }
  92. bit >>= 1
  93. }
  94. return value
  95. }
  96. // Finds the most specific match
  97. func (tree *Tree4) Match(ip iputil.VpnIp) (value interface{}) {
  98. bit := startbit
  99. node := tree.root
  100. lastNode := node
  101. for node != nil {
  102. lastNode = node
  103. if ip&bit != 0 {
  104. node = node.right
  105. } else {
  106. node = node.left
  107. }
  108. bit >>= 1
  109. }
  110. if bit == 0 && lastNode != nil {
  111. value = lastNode.value
  112. }
  113. return value
  114. }