Browse Source

Merge pull request #151 from slingamn/limits_refactor.3

refactor connection limits and throttling
tags/v0.10.0
Daniel Oaks 6 years ago
parent
commit
79325d333e
6 changed files with 180 additions and 142 deletions
  1. 1
    3
      irc/client.go
  2. 17
    39
      irc/config.go
  3. 51
    20
      irc/connection_limits/limiter.go
  4. 72
    25
      irc/connection_limits/throttler.go
  5. 38
    54
      irc/server.go
  6. 1
    1
      oragono.yaml

+ 1
- 3
irc/client.go View File

542
 	ipaddr := client.IP()
542
 	ipaddr := client.IP()
543
 	// this check shouldn't be required but eh
543
 	// this check shouldn't be required but eh
544
 	if ipaddr != nil {
544
 	if ipaddr != nil {
545
-		client.server.connectionLimitsMutex.Lock()
546
-		client.server.connectionLimits.RemoveClient(ipaddr)
547
-		client.server.connectionLimitsMutex.Unlock()
545
+		client.server.connectionLimiter.RemoveClient(ipaddr)
548
 	}
546
 	}
549
 
547
 
550
 	// alert monitors
548
 	// alert monitors

+ 17
- 39
irc/config.go View File

15
 	"time"
15
 	"time"
16
 
16
 
17
 	"code.cloudfoundry.org/bytefmt"
17
 	"code.cloudfoundry.org/bytefmt"
18
+	"github.com/oragono/oragono/irc/connection_limits"
18
 	"github.com/oragono/oragono/irc/custime"
19
 	"github.com/oragono/oragono/irc/custime"
19
 	"github.com/oragono/oragono/irc/logger"
20
 	"github.com/oragono/oragono/irc/logger"
20
 	"github.com/oragono/oragono/irc/passwd"
21
 	"github.com/oragono/oragono/irc/passwd"
108
 	return bytes
109
 	return bytes
109
 }
110
 }
110
 
111
 
111
-// ConnectionLimitsConfig controls the automated connection limits.
112
-type ConnectionLimitsConfig struct {
113
-	Enabled     bool
114
-	CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
115
-	CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
116
-	IPsPerCidr  int `yaml:"ips-per-subnet"`
117
-	Exempted    []string
118
-}
119
-
120
-// ConnectionThrottleConfig controls the automated connection throttling.
121
-type ConnectionThrottleConfig struct {
122
-	Enabled            bool
123
-	CidrLenIPv4        int           `yaml:"cidr-len-ipv4"`
124
-	CidrLenIPv6        int           `yaml:"cidr-len-ipv6"`
125
-	ConnectionsPerCidr int           `yaml:"max-connections"`
126
-	DurationString     string        `yaml:"duration"`
127
-	Duration           time.Duration `yaml:"duration-time"`
128
-	BanDurationString  string        `yaml:"ban-duration"`
129
-	BanDuration        time.Duration
130
-	BanMessage         string `yaml:"ban-message"`
131
-	Exempted           []string
132
-}
133
-
134
 // LineLenConfig controls line lengths.
112
 // LineLenConfig controls line lengths.
