mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-22 11:59:40 +01:00
tweaks to UBAN
This commit is contained in:
parent
c14154c062
commit
8dd39a6e71
@ -28,6 +28,7 @@ type CustomLimitConfig struct {
|
||||
// tuples the key-value pair of a CIDR and its custom limit/throttle values
|
||||
type customLimit struct {
|
||||
name [16]byte
|
||||
customID string // operator-configured identifier for a custom net
|
||||
maxConcurrent int
|
||||
maxPerWindow int
|
||||
nets []flatip.IPNet
|
||||
@ -103,6 +104,7 @@ func (config *LimiterConfig) postprocess() (err error) {
|
||||
maxConcurrent: customLimitConf.MaxConcurrent,
|
||||
maxPerWindow: customLimitConf.MaxPerWindow,
|
||||
name: md5.Sum([]byte(identifier)),
|
||||
customID: identifier,
|
||||
nets: nets,
|
||||
})
|
||||
}
|
||||
@ -124,11 +126,11 @@ type Limiter struct {
|
||||
|
||||
// addrToKey canonicalizes `addr` to a string key, and returns
|
||||
// the relevant connection limit and throttle max-per-window values
|
||||
func (cl *Limiter) addrToKey(addr flatip.IP) (key limiterKey, limit int, throttle int) {
|
||||
func (cl *Limiter) addrToKey(addr flatip.IP) (key limiterKey, customID string, limit int, throttle int) {
|
||||
for _, custom := range cl.config.customLimits {
|
||||
for _, net := range custom.nets {
|
||||
if net.Contains(addr) {
|
||||
return limiterKey{maskedIP: custom.name, prefixLen: 0}, custom.maxConcurrent, custom.maxPerWindow
|
||||
return limiterKey{maskedIP: custom.name, prefixLen: 0}, custom.customID, custom.maxConcurrent, custom.maxPerWindow
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,7 +145,7 @@ func (cl *Limiter) addrToKey(addr flatip.IP) (key limiterKey, limit int, throttl
|
||||
addr = addr.Mask(prefixLen, 128)
|
||||
}
|
||||
|
||||
return limiterKey{maskedIP: addr, prefixLen: uint8(prefixLen)}, cl.config.MaxConcurrent, cl.config.MaxPerWindow
|
||||
return limiterKey{maskedIP: addr, prefixLen: uint8(prefixLen)}, "", cl.config.MaxConcurrent, cl.config.MaxPerWindow
|
||||
}
|
||||
|
||||
// AddClient adds a client to our population if possible. If we can't, throws an error instead.
|
||||
@ -156,7 +158,7 @@ func (cl *Limiter) AddClient(addr flatip.IP) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
addrString, maxConcurrent, maxPerWindow := cl.addrToKey(addr)
|
||||
addrString, _, maxConcurrent, maxPerWindow := cl.addrToKey(addr)
|
||||
|
||||
// check limiter
|
||||
var count int
|
||||
@ -200,7 +202,7 @@ func (cl *Limiter) RemoveClient(addr flatip.IP) {
|
||||
return
|
||||
}
|
||||
|
||||
addrString, _, _ := cl.addrToKey(addr)
|
||||
addrString, _, _, _ := cl.addrToKey(addr)
|
||||
count := cl.limiter[addrString]
|
||||
count -= 1
|
||||
if count < 0 {
|
||||
@ -220,7 +222,7 @@ type LimiterStatus struct {
|
||||
ThrottleDuration time.Duration
|
||||
}
|
||||
|
||||
func (cl *Limiter) Status(addr flatip.IP) (status LimiterStatus) {
|
||||
func (cl *Limiter) Status(addr flatip.IP) (netName string, status LimiterStatus) {
|
||||
cl.Lock()
|
||||
defer cl.Unlock()
|
||||
|
||||
@ -231,12 +233,20 @@ func (cl *Limiter) Status(addr flatip.IP) (status LimiterStatus) {
|
||||
|
||||
status.ThrottleDuration = cl.config.Window
|
||||
|
||||
addrString, maxConcurrent, maxPerWindow := cl.addrToKey(addr)
|
||||
limiterKey, customID, maxConcurrent, maxPerWindow := cl.addrToKey(addr)
|
||||
status.MaxCount = maxConcurrent
|
||||
status.MaxPerWindow = maxPerWindow
|
||||
|
||||
status.Count = cl.limiter[addrString]
|
||||
status.Throttle = cl.throttler[addrString].Count
|
||||
status.Count = cl.limiter[limiterKey]
|
||||
status.Throttle = cl.throttler[limiterKey].Count
|
||||
|
||||
netName = customID
|
||||
if netName == "" {
|
||||
netName = flatip.IPNet{
|
||||
IP: limiterKey.maskedIP,
|
||||
PrefixLen: limiterKey.prefixLen,
|
||||
}.String()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@ -250,7 +260,7 @@ func (cl *Limiter) ResetThrottle(addr flatip.IP) {
|
||||
return
|
||||
}
|
||||
|
||||
addrString, _, _ := cl.addrToKey(addr)
|
||||
addrString, _, _, _ := cl.addrToKey(addr)
|
||||
delete(cl.throttler, addrString)
|
||||
}
|
||||
|
||||
|
@ -50,20 +50,20 @@ func TestKeying(t *testing.T) {
|
||||
limiter.ApplyConfig(&config)
|
||||
|
||||
// an ipv4 /32 looks like a /128 to us after applying the 4-in-6 mapping
|
||||
key, maxConc, maxWin := limiter.addrToKey(easyParseIP("1.1.1.1"))
|
||||
key, _, maxConc, maxWin := limiter.addrToKey(easyParseIP("1.1.1.1"))
|
||||
assertEqual(key.prefixLen, uint8(128), t)
|
||||
assertEqual(key.maskedIP[12:], []byte{1, 1, 1, 1}, t)
|
||||
assertEqual(maxConc, 4, t)
|
||||
assertEqual(maxWin, 8, t)
|
||||
|
||||
testIPv6 := easyParseIP("2607:5301:201:3100::7426")
|
||||
key, maxConc, maxWin = limiter.addrToKey(testIPv6)
|
||||
key, _, maxConc, maxWin = limiter.addrToKey(testIPv6)
|
||||
assertEqual(key.prefixLen, uint8(64), t)
|
||||
assertEqual(flatip.IP(key.maskedIP), easyParseIP("2607:5301:201:3100::"), t)
|
||||
assertEqual(maxConc, 4, t)
|
||||
assertEqual(maxWin, 8, t)
|
||||
|
||||
key, maxConc, maxWin = limiter.addrToKey(easyParseIP("8.8.4.4"))
|
||||
key, _, maxConc, maxWin = limiter.addrToKey(easyParseIP("8.8.4.4"))
|
||||
assertEqual(key.prefixLen, uint8(0), t)
|
||||
assertEqual([16]byte(key.maskedIP), md5.Sum([]byte("google")), t)
|
||||
assertEqual(maxConc, 128, t)
|
||||
|
@ -107,14 +107,6 @@ For instance, this would set the kill, oper, account and xline snomasks on dan:
|
||||
// Help contains the help strings distributed with the IRCd.
|
||||
var Help = map[string]HelpEntry{
|
||||
// Commands
|
||||
"acc": {
|
||||
text: `ACC LS
|
||||
ACC REGISTER <accountname> [callback_namespace:]<callback> [cred_type] :<credential>
|
||||
ACC VERIFY <accountname> <auth_code>
|
||||
|
||||
Used in account registration. See the relevant specs for more info:
|
||||
https://oragono.io/specs.html`,
|
||||
},
|
||||
"ambiance": {
|
||||
text: `AMBIANCE <target> <text to be sent>
|
||||
|
||||
|
24
irc/uban.go
24
irc/uban.go
@ -303,13 +303,12 @@ func ubanInfoHandler(client *Client, target ubanTarget, params []string, rb *Res
|
||||
|
||||
func ubanInfoCIDR(client *Client, target ubanTarget, rb *ResponseBuffer) {
|
||||
if target.cidr.PrefixLen == 128 {
|
||||
status := client.server.connectionLimiter.Status(target.cidr.IP)
|
||||
str := target.cidr.IP.String()
|
||||
netName, status := client.server.connectionLimiter.Status(target.cidr.IP)
|
||||
if status.Exempt {
|
||||
rb.Notice(fmt.Sprintf(client.t("IP %s is exempt from connection limits"), str))
|
||||
rb.Notice(fmt.Sprintf(client.t("IP %s is exempt from connection limits"), target.cidr.IP.String()))
|
||||
} else {
|
||||
rb.Notice(fmt.Sprintf(client.t("IP %[1]s has %[2]d active connections out of a maximum of %[3]d"), str, status.Count, status.MaxCount))
|
||||
rb.Notice(fmt.Sprintf(client.t("IP %[1]s has had %[2]d connection attempts in the past %[3]v, out of a maximum of %[4]d"), str, status.Throttle, status.ThrottleDuration, status.MaxPerWindow))
|
||||
rb.Notice(fmt.Sprintf(client.t("Network %[1]s has %[2]d active connections out of a maximum of %[3]d"), netName, status.Count, status.MaxCount))
|
||||
rb.Notice(fmt.Sprintf(client.t("Network %[1]s has had %[2]d connection attempts in the past %[3]v, out of a maximum of %[4]d"), netName, status.Throttle, status.ThrottleDuration, status.MaxPerWindow))
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,15 +363,22 @@ func ubanInfoNick(client *Client, target ubanTarget, rb *ResponseBuffer) {
|
||||
mcl := client.server.clients.Get(target.nickOrMask)
|
||||
if mcl != nil {
|
||||
details := mcl.Details()
|
||||
sessions := mcl.Sessions()
|
||||
ip := mcl.IP()
|
||||
sendIPBanWarning := false
|
||||
if details.account == "" {
|
||||
rb.Notice(fmt.Sprintf(client.t("Client %[1]s is unauthenticated and connected from %[2]s"), details.nick, mcl.IP().String()))
|
||||
rb.Notice(fmt.Sprintf(client.t("Client %[1]s is unauthenticated and connected from %[2]s"), details.nick, ip.String()))
|
||||
sendIPBanWarning = true
|
||||
} else {
|
||||
rb.Notice(fmt.Sprintf(client.t("Client %[1]s is logged into account %[2]s and has %[3]d active clients (see /NICKSERV CLIENTS LIST %[4]s for more info"), details.nick, details.accountName, len(mcl.Sessions()), details.nick))
|
||||
ip := mcl.IP()
|
||||
if !ip.IsLoopback() {
|
||||
rb.Notice(fmt.Sprintf(client.t("Client %[1]s is associated with IP %[2]s; you can ban this IP with /UBAN ADD"), details.nick, ip.String()))
|
||||
if !ip.IsLoopback() && len(sessions) == 1 {
|
||||
rb.Notice(fmt.Sprintf(client.t("Client %[1]s is associated with IP %[2]s"), details.nick, ip.String()))
|
||||
sendIPBanWarning = true
|
||||
}
|
||||
}
|
||||
if sendIPBanWarning {
|
||||
rb.Notice(client.t("Warning: banning this IP or a network that contains it may affect other users. Use /UBAN INFO on the candidate IP or network for more information."))
|
||||
}
|
||||
} else {
|
||||
rb.Notice(fmt.Sprintf(client.t("No client is currently using that nickname")))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user