3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-22 18:52:41 +01:00

Merge pull request #1504 from slingamn/soft_dline

allow UBAN <ip> REQUIRE-SASL
This commit is contained in:
Shivaram Lingamneni 2021-01-22 10:11:01 -05:00 committed by GitHub
commit a988434bf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 21 deletions

View File

@ -20,6 +20,8 @@ const (
// IPBanInfo holds info about an IP/net ban. // IPBanInfo holds info about an IP/net ban.
type IPBanInfo struct { type IPBanInfo struct {
// RequireSASL indicates a "soft" ban; connections are allowed but they must SASL
RequireSASL bool
// Reason is the ban reason. // Reason is the ban reason.
Reason string `json:"reason"` Reason string `json:"reason"`
// OperReason is an oper ban reason. // OperReason is an oper ban reason.
@ -95,12 +97,13 @@ func (dm *DLineManager) AllBans() map[string]IPBanInfo {
} }
// AddNetwork adds a network to the blocked list. // AddNetwork adds a network to the blocked list.
func (dm *DLineManager) AddNetwork(network flatip.IPNet, duration time.Duration, reason, operReason, operName string) error { func (dm *DLineManager) AddNetwork(network flatip.IPNet, duration time.Duration, requireSASL bool, reason, operReason, operName string) error {
dm.persistenceMutex.Lock() dm.persistenceMutex.Lock()
defer dm.persistenceMutex.Unlock() defer dm.persistenceMutex.Unlock()
// assemble ban info // assemble ban info
info := IPBanInfo{ info := IPBanInfo{
RequireSASL: requireSASL,
Reason: reason, Reason: reason,
OperReason: operReason, OperReason: operReason,
OperName: operName, OperName: operName,

View File

@ -818,7 +818,11 @@ func formatBanForListing(client *Client, key string, info IPBanInfo) string {
if info.Duration != 0 { if info.Duration != 0 {
desc = fmt.Sprintf("%s [%s]", desc, info.TimeLeft()) desc = fmt.Sprintf("%s [%s]", desc, info.TimeLeft())
} }
return fmt.Sprintf(client.t("Ban - %[1]s - added by %[2]s - %[3]s"), key, info.OperName, desc) banType := "Ban"
if info.RequireSASL {
banType = "SASL required"
}
return fmt.Sprintf(client.t("%[1]s - %[2]s - added by %[3]s - %[4]s"), banType, key, info.OperName, desc)
} }
// DLINE [ANDKILL] [MYSELF] [duration] <ip>/<net> [ON <server>] [reason [| oper reason]] // DLINE [ANDKILL] [MYSELF] [duration] <ip>/<net> [ON <server>] [reason [| oper reason]]
@ -906,7 +910,7 @@ func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
operName = server.name operName = server.name
} }
err = server.dlines.AddNetwork(flatip.FromNetIPNet(hostNet), duration, reason, operReason, operName) err = server.dlines.AddNetwork(flatip.FromNetIPNet(hostNet), duration, false, reason, operReason, operName)
if err != nil { if err != nil {
rb.Notice(fmt.Sprintf(client.t("Could not successfully save new D-LINE: %s"), err.Error())) rb.Notice(fmt.Sprintf(client.t("Could not successfully save new D-LINE: %s"), err.Error()))

View File

@ -518,13 +518,13 @@ given, views the current topic on the channel.`,
Oragono's "unified ban" system. Accepts the following subcommands: Oragono's "unified ban" system. Accepts the following subcommands:
1. UBAN ADD <target> [DURATION <duration>] [REASON...] 1. UBAN ADD <target> [REQUIRE-SASL] [DURATION <duration>] [REASON...]
2. UBAN DEL <target> 2. UBAN DEL <target>
3. UBAN LIST 3. UBAN LIST
4. UBAN INFO <target> 4. UBAN INFO <target>
<target> may be an IP, a CIDR, a nickmask with wildcards, or the name of an <target> may be an IP, a CIDR, a nickmask with wildcards, or the name of an
account to suspend.`, account to suspend. Note that REQUIRE-SASL is only valid for IP and CIDR bans.`,
}, },
"undline": { "undline": {
oper: true, oper: true,

View File

@ -179,8 +179,13 @@ func (server *Server) checkBans(config *Config, ipaddr net.IP, checkScripts bool
// check DLINEs // check DLINEs
isBanned, info := server.dlines.CheckIP(flat) isBanned, info := server.dlines.CheckIP(flat)
if isBanned { if isBanned {
server.logger.Info("connect-ip", "Client rejected by d-line", ipaddr.String()) if info.RequireSASL {
return true, false, info.BanMessage("You are banned from this server (%s)") server.logger.Info("connect-ip", "Requiring SASL from client due to d-line", ipaddr.String())
return false, true, info.BanMessage("You must authenticate with SASL to connect from this IP (%s)")
} else {
server.logger.Info("connect-ip", "Client rejected by d-line", ipaddr.String())
return true, false, info.BanMessage("You are banned from this server (%s)")
}
} }
// check connection limits // check connection limits
@ -202,14 +207,14 @@ func (server *Server) checkBans(config *Config, ipaddr net.IP, checkScripts bool
server.logger.Error("internal", "couldn't check IP ban script", ipaddr.String(), err.Error()) server.logger.Error("internal", "couldn't check IP ban script", ipaddr.String(), err.Error())
return false, false, "" return false, false, ""
} }
// TODO: currently no way to cache results other than IPBanned // TODO: currently no way to cache IPAccepted
if output.Result == IPBanned && output.CacheSeconds != 0 { if (output.Result == IPBanned || output.Result == IPRequireSASL) && output.CacheSeconds != 0 {
network, err := flatip.ParseToNormalizedNet(output.CacheNet) network, err := flatip.ParseToNormalizedNet(output.CacheNet)
if err != nil { if err != nil {
server.logger.Error("internal", "invalid dline net from IP ban script", ipaddr.String(), output.CacheNet) server.logger.Error("internal", "invalid dline net from IP ban script", ipaddr.String(), output.CacheNet)
} else { } else {
dlineDuration := time.Duration(output.CacheSeconds) * time.Second dlineDuration := time.Duration(output.CacheSeconds) * time.Second
err := server.dlines.AddNetwork(network, dlineDuration, output.BanMessage, "", "") err := server.dlines.AddNetwork(network, dlineDuration, output.Result == IPRequireSASL, output.BanMessage, "", "")
if err != nil { if err != nil {
server.logger.Error("internal", "couldn't set dline from IP ban script", ipaddr.String(), err.Error()) server.logger.Error("internal", "couldn't set dline from IP ban script", ipaddr.String(), err.Error())
} }

View File

@ -16,15 +16,24 @@ import (
"github.com/oragono/oragono/irc/utils" "github.com/oragono/oragono/irc/utils"
) )
func consumeDuration(params []string, rb *ResponseBuffer) (duration time.Duration, remainingParams []string, err error) { func consumeDuration(params []string, rb *ResponseBuffer) (duration time.Duration, requireSASL bool, remainingParams []string, err error) {
remainingParams = params remainingParams = params
if 2 <= len(remainingParams) && strings.ToLower(remainingParams[0]) == "duration" { for {
duration, err = custime.ParseDuration(remainingParams[1]) if duration == 0 && 2 <= len(remainingParams) && strings.ToLower(remainingParams[0]) == "duration" {
if err != nil { duration, err = custime.ParseDuration(remainingParams[1])
rb.Notice(rb.session.client.t("Invalid time duration for NS SUSPEND")) if err != nil {
return rb.Notice(rb.session.client.t("Invalid time duration for NS SUSPEND"))
return
}
remainingParams = remainingParams[2:]
continue
} }
remainingParams = remainingParams[2:] if !requireSASL && 1 <= len(remainingParams) && strings.ToLower(remainingParams[0]) == "require-sasl" {
requireSASL = true
remainingParams = remainingParams[1:]
continue
}
break
} }
return return
} }
@ -139,7 +148,7 @@ func sessionsForCIDR(server *Server, cidr flatip.IPNet, exclude *Session) (sessi
} }
func ubanAddHandler(client *Client, target ubanTarget, params []string, rb *ResponseBuffer) bool { func ubanAddHandler(client *Client, target ubanTarget, params []string, rb *ResponseBuffer) bool {
duration, params, err := consumeDuration(params, rb) duration, requireSASL, params, err := consumeDuration(params, rb)
if err != nil { if err != nil {
return false return false
} }
@ -148,7 +157,7 @@ func ubanAddHandler(client *Client, target ubanTarget, params []string, rb *Resp
switch target.banType { switch target.banType {
case ubanCIDR: case ubanCIDR:
ubanAddCIDR(client, target, duration, operReason, rb) ubanAddCIDR(client, target, duration, requireSASL, operReason, rb)
case ubanNickmask: case ubanNickmask:
ubanAddNickmask(client, target, duration, operReason, rb) ubanAddNickmask(client, target, duration, operReason, rb)
case ubanNick: case ubanNick:
@ -158,8 +167,8 @@ func ubanAddHandler(client *Client, target ubanTarget, params []string, rb *Resp
return false return false
} }
func ubanAddCIDR(client *Client, target ubanTarget, duration time.Duration, operReason string, rb *ResponseBuffer) { func ubanAddCIDR(client *Client, target ubanTarget, duration time.Duration, requireSASL bool, operReason string, rb *ResponseBuffer) {
err := client.server.dlines.AddNetwork(target.cidr, duration, "", operReason, client.Oper().Name) err := client.server.dlines.AddNetwork(target.cidr, duration, requireSASL, "", operReason, client.Oper().Name)
if err == nil { if err == nil {
rb.Notice(fmt.Sprintf(client.t("Successfully added UBAN for %s"), target.cidr.HumanReadableString())) rb.Notice(fmt.Sprintf(client.t("Successfully added UBAN for %s"), target.cidr.HumanReadableString()))
} else { } else {