135
 type LineLenConfig struct {
113
 type LineLenConfig struct {
136
 	Tags int
114
 	Tags int
173
 
151
 
174
 	Server struct {
152
 	Server struct {
175
 		PassConfig
153
 		PassConfig
176
-		Password           string
177
-		Name               string
178
-		Listen             []string
179
-		TLSListeners       map[string]*TLSListenConfig `yaml:"tls-listeners"`
180
-		STS                STSConfig
181
-		CheckIdent         bool `yaml:"check-ident"`
182
-		MOTD               string
183
-		MOTDFormatting     bool     `yaml:"motd-formatting"`
184
-		ProxyAllowedFrom   []string `yaml:"proxy-allowed-from"`
185
-		MaxSendQString     string   `yaml:"max-sendq"`
186
-		MaxSendQBytes      uint64
187
-		ConnectionLimits   ConnectionLimitsConfig   `yaml:"connection-limits"`
188
-		ConnectionThrottle ConnectionThrottleConfig `yaml:"connection-throttling"`
154
+		Password            string
155
+		Name                string
156
+		Listen              []string
157
+		TLSListeners        map[string]*TLSListenConfig `yaml:"tls-listeners"`
158
+		STS                 STSConfig
159
+		CheckIdent          bool `yaml:"check-ident"`
160
+		MOTD                string
161
+		MOTDFormatting      bool     `yaml:"motd-formatting"`
162
+		ProxyAllowedFrom    []string `yaml:"proxy-allowed-from"`
163
+		MaxSendQString      string   `yaml:"max-sendq"`
164
+		MaxSendQBytes       uint64
165
+		ConnectionLimiter   connection_limits.LimiterConfig   `yaml:"connection-limits"`
166
+		ConnectionThrottler connection_limits.ThrottlerConfig `yaml:"connection-throttling"`
189
 	}
167
 	}
190
 
168
 
191
 	Datastore struct {
169
 	Datastore struct {
405
 			return nil, fmt.Errorf("STS port is incorrect, should be 0 if disabled: %d", config.Server.STS.Port)
383
 			return nil, fmt.Errorf("STS port is incorrect, should be 0 if disabled: %d", config.Server.STS.Port)
406
 		}
384
 		}
407
 	}
385
 	}
