aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-11-17 16:39:09 +0100
committerHimbeer <himbeer@disroot.org>2024-11-17 16:39:09 +0100
commit3b344731fff17f3c5255f278f8f14879e7610f7d (patch)
treef92726ba8364a21e450ff4b53fedfd285ab253e5
parentd0d39d2f9f3abb68eec146376b3233c8bc7c1cfa (diff)
Notify authentication backends of failed login attempts
Closes #157.
-rw-r--r--auth.go13
-rw-r--r--auth_files.go10
-rw-r--r--auth_mtpostgresql.go10
-rw-r--r--auth_mtsqlite3.go10
-rw-r--r--process.go8
5 files changed, 37 insertions, 14 deletions
diff --git a/auth.go b/auth.go
index 45f9bdc..80ce286 100644
--- a/auth.go
+++ b/auth.go
@@ -2,7 +2,6 @@ package proxy
import (
"errors"
- "net"
"strings"
"time"
)
@@ -66,9 +65,15 @@ type AuthBackend interface {
Ban(addr, name string) error
// Unban deletes a ban entry by network address or username.
Unban(id string) error
- // Banned reports whether a network address is banned.
- // The result is true if an error is encountered.
- Banned(addr *net.UDPAddr) bool
+ // Banned reports whether a network address or username is banned.
+ // The result is true if either identifier is banned
+ // or if an error is encountered.
+ Banned(addr, name string) bool
+ // RecordFail records an authentication failure regarding a certain
+ // network address and username. The implementation is not required
+ // to process this event in any way, but the intent is to allow
+ // rate limiting / brute-force protection to be implemented by plugins.
+ RecordFail(addr, name string, sudo bool) error
// ImportBans adds or modifies ban entries in bulk.
ImportBans(in []Ban) error
// Export returns all ban entries or an error.
diff --git a/auth_files.go b/auth_files.go
index eb7a076..c6a4d5d 100644
--- a/auth_files.go
+++ b/auth_files.go
@@ -1,7 +1,6 @@
package proxy
import (
- "net"
"os"
"time"
)
@@ -164,10 +163,10 @@ func (a AuthFiles) Unban(id string) error {
// Banned reports whether a network address is banned.
// Error cases count as banned.
-func (a AuthFiles) Banned(addr *net.UDPAddr) bool {
+func (a AuthFiles) Banned(addr, name string) bool {
os.Mkdir(Path("ban"), 0700)
- _, err := os.Stat(Path("ban/", addr.IP.String()))
+ _, err := os.Stat(Path("ban/", addr))
if os.IsNotExist(err) {
return false
}
@@ -175,6 +174,11 @@ func (a AuthFiles) Banned(addr *net.UDPAddr) bool {
return true
}
+// RecordFail is a no-op.
+func (a AuthFiles) RecordFail(addr, name string, sudo bool) error {
+ return nil
+}
+
// ImportBans deletes all ban entries and adds the passed entries.
func (a AuthFiles) ImportBans(in []Ban) error {
os.Mkdir(Path("ban"), 0700)
diff --git a/auth_mtpostgresql.go b/auth_mtpostgresql.go
index dc7f2f3..790a30f 100644
--- a/auth_mtpostgresql.go
+++ b/auth_mtpostgresql.go
@@ -5,7 +5,6 @@ import (
"database/sql"
"errors"
"fmt"
- "net"
"os"
"strings"
"time"
@@ -261,16 +260,21 @@ func (a *AuthMTPostgreSQL) Unban(id string) error {
// Banned reports whether a network address is banned.
// Error cases count as banned.
-func (a *AuthMTPostgreSQL) Banned(addr *net.UDPAddr) bool {
+func (a *AuthMTPostgreSQL) Banned(addr, name string) bool {
bans, err := a.readBans()
if err != nil {
return true
}
- _, ok := bans[addr.IP.String()]
+ _, ok := bans[addr]
return ok
}
+// RecordFail is a no-op.
+func (a *AuthMTPostgreSQL) RecordFail(addr, name string, sudo bool) error {
+ return nil
+}
+
// ImportBans adds the passed entries.
func (a *AuthMTPostgreSQL) ImportBans(in []Ban) error {
for _, b := range in {
diff --git a/auth_mtsqlite3.go b/auth_mtsqlite3.go
index fb340c5..3140e69 100644
--- a/auth_mtsqlite3.go
+++ b/auth_mtsqlite3.go
@@ -5,7 +5,6 @@ import (
"database/sql"
"errors"
"fmt"
- "net"
"os"
"strings"
"time"
@@ -207,16 +206,21 @@ func (a *AuthMTSQLite3) Unban(id string) error {
// Banned reports whether a network address is banned.
// Error cases count as banned.
-func (a *AuthMTSQLite3) Banned(addr *net.UDPAddr) bool {
+func (a *AuthMTSQLite3) Banned(addr, name string) bool {
bans, err := a.readBans()
if err != nil {
return true
}
- _, ok := bans[addr.IP.String()]
+ _, ok := bans[addr]
return ok
}
+// RecordFail is a no-op.
+func (a *AuthMTSQLite3) RecordFail(addr, name string, sudo bool) error {
+ return nil
+}
+
// ImportBans adds the passed entries.
func (a *AuthMTSQLite3) ImportBans(in []Ban) error {
for _, b := range in {
diff --git a/process.go b/process.go
index 71cf0b8..215e6cc 100644
--- a/process.go
+++ b/process.go
@@ -88,7 +88,8 @@ func (cc *ClientConn) process(pkt mt.Pkt) {
cc.name = cmd.PlayerName
cc.logger.SetPrefix(fmt.Sprintf("[%s %s] ", cc.RemoteAddr(), cc.Name()))
- if DefaultAuth().Banned(cc.RemoteAddr().(*net.UDPAddr)) {
+ ip := cc.RemoteAddr().(*net.UDPAddr).IP.String()
+ if DefaultAuth().Banned(ip, cc.Name()) {
cc.Log("<-", "banned")
cc.Kick("Banned by proxy.")
return
@@ -339,6 +340,11 @@ func (cc *ClientConn) process(pkt mt.Pkt) {
})
}
} else {
+ ip := cc.RemoteAddr().(*net.UDPAddr).IP.String()
+ if err := DefaultAuth().RecordFail(ip, cc.Name(), wantSudo); err != nil {
+ cc.Log("<-", "record auth fail:", err)
+ }
+
if wantSudo {
cc.Log("<-", "invalid password (sudo)")
cc.SendCmd(&mt.ToCltDenySudoMode{})