Skip to content

Commit

Permalink
Enhance failtoban plugin with log-only mode and SIGHUP cache reset
Browse files Browse the repository at this point in the history
  • Loading branch information
tg123 committed Feb 5, 2025
1 parent 44068f3 commit 6e445b9
Showing 1 changed file with 29 additions and 3 deletions.
32 changes: 29 additions & 3 deletions plugin/failtoban/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ package main
import (
"fmt"
"net"
"os"
"os/signal"
"syscall"
"time"

gocache "github.com/patrickmn/go-cache"
Expand All @@ -17,7 +20,7 @@ func main() {

libplugin.CreateAndRunPluginTemplate(&libplugin.PluginTemplate{
Name: "failtoban",
Usage: "sshpiperd fixed plugin, only password auth is supported",
Usage: "failtoban plugin, block ip after too many auth failures",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "max-failures",
Expand All @@ -31,14 +34,33 @@ func main() {
EnvVars: []string{"SSHPIPERD_FAILTOBAN_BAN_DURATION"},
Value: 60 * time.Minute,
},
&cli.BoolFlag{
Name: "log-only",
Usage: "log only mode, no ban, useful for working with other tools like fail2ban",
EnvVars: []string{"SSHPIPERD_FAILTOBAN_LOG_ONLY"},
Value: false,
},
},
CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) {

maxFailures := c.Int("max-failures")
banDuration := c.Duration("ban-duration")
logOnly := c.Bool("log-only")

cache := gocache.New(banDuration, banDuration/2*3)

// register signal handler
go func() {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGHUP)

for {
<-sigChan
cache.Flush()
log.Info("failtoban: cache reset due to SIGHUP")
}
}()

return &libplugin.SshPiperPluginConfig{
NoClientAuthCallback: func(conn libplugin.ConnMetadata) (*libplugin.Upstream, error) {
// in case someone put the failtoban plugin before other plugins
Expand All @@ -47,6 +69,10 @@ func main() {
}, nil
},
NewConnectionCallback: func(conn libplugin.ConnMetadata) error {
if logOnly {
return nil
}

ip, _, _ := net.SplitHostPort(conn.RemoteAddr())

failed, found := cache.Get(ip)
Expand All @@ -64,12 +90,12 @@ func main() {
UpstreamAuthFailureCallback: func(conn libplugin.ConnMetadata, method string, err error, allowmethods []string) {
ip, _, _ := net.SplitHostPort(conn.RemoteAddr())
failed, _ := cache.IncrementInt(ip, 1)
log.Debugf("failtoban: %v auth failed. current status: fail %v times, max allowed %v", ip, failed, maxFailures)
log.Warnf("failtoban: %v auth failed. current status: fail %v times, max allowed %v", ip, failed, maxFailures)
},
PipeCreateErrorCallback: func(remoteAddr string, err error) {
ip, _, _ := net.SplitHostPort(remoteAddr)
failed, _ := cache.IncrementInt(ip, 1)
log.Debugf("failtoban: %v pipe create failed, reason %v. current status: fail %v times, max allowed %v", ip, err, failed, maxFailures)
log.Warnf("failtoban: %v pipe create failed, reason %v. current status: fail %v times, max allowed %v", ip, err, failed, maxFailures)
},
}, nil
},
Expand Down

0 comments on commit 6e445b9

Please sign in to comment.