408
-	if config.Server.ConnectionThrottle.Enabled {
409
-		config.Server.ConnectionThrottle.Duration, err = time.ParseDuration(config.Server.ConnectionThrottle.DurationString)
386
+	if config.Server.ConnectionThrottler.Enabled {
387
+		config.Server.ConnectionThrottler.Duration, err = time.ParseDuration(config.Server.ConnectionThrottler.DurationString)
410
 		if err != nil {
388
 		if err != nil {
411
 			return nil, fmt.Errorf("Could not parse connection-throttle duration: %s", err.Error())
389
 			return nil, fmt.Errorf("Could not parse connection-throttle duration: %s", err.Error())
412
 		}
390
 		}
413
-		config.Server.ConnectionThrottle.BanDuration, err = time.ParseDuration(config.Server.ConnectionThrottle.BanDurationString)
391
+		config.Server.ConnectionThrottler.BanDuration, err = time.ParseDuration(config.Server.ConnectionThrottler.BanDurationString)
414
 		if err != nil {
392
 		if err != nil {
415
 			return nil, fmt.Errorf("Could not parse connection-throttle ban-duration: %s", err.Error())
393
 			return nil, fmt.Errorf("Could not parse connection-throttle ban-duration: %s", err.Error())
416
 		}
394
 		}

irc/connection_limits.go → irc/connection_limits/limiter.go View File

1
 // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
1
 // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
2
 // released under the MIT license
2
 // released under the MIT license
3
 
3
 
4
-package irc
4
+package connection_limits
5
 
5
 
6
 import (
6
 import (
7
 	"errors"
7
 	"errors"
8
 	"fmt"
8
 	"fmt"
9
 	"net"
9
 	"net"
10
+	"sync"
10
 )
11
 )
11
 
12
 
13
+// LimiterConfig controls the automated connection limits.
14
+type LimiterConfig struct {
15
+	Enabled     bool
16
+	CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
17
+	CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
18
+	IPsPerCidr  int `yaml:"ips-per-subnet"`
19
+	Exempted    []string
20
+}
21
+
12
 var (
22
 var (
13
 	errTooManyClients = errors.New("Too many clients in subnet")
23
 	errTooManyClients = errors.New("Too many clients in subnet")
14
 )
24
 )
15
 
25
 
16
-// ConnectionLimits manages the automated client connection limits.
17
-type ConnectionLimits struct {
26
+// Limiter manages the automated client connection limits.
27
+type Limiter struct {
28
+	sync.Mutex
29
+
18
 	enabled  bool
30
 	enabled  bool
19
 	ipv4Mask net.IPMask
31
 	ipv4Mask net.IPMask
20
 	ipv6Mask net.IPMask
32
 	ipv6Mask net.IPMask
30
 }
42
 }
31
 
43
 
32
 // maskAddr masks the given IPv4/6 address with our cidr limit masks.
44
 // maskAddr masks the given IPv4/6 address with our cidr limit masks.
33
-func (cl *ConnectionLimits) maskAddr(addr net.IP) net.IP {
45
+func (cl *Limiter) maskAddr(addr net.IP) net.IP {
34
 	if addr.To4() == nil {
46
 	if addr.To4() == nil {
35
 		// IPv6 addr
47
 		// IPv6 addr
36
 		addr = addr.Mask(cl.ipv6Mask)
48
 		addr = addr.Mask(cl.ipv6Mask)
44
 
56
 
45
 // AddClient adds a client to our population if possible. If we can't, throws an error instead.
57
 // AddClient adds a client to our population if possible. If we can't, throws an error instead.
46
 // 'force' is used to add already-existing clients (i.e. ones that are already on the network).
58
 // 'force' is used to add already-existing clients (i.e. ones that are already on the network).
47
-func (cl *ConnectionLimits) AddClient(addr net.IP, force bool) error {
59
+func (cl *Limiter) AddClient(addr net.IP, force bool) error {
60
+	cl.Lock()
61
+	defer cl.Unlock()
62
+
48
 	if !cl.enabled {
63
 	if !cl.enabled {
49
 		return nil
64
 		return nil
50
 	}
65
 	}
74
 }
89
 }
75
 
90
 
76
 // RemoveClient removes the given address from our population
91
 // RemoveClient removes the given address from our population
77
-func (cl *ConnectionLimits) RemoveClient(addr net.IP) {
92
+func (cl *Limiter) RemoveClient(addr net.IP) {
93
+	cl.Lock()
94
+	defer cl.Unlock()
95
+
78
 	if !cl.enabled {
96
 	if !cl.enabled {
79
 		return
97
 		return
80
 	}
98
 	}
88
 	}
106
 	}
89
 }
107
 }
90
 
108
 
91
-// NewConnectionLimits returns a new connection limit handler.
92
-func NewConnectionLimits(config ConnectionLimitsConfig) (*ConnectionLimits, error) {
93
-	var cl ConnectionLimits
94
-	cl.enabled = config.Enabled
109
+// NewLimiter returns a new connection limit handler.
110
+// The handler is functional, but disabled; it can be enabled via `ApplyConfig`.
111
+func NewLimiter() *Limiter {
112
+	var cl Limiter
95
 
113
 
114
+	// initialize empty population; all other state is configurable
96
 	cl.population = make(map[string]int)
115
 	cl.population = make(map[string]int)
97
-	cl.exemptedIPs = make(map[string]bool)
98
 
116
 
99
-	cl.ipv4Mask = net.CIDRMask(config.CidrLenIPv4, 32)
100
-	cl.ipv6Mask = net.CIDRMask(config.CidrLenIPv6, 128)
101
-	// subnetLimit is explicitly NOT capped at a minimum of one.
102
-	// this is so that CL config can be used to allow ONLY clients from exempted IPs/nets
103
-	cl.subnetLimit = config.IPsPerCidr
117
+	return &cl
118
+}
104
 
119
 
120
+// ApplyConfig atomically applies a config update to a connection limit handler
121
+func (cl *Limiter) ApplyConfig(config LimiterConfig) error {
105
 	// assemble exempted nets
122
 	// assemble exempted nets
123
+	exemptedIPs := make(map[string]bool)
124
+	var exemptedNets []net.IPNet
106
 	for _, cidr := range config.Exempted {
125
 	for _, cidr := range config.Exempted {
107
 		ipaddr := net.ParseIP(cidr)
126
 		ipaddr := net.ParseIP(cidr)
108
 		_, netaddr, err := net.ParseCIDR(cidr)
127
 		_, netaddr, err := net.ParseCIDR(cidr)
109
 
128
 
110
 		if ipaddr == nil && err != nil {
129
 		if ipaddr == nil && err != nil {
111
-			return nil, fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
130
+			return fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
112
 		}
131
 		}
113
 
132
 
114
 		if ipaddr != nil {
133
 		if ipaddr != nil {
115
-			cl.exemptedIPs[ipaddr.String()] = true
134
+			exemptedIPs[ipaddr.String()] = true
116
 		} else {
135
 		} else {
117
-			cl.exemptedNets = append(cl.exemptedNets, *netaddr)
136
+			exemptedNets = append(exemptedNets, *netaddr)
118
 		}
137
 		}
119
 	}
138
 	}
120
 
139
 
121
-	return &cl, nil
140
+	cl.Lock()
141
+	defer cl.Unlock()
142
+
143
+	cl.enabled = config.Enabled
144
+	cl.ipv4Mask = net.CIDRMask(config.CidrLenIPv4, 32)
145
+	cl.ipv6Mask = net.CIDRMask(config.CidrLenIPv6, 128)
146
+	// subnetLimit is explicitly NOT capped at a minimum of one.
147
+	// this is so that CL config can be used to allow ONLY clients from exempted IPs/nets
148
+	cl.subnetLimit = config.IPsPerCidr
149
+	cl.exemptedIPs = exemptedIPs
150
+	cl.exemptedNets = exemptedNets
151
+
152
+	return nil
122
 }
153
 }

irc/connection_throttling.go → irc/connection_limits/throttler.go View File

1
 // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
1
 // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
2
 // released under the MIT license
2
 // released under the MIT license
3
 
3
 
4
-package irc
4
+package connection_limits
5
 
5
 
6
 import (
6
 import (
7
 	"fmt"
7
 	"fmt"
8
 	"net"
8
 	"net"
9
+	"sync"
9
 	"time"
10
 	"time"
10
 )
11
 )
11
 
12
 
13
+// ThrottlerConfig controls the automated connection throttling.
14
+type ThrottlerConfig struct {
15
+	Enabled            bool
16
+	CidrLenIPv4        int           `yaml:"cidr-len-ipv4"`
17
+	CidrLenIPv6        int           `yaml:"cidr-len-ipv6"`
18
+	ConnectionsPerCidr int           `yaml:"max-connections"`
19
+	DurationString     string        `yaml:"duration"`
20
+	Duration           time.Duration `yaml:"duration-time"`
21
+	BanDurationString  string        `yaml:"ban-duration"`
22
+	BanDuration        time.Duration
23
+	BanMessage         string `yaml:"ban-message"`
24
+	Exempted           []string
25
+}
26
+
12
 // ThrottleDetails holds the connection-throttling details for a subnet/IP.
27
 // ThrottleDetails holds the connection-throttling details for a subnet/IP.
13
 type ThrottleDetails struct {
28
 type ThrottleDetails struct {
14
 	Start       time.Time
29
 	Start       time.Time
15
 	ClientCount int
30
 	ClientCount int
16
 }
31
 }
17
 
32
 
18
-// ConnectionThrottle manages automated client connection throttling.
19
-type ConnectionThrottle struct {
33
+// Throttler manages automated client connection throttling.
34
+type Throttler struct {
35
+	sync.RWMutex
36
+
20
 	enabled     bool
37
 	enabled     bool
21
 	ipv4Mask    net.IPMask
38
 	ipv4Mask    net.IPMask
22
 	ipv6Mask    net.IPMask
39
 	ipv6Mask    net.IPMask
25
 	population  map[string]ThrottleDetails
42
 	population  map[string]ThrottleDetails
26
 
43
 
27
 	// used by the server to ban clients that go over this limit
44
 	// used by the server to ban clients that go over this limit
28
-	BanDuration     time.Duration
29
-	BanMessage      string
30
-	BanMessageBytes []byte
45
+	banDuration time.Duration
46
+	banMessage  string
31
 
47
 
32
 	// exemptedIPs holds IPs that are exempt from limits
48
 	// exemptedIPs holds IPs that are exempt from limits
33
 	exemptedIPs map[string]bool
49
 	exemptedIPs map[string]bool
36
 }
52
 }
37
 
53
 
38
 // maskAddr masks the given IPv4/6 address with our cidr limit masks.
54
 // maskAddr masks the given IPv4/6 address with our cidr limit masks.
39
-func (ct *ConnectionThrottle) maskAddr(addr net.IP) net.IP {
55
+func (ct *Throttler) maskAddr(addr net.IP) net.IP {
40
 	if addr.To4() == nil {
56
 	if addr.To4() == nil {
41
 		// IPv6 addr
57
 		// IPv6 addr
42
 		addr = addr.Mask(ct.ipv6Mask)
58
 		addr = addr.Mask(ct.ipv6Mask)
49
 }
65
 }
50
 
66
 
51
 // ResetFor removes any existing count for the given address.
67
 // ResetFor removes any existing count for the given address.
52
-func (ct *ConnectionThrottle) ResetFor(addr net.IP) {
68
+func (ct *Throttler) ResetFor(addr net.IP) {
69
+	ct.Lock()
70
+	defer ct.Unlock()
71
+
53
 	if !ct.enabled {
72
 	if !ct.enabled {
54
 		return
73
 		return
55
 	}
74
 	}
61
 }
80
 }
62
 
81
 
63
 // AddClient introduces a new client connection if possible. If we can't, throws an error instead.
82
 // AddClient introduces a new client connection if possible. If we can't, throws an error instead.
64
-func (ct *ConnectionThrottle) AddClient(addr net.IP) error {
83
+func (ct *Throttler) AddClient(addr net.IP) error {
84
+	ct.Lock()
85
+	defer ct.Unlock()
86
+
65
 	if !ct.enabled {
87
 	if !ct.enabled {
66
 		return nil
88
 		return nil
67
 	}
89
 	}
97
 	return nil
119
 	return nil
98
 }
120
 }
99
 
121
 
100
-// NewConnectionThrottle returns a new client connection throttler.
101
-func NewConnectionThrottle(config ConnectionThrottleConfig) (*ConnectionThrottle, error) {
102
-	var ct ConnectionThrottle
103
-	ct.enabled = config.Enabled
122
+func (ct *Throttler) BanDuration() time.Duration {
123
+	ct.RLock()
124
+	defer ct.RUnlock()
104
 
125
 
105
-	ct.population = make(map[string]ThrottleDetails)
106
-	ct.exemptedIPs = make(map[string]bool)
126
+	return ct.banDuration
127
+}
107
 
128
 
108
-	ct.ipv4Mask = net.CIDRMask(config.CidrLenIPv4, 32)
109
-	ct.ipv6Mask = net.CIDRMask(config.CidrLenIPv6, 128)
110
-	ct.subnetLimit = config.ConnectionsPerCidr
129
+func (ct *Throttler) BanMessage() string {
130
+	ct.RLock()
131
+	defer ct.RUnlock()
111
 
132
 
112
-	ct.duration = config.Duration
133
+	return ct.banMessage
134
+}
113
 
135
 
114
-	ct.BanDuration = config.BanDuration
115
-	ct.BanMessage = config.BanMessage
136
+// NewThrottler returns a new client connection throttler.
137
+// The throttler is functional, but disabled; it can be enabled via `ApplyConfig`.
138
+func NewThrottler() *Throttler {
139
+	var ct Throttler
116
 
140
 
141
+	// initialize empty population; all other state is configurable
142
+	ct.population = make(map[string]ThrottleDetails)
143
+
144
+	return &ct
145
+}
146
+
147
+// ApplyConfig atomically applies a config update to a throttler
148
+func (ct *Throttler) ApplyConfig(config ThrottlerConfig) error {
117
 	// assemble exempted nets
149
 	// assemble exempted nets
150
+	exemptedIPs := make(map[string]bool)
151
+	var exemptedNets []net.IPNet
118
 	for _, cidr := range config.Exempted {
152
 	for _, cidr := range config.Exempted {
119
 		ipaddr := net.ParseIP(cidr)
153
 		ipaddr := net.ParseIP(cidr)
120
 		_, netaddr, err := net.ParseCIDR(cidr)
154
 		_, netaddr, err := net.ParseCIDR(cidr)
121
 
155
 
122
 		if ipaddr == nil && err != nil {
156
 		if ipaddr == nil && err != nil {
123
-			return nil, fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
157
+			return fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
124
 		}
158
 		}
125
 
159
 
126
 		if ipaddr != nil {
160
 		if ipaddr != nil {
127
-			ct.exemptedIPs[ipaddr.String()] = true
161
+			exemptedIPs[ipaddr.String()] = true
128
 		} else {
162
 		} else {
129
-			ct.exemptedNets = append(ct.exemptedNets, *netaddr)
163
+			exemptedNets = append(exemptedNets, *netaddr)
130
 		}
164
 		}
131
 	}
165
 	}
132
 
166
 
133
-	return &ct, nil
167
+	ct.Lock()
168
+	defer ct.Unlock()
169
+
170
+	ct.enabled = config.Enabled
171
+	ct.ipv4Mask = net.CIDRMask(config.CidrLenIPv4, 32)
172
+	ct.ipv6Mask = net.CIDRMask(config.CidrLenIPv6, 128)
173
+	ct.subnetLimit = config.ConnectionsPerCidr
174
+	ct.duration = config.Duration
175
+	ct.banDuration = config.BanDuration
176
+	ct.banMessage = config.BanMessage
177
+	ct.exemptedIPs = exemptedIPs
178
+	ct.exemptedNets = exemptedNets
179
+
180
+	return nil
134
 }
181
 }

+ 38
- 54
irc/server.go View File

24
 	"github.com/goshuirc/irc-go/ircfmt"
24
 	"github.com/goshuirc/irc-go/ircfmt"
25
 	"github.com/goshuirc/irc-go/ircmsg"
25
 	"github.com/goshuirc/irc-go/ircmsg"
26
 	"github.com/oragono/oragono/irc/caps"
26
 	"github.com/oragono/oragono/irc/caps"
27
+	"github.com/oragono/oragono/irc/connection_limits"
27
 	"github.com/oragono/oragono/irc/isupport"
28
 	"github.com/oragono/oragono/irc/isupport"
28
 	"github.com/oragono/oragono/irc/logger"
29
 	"github.com/oragono/oragono/irc/logger"
29
 	"github.com/oragono/oragono/irc/passwd"
30
 	"github.com/oragono/oragono/irc/passwd"
86
 	commands                     chan Command
87
 	commands                     chan Command
87
 	configFilename               string
88
 	configFilename               string
88
 	configurableStateMutex       sync.RWMutex // generic protection for server state modified by rehash()
89
 	configurableStateMutex       sync.RWMutex // generic protection for server state modified by rehash()
89
-	connectionLimits             *ConnectionLimits
90
-	connectionLimitsMutex        sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack
91
-	connectionThrottle           *ConnectionThrottle
92
-	connectionThrottleMutex      sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack
90
+	connectionLimiter            *connection_limits.Limiter
91
+	connectionThrottler          *connection_limits.Throttler
93
 	ctime                        time.Time
92
 	ctime                        time.Time
94
 	defaultChannelModes          Modes
93
 	defaultChannelModes          Modes
95
 	dlines                       *DLineManager
94
 	dlines                       *DLineManager
145
 
144
 
146
 	// initialize data structures
145
 	// initialize data structures
147
 	server := &Server{
146
 	server := &Server{
148
-		accounts:           make(map[string]*ClientAccount),
149
-		channels:           *NewChannelNameMap(),
150
-		clients:            NewClientLookupSet(),
151
-		commands:           make(chan Command),
152
-		listeners:          make(map[string]*ListenerWrapper),
153
-		logger:             logger,
154
-		monitorManager:     NewMonitorManager(),
155
-		newConns:           make(chan clientConn),
156
-		registeredChannels: make(map[string]*RegisteredChannel),
157
-		rehashSignal:       make(chan os.Signal, 1),
158
-		signals:            make(chan os.Signal, len(ServerExitSignals)),
159
-		snomasks:           NewSnoManager(),
160
-		whoWas:             NewWhoWasList(config.Limits.WhowasEntries),
147
+		accounts:            make(map[string]*ClientAccount),
148
+		channels:            *NewChannelNameMap(),
149
+		clients:             NewClientLookupSet(),
150
+		commands:            make(chan Command),
151
+		connectionLimiter:   connection_limits.NewLimiter(),
152
+		connectionThrottler: connection_limits.NewThrottler(),
153
+		listeners:           make(map[string]*ListenerWrapper),
154
+		logger:              logger,
155
+		monitorManager:      NewMonitorManager(),
156
+		newConns:            make(chan clientConn),
157
+		registeredChannels:  make(map[string]*RegisteredChannel),
158
+		rehashSignal:        make(chan os.Signal, 1),
159
+		signals:             make(chan os.Signal, len(ServerExitSignals)),
160
+		snomasks:            NewSnoManager(),
161
+		whoWas:              NewWhoWasList(config.Limits.WhowasEntries),
161
 	}
162
 	}
162
 
163
 
163
 	if err := server.applyConfig(config, true); err != nil {
164
 	if err := server.applyConfig(config, true); err != nil {
297
 	// check DLINEs
298
 	// check DLINEs
298
 	isBanned, info := server.dlines.CheckIP(ipaddr)
299
 	isBanned, info := server.dlines.CheckIP(ipaddr)
299
 	if isBanned {
300
 	if isBanned {
301
+		server.logger.Info("localconnect-ip", fmt.Sprintf("Client from %v rejected by d-line", ipaddr))
300
 		return true, info.BanMessage("You are banned from this server (%s)")
302
 		return true, info.BanMessage("You are banned from this server (%s)")
301
 	}
303
 	}
302
 
304
 
303
 	// check connection limits
305
 	// check connection limits
304
-	server.connectionLimitsMutex.Lock()
305
-	err := server.connectionLimits.AddClient(ipaddr, false)
306
-	server.connectionLimitsMutex.Unlock()
306
+	err := server.connectionLimiter.AddClient(ipaddr, false)
307
 	if err != nil {
307
 	if err != nil {
308
 		// too many connections from one client, tell the client and close the connection
308
 		// too many connections from one client, tell the client and close the connection
309
+		server.logger.Info("localconnect-ip", fmt.Sprintf("Client from %v rejected for connection limit", ipaddr))
309
 		return true, "Too many clients from your network"
310
 		return true, "Too many clients from your network"
310
 	}
311
 	}
311
 
312
 
312
 	// check connection throttle
313
 	// check connection throttle
313
-	server.connectionThrottleMutex.Lock()
314
-	err = server.connectionThrottle.AddClient(ipaddr)
315
-	server.connectionThrottleMutex.Unlock()
314
+	err = server.connectionThrottler.AddClient(ipaddr)
316
 	if err != nil {
315
 	if err != nil {
317
 		// too many connections too quickly from client, tell them and close the connection
316
 		// too many connections too quickly from client, tell them and close the connection
317
+		duration := server.connectionThrottler.BanDuration()
318
 		length := &IPRestrictTime{
318
 		length := &IPRestrictTime{
319
-			Duration: server.connectionThrottle.BanDuration,
320
-			Expires:  time.Now().Add(server.connectionThrottle.BanDuration),
319
+			Duration: duration,
320
+			Expires:  time.Now().Add(duration),
321
 		}
321
 		}
322
-		server.dlines.AddIP(ipaddr, length, server.connectionThrottle.BanMessage, "Exceeded automated connection throttle")
322
+		server.dlines.AddIP(ipaddr, length, server.connectionThrottler.BanMessage(), "Exceeded automated connection throttle")
323
 
323
 
324
 		// they're DLINE'd for 15 minutes or whatever, so we can reset the connection throttle now,
324
 		// they're DLINE'd for 15 minutes or whatever, so we can reset the connection throttle now,
325
 		// and once their temporary DLINE is finished they can fill up the throttler again
325
 		// and once their temporary DLINE is finished they can fill up the throttler again
326
-		server.connectionThrottle.ResetFor(ipaddr)
326
+		server.connectionThrottler.ResetFor(ipaddr)
327
 
327
 
328
 		// this might not show up properly on some clients, but our objective here is just to close it out before it has a load impact on us
328
 		// this might not show up properly on some clients, but our objective here is just to close it out before it has a load impact on us
329
-		return true, server.connectionThrottle.BanMessage
329
+		server.logger.Info(
330
+			"localconnect-ip",
331
+			fmt.Sprintf("Client from %v exceeded connection throttle, d-lining for %v", ipaddr, duration))
332
+		return true, server.connectionThrottler.BanMessage()
330
 	}
333
 	}
331
 
334
 
332
 	return false, ""
335
 	return false, ""
1229
 		return fmt.Errorf("Server name isn't valid [%s]: %s", config.Server.Name, err.Error())
1232
 		return fmt.Errorf("Server name isn't valid [%s]: %s", config.Server.Name, err.Error())
1230
 	}
1233
 	}
1231
 
1234
 
1232
-	// confirm connectionLimits are fine
1233
-	connectionLimits, err := NewConnectionLimits(config.Server.ConnectionLimits)
1234
-	if err != nil {
1235
-		return fmt.Errorf("Error rehashing config file connection-limits: %s", err.Error())
1236
-	}
1237
-
1238
-	// confirm connectionThrottler is fine
1239
-	connectionThrottle, err := NewConnectionThrottle(config.Server.ConnectionThrottle)
1240
-	if err != nil {
1241
-		return fmt.Errorf("Error rehashing config file connection-throttle: %s", err.Error())
1242
-	}
1243
-
1244
 	// confirm operator stuff all exists and is fine
1235
 	// confirm operator stuff all exists and is fine
1245
 	operclasses, err := config.OperatorClasses()
1236
 	operclasses, err := config.OperatorClasses()
1246
 	if err != nil {
1237
 	if err != nil {
1272
 	// apply new PROXY command restrictions
1263
 	// apply new PROXY command restrictions
1273
 	server.proxyAllowedFrom = config.Server.ProxyAllowedFrom
1264
 	server.proxyAllowedFrom = config.Server.ProxyAllowedFrom
1274
 
1265
 
1275
-	// apply new connectionlimits
1276
-	server.connectionLimitsMutex.Lock()
1277
-	server.connectionLimits = connectionLimits
1278
-	server.connectionThrottleMutex.Lock()
1279
-	server.connectionThrottle = connectionThrottle
1266
+	err = server.connectionLimiter.ApplyConfig(config.Server.ConnectionLimiter)
1267
+	if err != nil {
1268
+		return err
1269
+	}
1280
 
1270
 
1281
-	server.clients.ByNickMutex.RLock()
1282
-	for _, client := range server.clients.ByNick {
1283
-		ipaddr := client.IP()
1284
-		if ipaddr != nil {
1285
-			server.connectionLimits.AddClient(ipaddr, true)
1286
-		}
1271
+	err = server.connectionThrottler.ApplyConfig(config.Server.ConnectionThrottler)
1272
+	if err != nil {
1273
+		return err
1287
 	}
1274
 	}
1288
-	server.clients.ByNickMutex.RUnlock()
1289
-	server.connectionThrottleMutex.Unlock()
1290
-	server.connectionLimitsMutex.Unlock()
1291
 
1275
 
1292
 	// setup new and removed caps
1276
 	// setup new and removed caps
1293
 	addedCaps := caps.NewSet()
1277
 	addedCaps := caps.NewSet()

+ 1
- 1
oragono.yaml View File

71
 
71
 
72
     # maximum number of connections per subnet
72
     # maximum number of connections per subnet
73
     connection-limits:
73
     connection-limits:
74
-        # whether to throttle limits or not
74
+        # whether to enforce connection limits or not
75
         enabled: true
75
         enabled: true
76
 
76
 
77
         # how wide the cidr should be for IPv4
77
         # how wide the cidr should be for IPv4

Loading…
Cancel
Save