Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

connection_limits.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "errors"
  6. "fmt"
  7. "net"
  8. )
  9. var (
  10. errTooManyClients = errors.New("Too many clients in subnet")
  11. )
  12. // ConnectionLimits manages the automated client connection limits.
  13. type ConnectionLimits struct {
  14. enabled bool
  15. ipv4Mask net.IPMask
  16. ipv6Mask net.IPMask
  17. // subnetLimit is the maximum number of clients per subnet
  18. subnetLimit int
  19. // population holds IP -> count of clients connected from there
  20. population map[string]int
  21. // exemptedIPs holds IPs that are exempt from limits
  22. exemptedIPs map[string]bool
  23. // exemptedNets holds networks that are exempt from limits
  24. exemptedNets []net.IPNet
  25. }
  26. // maskAddr masks the given IPv4/6 address with our cidr limit masks.
  27. func (cl *ConnectionLimits) maskAddr(addr net.IP) net.IP {
  28. if addr.To4() == nil {
  29. // IPv6 addr
  30. addr = addr.Mask(cl.ipv6Mask)
  31. } else {
  32. // IPv4 addr
  33. addr = addr.Mask(cl.ipv4Mask)
  34. }
  35. return addr
  36. }
  37. // AddClient adds a client to our population if possible. If we can't, throws an error instead.
  38. // 'force' is used to add already-existing clients (i.e. ones that are already on the network).
  39. func (cl *ConnectionLimits) AddClient(addr net.IP, force bool) error {
  40. if !cl.enabled {
  41. return nil
  42. }
  43. // check exempted lists
  44. // we don't track populations for exempted addresses or nets - this is by design
  45. if cl.exemptedIPs[addr.String()] {
  46. return nil
  47. }
  48. for _, ex := range cl.exemptedNets {
  49. if ex.Contains(addr) {
  50. return nil
  51. }
  52. }
  53. // check population
  54. cl.maskAddr(addr)
  55. addrString := addr.String()
  56. if cl.population[addrString]+1 > cl.subnetLimit && !force {
  57. return errTooManyClients
  58. }
  59. cl.population[addrString] = cl.population[addrString] + 1
  60. return nil
  61. }
  62. // RemoveClient removes the given address from our population
  63. func (cl *ConnectionLimits) RemoveClient(addr net.IP) {
  64. if !cl.enabled {
  65. return
  66. }
  67. addrString := addr.String()
  68. cl.population[addrString] = cl.population[addrString] - 1
  69. // safety limiter
  70. if cl.population[addrString] < 0 {
  71. cl.population[addrString] = 0
  72. }
  73. }
  74. // NewConnectionLimits returns a new connection limit handler.
  75. func NewConnectionLimits(config ConnectionLimitsConfig) (*ConnectionLimits, error) {
  76. var cl ConnectionLimits
  77. cl.enabled = config.Enabled
  78. cl.population = make(map[string]int)
  79. cl.exemptedIPs = make(map[string]bool)
  80. cl.ipv4Mask = net.CIDRMask(config.CidrLenIPv4, 32)
  81. cl.ipv6Mask = net.CIDRMask(config.CidrLenIPv6, 128)
  82. // subnetLimit is explicitly NOT capped at a minimum of one.
  83. // this is so that CL config can be used to allow ONLY clients from exempted IPs/nets
  84. cl.subnetLimit = config.IPsPerCidr
  85. // assemble exempted nets
  86. for _, cidr := range config.Exempted {
  87. ipaddr := net.ParseIP(cidr)
  88. _, netaddr, err := net.ParseCIDR(cidr)
  89. if ipaddr == nil && err != nil {
  90. return nil, fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
  91. }
  92. if ipaddr != nil {
  93. cl.exemptedIPs[ipaddr.String()] = true
  94. } else {
  95. cl.exemptedNets = append(cl.exemptedNets, *netaddr)
  96. }
  97. }
  98. return &cl, nil
  99. }