Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package connection_limits
  4. import (
  5. "errors"
  6. "fmt"
  7. "net"
  8. "sync"
  9. )
  10. // LimiterConfig controls the automated connection limits.
  11. type LimiterConfig struct {
  12. Enabled bool
  13. CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
  14. CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
  15. ConnsPerSubnet int `yaml:"connections-per-subnet"`
  16. IPsPerSubnet int `yaml:"ips-per-subnet"` // legacy name for ConnsPerSubnet
  17. Exempted []string
  18. }
  19. var (
  20. errTooManyClients = errors.New("Too many clients in subnet")
  21. )
  22. // Limiter manages the automated client connection limits.
  23. type Limiter struct {
  24. sync.Mutex
  25. enabled bool
  26. ipv4Mask net.IPMask
  27. ipv6Mask net.IPMask
  28. // subnetLimit is the maximum number of clients per subnet
  29. subnetLimit int
  30. // population holds IP -> count of clients connected from there
  31. population map[string]int
  32. // exemptedIPs holds IPs that are exempt from limits
  33. exemptedIPs map[string]bool
  34. // exemptedNets holds networks that are exempt from limits
  35. exemptedNets []net.IPNet
  36. }
  37. // maskAddr masks the given IPv4/6 address with our cidr limit masks.
  38. func (cl *Limiter) maskAddr(addr net.IP) net.IP {
  39. if addr.To4() == nil {
  40. // IPv6 addr
  41. addr = addr.Mask(cl.ipv6Mask)
  42. } else {
  43. // IPv4 addr
  44. addr = addr.Mask(cl.ipv4Mask)
  45. }
  46. return addr
  47. }
  48. // AddClient adds a client to our population if possible. If we can't, throws an error instead.
  49. // 'force' is used to add already-existing clients (i.e. ones that are already on the network).
  50. func (cl *Limiter) AddClient(addr net.IP, force bool) error {
  51. cl.Lock()
  52. defer cl.Unlock()
  53. if !cl.enabled {
  54. return nil
  55. }
  56. // check exempted lists
  57. // we don't track populations for exempted addresses or nets - this is by design
  58. if cl.exemptedIPs[addr.String()] {
  59. return nil
  60. }
  61. for _, ex := range cl.exemptedNets {
  62. if ex.Contains(addr) {
  63. return nil
  64. }
  65. }
  66. // check population
  67. cl.maskAddr(addr)
  68. addrString := addr.String()
  69. if cl.population[addrString]+1 > cl.subnetLimit && !force {
  70. return errTooManyClients
  71. }
  72. cl.population[addrString] = cl.population[addrString] + 1
  73. return nil
  74. }
  75. // RemoveClient removes the given address from our population
  76. func (cl *Limiter) RemoveClient(addr net.IP) {
  77. cl.Lock()
  78. defer cl.Unlock()
  79. if !cl.enabled {
  80. return
  81. }
  82. addrString := addr.String()
  83. cl.population[addrString] = cl.population[addrString] - 1
  84. // safety limiter
  85. if cl.population[addrString] < 0 {
  86. cl.population[addrString] = 0
  87. }
  88. }
  89. // NewLimiter returns a new connection limit handler.
  90. // The handler is functional, but disabled; it can be enabled via `ApplyConfig`.
  91. func NewLimiter() *Limiter {
  92. var cl Limiter
  93. // initialize empty population; all other state is configurable
  94. cl.population = make(map[string]int)
  95. return &cl
  96. }
  97. // ApplyConfig atomically applies a config update to a connection limit handler
  98. func (cl *Limiter) ApplyConfig(config LimiterConfig) error {
  99. // assemble exempted nets
  100. exemptedIPs := make(map[string]bool)
  101. var exemptedNets []net.IPNet
  102. for _, cidr := range config.Exempted {
  103. ipaddr := net.ParseIP(cidr)
  104. _, netaddr, err := net.ParseCIDR(cidr)
  105. if ipaddr == nil && err != nil {
  106. return fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
  107. }
  108. if ipaddr != nil {
  109. exemptedIPs[ipaddr.String()] = true
  110. } else {
  111. exemptedNets = append(exemptedNets, *netaddr)
  112. }
  113. }
  114. cl.Lock()
  115. defer cl.Unlock()
  116. cl.enabled = config.Enabled
  117. cl.ipv4Mask = net.CIDRMask(config.CidrLenIPv4, 32)
  118. cl.ipv6Mask = net.CIDRMask(config.CidrLenIPv6, 128)
  119. // subnetLimit is explicitly NOT capped at a minimum of one.
  120. // this is so that CL config can be used to allow ONLY clients from exempted IPs/nets
  121. cl.subnetLimit = config.ConnsPerSubnet
  122. // but: check if the current key was left unset, but the legacy was set:
  123. if cl.subnetLimit == 0 && config.IPsPerSubnet != 0 {
  124. cl.subnetLimit = config.IPsPerSubnet
  125. }
  126. cl.exemptedIPs = exemptedIPs
  127. cl.exemptedNets = exemptedNets
  128. return nil
  129. }