You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

224 rivejä
5.6 KiB

  1. /*
  2. MIT License
  3. Copyright © 2016 <dev@jpillora.com>
  4. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  5. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  6. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  7. */
  8. package utils
  9. import (
  10. "log"
  11. "net"
  12. "net/http"
  13. "os"
  14. "sync"
  15. "github.com/tomasen/realip"
  16. )
  17. //IPFilterOptions for IPFilter. Allowed takes precendence over Blocked.
  18. //IPs can be IPv4 or IPv6 and can optionally contain subnet
  19. //masks (/24). Note however, determining if a given IP is
  20. //included in a subnet requires a linear scan so is less performant
  21. //than looking up single IPs.
  22. //
  23. //This could be improved with some algorithmic magic.
  24. type IPFilterOptions struct {
  25. //explicity allowed IPs
  26. AllowedIPs []string
  27. //explicity blocked IPs
  28. BlockedIPs []string
  29. //block by default (defaults to allow)
  30. BlockByDefault bool
  31. // TrustProxy enable check request IP from proxy
  32. TrustProxy bool
  33. Logger interface {
  34. Printf(format string, v ...interface{})
  35. }
  36. }
  37. type IPFilter struct {
  38. opts IPFilterOptions
  39. //mut protects the below
  40. //rw since writes are rare
  41. mut sync.RWMutex
  42. defaultAllowed bool
  43. ips map[string]bool
  44. subnets []*subnet
  45. }
  46. type subnet struct {
  47. str string
  48. ipnet *net.IPNet
  49. allowed bool
  50. }
  51. func IPFilterHandler(h http.Handler, ipFilterOptions *IPFilterOptions) http.HandlerFunc {
  52. return func(w http.ResponseWriter, r *http.Request) {
  53. if ipFilterOptions == nil {
  54. h.ServeHTTP(w, r)
  55. } else {
  56. WrapIPFilter(h, *ipFilterOptions).ServeHTTP(w, r)
  57. }
  58. return
  59. }
  60. }
  61. //New constructs IPFilter instance.
  62. func NewIPFilter(opts IPFilterOptions) *IPFilter {
  63. if opts.Logger == nil {
  64. flags := log.LstdFlags
  65. opts.Logger = log.New(os.Stdout, "", flags)
  66. }
  67. f := &IPFilter{
  68. opts: opts,
  69. ips: map[string]bool{},
  70. defaultAllowed: !opts.BlockByDefault,
  71. }
  72. for _, ip := range opts.BlockedIPs {
  73. f.BlockIP(ip)
  74. }
  75. for _, ip := range opts.AllowedIPs {
  76. f.AllowIP(ip)
  77. }
  78. return f
  79. }
  80. func (f *IPFilter) AllowIP(ip string) bool {
  81. return f.ToggleIP(ip, true)
  82. }
  83. func (f *IPFilter) BlockIP(ip string) bool {
  84. return f.ToggleIP(ip, false)
  85. }
  86. func (f *IPFilter) ToggleIP(str string, allowed bool) bool {
  87. //check if has subnet
  88. if ip, net, err := net.ParseCIDR(str); err == nil {
  89. // containing only one ip?
  90. if n, total := net.Mask.Size(); n == total {
  91. f.mut.Lock()
  92. f.ips[ip.String()] = allowed
  93. f.mut.Unlock()
  94. return true
  95. }
  96. //check for existing
  97. f.mut.Lock()
  98. found := false
  99. for _, subnet := range f.subnets {
  100. if subnet.str == str {
  101. found = true
  102. subnet.allowed = allowed
  103. break
  104. }
  105. }
  106. if !found {
  107. f.subnets = append(f.subnets, &subnet{
  108. str: str,
  109. ipnet: net,
  110. allowed: allowed,
  111. })
  112. }
  113. f.mut.Unlock()
  114. return true
  115. }
  116. //check if plain ip
  117. if ip := net.ParseIP(str); ip != nil {
  118. f.mut.Lock()
  119. f.ips[ip.String()] = allowed
  120. f.mut.Unlock()
  121. return true
  122. }
  123. return false
  124. }
  125. //ToggleDefault alters the default setting
  126. func (f *IPFilter) ToggleDefault(allowed bool) {
  127. f.mut.Lock()
  128. f.defaultAllowed = allowed
  129. f.mut.Unlock()
  130. }
  131. //Allowed returns if a given IP can pass through the filter
  132. func (f *IPFilter) Allowed(ipstr string) bool {
  133. return f.NetAllowed(net.ParseIP(ipstr))
  134. }
  135. //NetAllowed returns if a given net.IP can pass through the filter
  136. func (f *IPFilter) NetAllowed(ip net.IP) bool {
  137. //invalid ip
  138. if ip == nil {
  139. return false
  140. }
  141. //read lock entire function
  142. //except for db access
  143. f.mut.RLock()
  144. defer f.mut.RUnlock()
  145. //check single ips
  146. allowed, ok := f.ips[ip.String()]
  147. if ok {
  148. return allowed
  149. }
  150. //scan subnets for any allow/block
  151. blocked := false
  152. for _, subnet := range f.subnets {
  153. if subnet.ipnet.Contains(ip) {
  154. if subnet.allowed {
  155. return true
  156. }
  157. blocked = true
  158. }
  159. }
  160. if blocked {
  161. return false
  162. }
  163. //use default setting
  164. return f.defaultAllowed
  165. }
  166. //Blocked returns if a given IP can NOT pass through the filter
  167. func (f *IPFilter) Blocked(ip string) bool {
  168. return !f.Allowed(ip)
  169. }
  170. //NetBlocked returns if a given net.IP can NOT pass through the filter
  171. func (f *IPFilter) NetBlocked(ip net.IP) bool {
  172. return !f.NetAllowed(ip)
  173. }
  174. //WrapIPFilter the provided handler with simple IP blocking middleware
  175. //using this IP filter and its configuration
  176. func (f *IPFilter) Wrap(next http.Handler) http.Handler {
  177. return &ipFilterMiddleware{IPFilter: f, next: next}
  178. }
  179. //WrapIPFilter is equivalent to NewIPFilter(opts) then Wrap(next)
  180. func WrapIPFilter(next http.Handler, opts IPFilterOptions) http.Handler {
  181. return NewIPFilter(opts).Wrap(next)
  182. }
  183. type ipFilterMiddleware struct {
  184. *IPFilter
  185. next http.Handler
  186. }
  187. func (m *ipFilterMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  188. remoteIP := realip.FromRequest(r)
  189. if !m.IPFilter.Allowed(remoteIP) {
  190. //show simple forbidden text
  191. http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
  192. return
  193. }
  194. //success!
  195. m.next.ServeHTTP(w, r)
  196. }