3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-23 03:02:48 +01:00

Merge pull request #1425 from slingamn/issue1421_customlimits.2

fix #1421
This commit is contained in:
Shivaram Lingamneni 2020-12-05 16:03:51 -08:00 committed by GitHub
commit 23a7221137
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 24 deletions

View File

@ -263,13 +263,23 @@ server:
# - "192.168.1.1"
# - "2001:0db8::/32"
# custom connection limits for certain IPs/networks. note that CIDR
# widths defined here override the default CIDR width --- the limit
# will apply to the entire CIDR no matter how large or small it is
# custom connection limits for certain IPs/networks.
custom-limits:
# "8.8.0.0/16":
# max-concurrent-connections: 128
# max-connections-per-window: 1024
#"irccloud":
# nets:
# - "192.184.9.108" # highgate.irccloud.com
# - "192.184.9.110" # ealing.irccloud.com
# - "192.184.9.112" # charlton.irccloud.com
# - "192.184.10.118" # brockwell.irccloud.com
# - "192.184.10.9" # tooting.irccloud.com
# - "192.184.8.73" # hathersage.irccloud.com
# - "192.184.8.103" # stonehaven.irccloud.com
# - "5.254.36.57" # tinside.irccloud.com
# - "5.254.36.56/29" # additional ipv4 net
# - "2001:67c:2f08::/48"
# - "2a03:5180:f::/64"
# max-concurrent-connections: 2048
# max-connections-per-window: 2048
# pluggable IP ban mechanism, via subprocess invocation
# this can be used to check new connections against a DNSBL, for example

View File

@ -19,14 +19,17 @@ var (
)
type CustomLimitConfig struct {
Nets []string
MaxConcurrent int `yaml:"max-concurrent-connections"`
MaxPerWindow int `yaml:"max-connections-per-window"`
}
// tuples the key-value pair of a CIDR and its custom limit/throttle values
type customLimit struct {
CustomLimitConfig
ipNet net.IPNet
name string
maxConcurrent int
maxPerWindow int
nets []net.IPNet
}
// LimiterConfig controls the automated connection limits.
@ -71,14 +74,29 @@ func (config *LimiterConfig) postprocess() (err error) {
return fmt.Errorf("Could not parse limiter exemption list: %v", err.Error())
}
for netStr, customLimitConf := range config.CustomLimits {
normalizedNet, err := utils.NormalizedNetFromString(netStr)
if err != nil {
return fmt.Errorf("Could not parse custom limit specification: %v", err.Error())
for identifier, customLimitConf := range config.CustomLimits {
nets := make([]net.IPNet, len(customLimitConf.Nets))
for i, netStr := range customLimitConf.Nets {
normalizedNet, err := utils.NormalizedNetFromString(netStr)
if err != nil {
return fmt.Errorf("Bad net %s in custom-limits block %s: %w", netStr, identifier, err)
}
nets[i] = normalizedNet
}
if len(customLimitConf.Nets) == 0 {
// see #1421: this is the legacy config format where the
// dictionary key of the block is a CIDR string
normalizedNet, err := utils.NormalizedNetFromString(identifier)
if err != nil {
return fmt.Errorf("Custom limit block %s has no defined nets", identifier)
}
nets = []net.IPNet{normalizedNet}
}
config.customLimits = append(config.customLimits, customLimit{
CustomLimitConfig: customLimitConf,
ipNet: normalizedNet,
maxConcurrent: customLimitConf.MaxConcurrent,
maxPerWindow: customLimitConf.MaxPerWindow,
name: "*" + identifier,
nets: nets,
})
}
@ -105,8 +123,10 @@ type Limiter struct {
func (cl *Limiter) addrToKey(addr net.IP) (key string, limit int, throttle int) {
// `key` will be a CIDR string like "8.8.8.8/32" or "2001:0db8::/32"
for _, custom := range cl.config.customLimits {
if custom.ipNet.Contains(addr) {
return custom.ipNet.String(), custom.MaxConcurrent, custom.MaxPerWindow
for _, net := range custom.nets {
if net.Contains(addr) {
return custom.name, custom.maxConcurrent, custom.maxPerWindow
}
}
}

View File

@ -32,7 +32,8 @@ var baseConfig = LimiterConfig{
Exempted: []string{"localhost"},
CustomLimits: map[string]CustomLimitConfig{
"8.8.0.0/16": {
"google": {
Nets: []string{"8.8.0.0/16"},
MaxConcurrent: 128,
MaxPerWindow: 256,
},
@ -57,7 +58,7 @@ func TestKeying(t *testing.T) {
assertEqual(maxWin, 8, t)
key, maxConc, maxWin = limiter.addrToKey(easyParseIP("8.8.4.4"))
assertEqual(key, "8.8.0.0/16", t)
assertEqual(key, "*google", t)
assertEqual(maxConc, 128, t)
assertEqual(maxWin, 256, t)
}

View File

@ -236,13 +236,23 @@ server:
# - "192.168.1.1"
# - "2001:0db8::/32"
# custom connection limits for certain IPs/networks. note that CIDR
# widths defined here override the default CIDR width --- the limit
# will apply to the entire CIDR no matter how large or small it is
# custom connection limits for certain IPs/networks.
custom-limits:
# "8.8.0.0/16":
# max-concurrent-connections: 128
# max-connections-per-window: 1024
#"irccloud":
# nets:
# - "192.184.9.108" # highgate.irccloud.com
# - "192.184.9.110" # ealing.irccloud.com
# - "192.184.9.112" # charlton.irccloud.com
# - "192.184.10.118" # brockwell.irccloud.com
# - "192.184.10.9" # tooting.irccloud.com
# - "192.184.8.73" # hathersage.irccloud.com
# - "192.184.8.103" # stonehaven.irccloud.com
# - "5.254.36.57" # tinside.irccloud.com
# - "5.254.36.56/29" # additional ipv4 net
# - "2001:67c:2f08::/48"
# - "2a03:5180:f::/64"
# max-concurrent-connections: 2048
# max-connections-per-window: 2048
# pluggable IP ban mechanism, via subprocess invocation
# this can be used to check new connections against a DNSBL, for example