whitelist_net.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package whitelist
  2. // This file contains a variant of the ACL that operates on
  3. // netblocks. It will mimic as much of the code in whitelist.go
  4. // that is needed to support network whitelists.
  5. import (
  6. "errors"
  7. "log"
  8. "net"
  9. "strings"
  10. "sync"
  11. )
  12. // A NetACL stores a list of permitted IP networks.
  13. type NetACL interface {
  14. ACL
  15. // Add takes an IP network and adds it to the whitelist so
  16. // that it is now permitted.
  17. Add(*net.IPNet)
  18. // Remove takes an IP network and drops it from the whitelist
  19. // so that it is no longer permitted.
  20. Remove(*net.IPNet)
  21. }
  22. // BasicNet implements a basic map-backed network whitelist using
  23. // locks for concurrency. It must be initialised with one of the
  24. // constructor functions. This particular implementation is
  25. // unoptimised and will not scale.
  26. type BasicNet struct {
  27. lock *sync.Mutex
  28. whitelist []*net.IPNet
  29. }
  30. // Permitted returns true if the IP has been whitelisted.
  31. func (wl *BasicNet) Permitted(ip net.IP) bool {
  32. if !validIP(ip) { // see whitelist.go for this function
  33. return false
  34. }
  35. wl.lock.Lock()
  36. defer wl.lock.Unlock()
  37. for i := range wl.whitelist {
  38. if wl.whitelist[i].Contains(ip) {
  39. return true
  40. }
  41. }
  42. return false
  43. }
  44. // BUG(kyle): overlapping networks aren't detected.
  45. // Add adds a new network to the whitelist. Caveat: overlapping
  46. // networks won't be detected.
  47. func (wl *BasicNet) Add(n *net.IPNet) {
  48. if n == nil {
  49. return
  50. }
  51. wl.lock.Lock()
  52. defer wl.lock.Unlock()
  53. wl.whitelist = append(wl.whitelist, n)
  54. }
  55. // Remove removes a network from the whitelist.
  56. func (wl *BasicNet) Remove(n *net.IPNet) {
  57. if n == nil {
  58. return
  59. }
  60. index := -1
  61. wl.lock.Lock()
  62. defer wl.lock.Unlock()
  63. for i := range wl.whitelist {
  64. if wl.whitelist[i].String() == n.String() {
  65. index = i
  66. break
  67. }
  68. }
  69. if index == -1 {
  70. return
  71. }
  72. wl.whitelist = append(wl.whitelist[:index], wl.whitelist[index+1:]...)
  73. }
  74. // NewBasicNet constructs a new basic network-based whitelist.
  75. func NewBasicNet() *BasicNet {
  76. return &BasicNet{
  77. lock: new(sync.Mutex),
  78. }
  79. }
  80. // MarshalJSON serialises a network whitelist to a comma-separated
  81. // list of networks.
  82. func (wl *BasicNet) MarshalJSON() ([]byte, error) {
  83. var ss = make([]string, 0, len(wl.whitelist))
  84. for i := range wl.whitelist {
  85. ss = append(ss, wl.whitelist[i].String())
  86. }
  87. out := []byte(`"` + strings.Join(ss, ",") + `"`)
  88. return out, nil
  89. }
  90. // UnmarshalJSON implements the json.Unmarshaler interface for network
  91. // whitelists, taking a comma-separated string of networks.
  92. func (wl *BasicNet) UnmarshalJSON(in []byte) error {
  93. if in[0] != '"' || in[len(in)-1] != '"' {
  94. return errors.New("whitelist: invalid whitelist")
  95. }
  96. if wl.lock == nil {
  97. wl.lock = new(sync.Mutex)
  98. }
  99. wl.lock.Lock()
  100. defer wl.lock.Unlock()
  101. var err error
  102. netString := strings.TrimSpace(string(in[1 : len(in)-1]))
  103. nets := strings.Split(netString, ",")
  104. wl.whitelist = make([]*net.IPNet, len(nets))
  105. for i := range nets {
  106. addr := strings.TrimSpace(nets[i])
  107. if addr == "" {
  108. continue
  109. }
  110. _, wl.whitelist[i], err = net.ParseCIDR(addr)
  111. if err != nil {
  112. wl.whitelist = nil
  113. return err
  114. }
  115. }
  116. return nil
  117. }
  118. // NetStub allows network whitelisting to be added into a system's
  119. // flow without doing anything yet. All operations result in warning
  120. // log messages being printed to stderr. There is no mechanism for
  121. // squelching these messages short of modifying the log package's
  122. // default logger.
  123. type NetStub struct{}
  124. // Permitted always returns true, but prints a warning message alerting
  125. // that whitelisting is stubbed.
  126. func (wl NetStub) Permitted(ip net.IP) bool {
  127. log.Printf("WARNING: whitelist check for %s but whitelisting is stubbed", ip)
  128. return true
  129. }
  130. // Add prints a warning message about whitelisting being stubbed.
  131. func (wl NetStub) Add(ip *net.IPNet) {
  132. log.Printf("WARNING: IP network %s added to whitelist but whitelisting is stubbed", ip)
  133. }
  134. // Remove prints a warning message about whitelisting being stubbed.
  135. func (wl NetStub) Remove(ip *net.IPNet) {
  136. log.Printf("WARNING: IP network %s removed from whitelist but whitelisting is stubbed", ip)
  137. }
  138. // NewNetStub returns a new stubbed network whitelister.
  139. func NewNetStub() NetStub {
  140. log.Println("WARNING: whitelisting is being stubbed")
  141. return NetStub{}
  142. }