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.
type IPBanInfo struct {
// RequireSASL indicates a "soft" ban; connections are allowed but they must SASL
RequireSASL bool
// Reason is the ban reason.
Reason string `json:"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.
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()
defer dm.persistenceMutex.Unlock()
// assemble ban info
info := IPBanInfo{
RequireSASL: requireSASL,
Reason: reason,
OperReason: operReason,
OperName: operName,

View File

@ -818,7 +818,11 @@ func formatBanForListing(client *Client, key string, info IPBanInfo) string {
if info.Duration != 0 {
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]]
@ -906,7 +910,7 @@ func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
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 {
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:
1. UBAN ADD <target> [DURATION <duration>] [REASON...]
1. UBAN ADD <target> [REQUIRE-SASL] [DURATION <duration>] [REASON...]
2. UBAN DEL <target>
3. UBAN LIST
4. UBAN INFO <target>
<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": {
oper: true,

View File

@ -179,8 +179,13 @@ func (server *Server) checkBans(config *Config, ipaddr net.IP, checkScripts bool
// check DLINEs
isBanned, info := server.dlines.CheckIP(flat)
if isBanned {
server.logger.Info("connect-ip", "Client rejected by d-line", ipaddr.String())
return true, false, info.BanMessage("You are banned from this server (%s)")
if info.RequireSASL {
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
@ -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())
return false, false, ""
}
// TODO: currently no way to cache results other than IPBanned
if output.Result == IPBanned && output.CacheSeconds != 0 {
// TODO: currently no way to cache IPAccepted
if (output.Result == IPBanned || output.Result == IPRequireSASL) && output.CacheSeconds != 0 {
network, err := flatip.ParseToNormalizedNet(output.CacheNet)
if err != nil {
server.logger.Error("internal", "invalid dline net from IP ban script", ipaddr.String(), output.CacheNet)
} else {
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 {
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"
)
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
if 2 <= len(remainingParams) && strings.ToLower(remainingParams[0]) == "duration" {
duration, err = custime.ParseDuration(remainingParams[1])
if err != nil {
rb.Notice(rb.session.client.t("Invalid time duration for NS SUSPEND"))
return
for {
if duration == 0 && 2 <= len(remainingParams) && strings.ToLower(remainingParams[0]) == "duration" {
duration, err = custime.ParseDuration(remainingParams[1])
if err != nil {
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
}
@ -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 {
duration, params, err := consumeDuration(params, rb)
duration, requireSASL, params, err := consumeDuration(params, rb)
if err != nil {
return false
}
@ -148,7 +157,7 @@ func ubanAddHandler(client *Client, target ubanTarget, params []string, rb *Resp
switch target.banType {
case ubanCIDR:
ubanAddCIDR(client, target, duration, operReason, rb)
ubanAddCIDR(client, target, duration, requireSASL, operReason, rb)
case ubanNickmask:
ubanAddNickmask(client, target, duration, operReason, rb)
case ubanNick:
@ -158,8 +167,8 @@ func ubanAddHandler(client *Client, target ubanTarget, params []string, rb *Resp
return false
}
func ubanAddCIDR(client *Client, target ubanTarget, duration time.Duration, operReason string, rb *ResponseBuffer) {
err := client.server.dlines.AddNetwork(target.cidr, duration, "", operReason, client.Oper().Name)
func ubanAddCIDR(client *Client, target ubanTarget, duration time.Duration, requireSASL bool, operReason string, rb *ResponseBuffer) {
err := client.server.dlines.AddNetwork(target.cidr, duration, requireSASL, "", operReason, client.Oper().Name)
if err == nil {
rb.Notice(fmt.Sprintf(client.t("Successfully added UBAN for %s"), target.cidr.HumanReadableString()))
} else {