Skip to content

Commit

Permalink
Optimize regexp compilations (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomMoulard authored Oct 5, 2023
1 parent e2716ec commit 46c5b4c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 16 deletions.
25 changes: 15 additions & 10 deletions fail2ban.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ func CreateConfig() *Config {
type RulesTransformed struct {
Bantime time.Duration
Findtime time.Duration
URLRegexpAllow []string
URLRegexpBan []string
URLRegexpAllow []*regexp.Regexp
URLRegexpBan []*regexp.Regexp
MaxRetry int
Enabled bool
}
Expand All @@ -97,18 +97,23 @@ func TransformRule(r Rules) (RulesTransformed, error) {

log.Printf("Findtime: %s", findtime)

var regexpAllow []string
var regexpAllow []*regexp.Regexp

var regexpBan []string
var regexpBan []*regexp.Regexp

for _, rg := range r.Urlregexps {
log.Printf("using mode %q for rule %q", rg.Mode, rg.Regexp)

re, err := regexp.Compile(rg.Regexp)
if err != nil {
return RulesTransformed{}, fmt.Errorf("failed to compile regexp %q: %w", rg.Regexp, err)
}

switch rg.Mode {
case "allow":
regexpAllow = append(regexpAllow, rg.Regexp)
regexpAllow = append(regexpAllow, re)
case "block":
regexpBan = append(regexpBan, rg.Regexp)
regexpBan = append(regexpBan, re)
default:
log.Printf("mode %q is not known, the rule %q cannot not be applied", rg.Mode, rg.Regexp)
}
Expand Down Expand Up @@ -254,19 +259,19 @@ func (u *Fail2Ban) shouldAllow(remoteIP, reqURL string) bool {
urlBytes := []byte(reqURL)

for _, reg := range u.rules.URLRegexpBan {
if matched, err := regexp.Match(reg, urlBytes); err != nil || matched {
if reg.Match(urlBytes) {
u.ipViewed[remoteIP] = IPViewed{time.Now(), ip.nb + 1, true}

LoggerDEBUG.Printf("Url (%q) was matched by regexpBan: %q for %q", reqURL, reg, remoteIP)
LoggerDEBUG.Printf("Url (%q) was matched by regexpBan: %q for %q", reqURL, reg.String(), remoteIP)

return false
}
}

// Urlregexp allow
for _, reg := range u.rules.URLRegexpAllow {
if matched, err := regexp.Match(reg, urlBytes); err != nil || matched {
LoggerDEBUG.Printf("Url (%q) was matched by regexpAllow: %q for %q", reqURL, reg, remoteIP)
if reg.Match(urlBytes) {
LoggerDEBUG.Printf("Url (%q) was matched by regexpAllow: %q for %q", reqURL, reg.String(), remoteIP)

return true
}
Expand Down
44 changes: 42 additions & 2 deletions fail2ban_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"net/http"
"net/http/httptest"
"regexp"
"strings"
"sync/atomic"
"testing"
Expand Down Expand Up @@ -212,6 +213,45 @@ func TestFail2Ban(t *testing.T) {
newError: false,
expectStatus: http.StatusOK,
},
{
name: "bad regexp",
url: "/test",
cfg: Config{
Rules: Rules{
Enabled: true,
Bantime: "300s",
Findtime: "300s",
Maxretry: 10,
Urlregexps: []Urlregexp{
{
Regexp: "/(test",
Mode: "allow",
},
},
},
},
newError: true,
},
{
name: "invalid Regexp mode",
url: "/test",
cfg: Config{
Rules: Rules{
Enabled: true,
Bantime: "300s",
Findtime: "300s",
Maxretry: 20,
Urlregexps: []Urlregexp{
{
Regexp: "/test",
Mode: "not-an-actual-mode",
},
},
},
},
newError: false,
expectStatus: http.StatusOK, // request not blacklisted
},
{
name: "url whitelisted",
url: "/test",
Expand Down Expand Up @@ -426,7 +466,7 @@ func TestShouldAllow(t *testing.T) {
cfg: &Fail2Ban{
rules: RulesTransformed{
Bantime: 300 * time.Second,
URLRegexpAllow: []string{"/test"}, // comment me.
URLRegexpAllow: []*regexp.Regexp{regexp.MustCompile("/test")}, // comment me.
},
ipViewed: map[string]IPViewed{
"10.0.0.0": {
Expand All @@ -444,7 +484,7 @@ func TestShouldAllow(t *testing.T) {
name: "block regexp",
cfg: &Fail2Ban{
rules: RulesTransformed{
URLRegexpBan: []string{"/test"}, // comment me.
URLRegexpBan: []*regexp.Regexp{regexp.MustCompile("/test")}, // comment me.
},
ipViewed: map[string]IPViewed{},
},
Expand Down
12 changes: 10 additions & 2 deletions log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ import (
"log"
)

func New(out io.Writer, prefix string, flag int) *log.Logger {
return nil
type Logger struct {
*log.Logger
}

func New(out io.Writer, prefix string, flag int) Logger {
return Logger{}
}

func (l Logger) Printf(format string, v ...interface{}) {}

func (l Logger) Println(v ...interface{}) {}
8 changes: 6 additions & 2 deletions log/log_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import (
"log"
)

func New(out io.Writer, prefix string, flag int) *log.Logger {
return log.New(out, prefix, flag)
type Logger struct {
*log.Logger
}

func New(out io.Writer, prefix string, flag int) Logger {
return Logger{log.New(out, prefix, flag)}
}

0 comments on commit 46c5b4c

Please sign in to comment.