Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ctl): implement ctl regexes #1207

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions internal/actions/ctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package actions
import (
"errors"
"fmt"
"regexp"
"strconv"
"strings"

Expand Down Expand Up @@ -105,11 +106,12 @@ type ctlFn struct {
value string
collection variables.RuleVariable
colKey string
colKeyRx *regexp.Regexp
}

func (a *ctlFn) Init(_ plugintypes.RuleMetadata, data string) error {
var err error
a.action, a.value, a.collection, a.colKey, err = parseCtl(data)
a.action, a.value, a.collection, a.colKey, a.colKeyRx, err = parseCtl(data)
return err
}

Expand Down Expand Up @@ -375,18 +377,25 @@ func (a *ctlFn) Type() plugintypes.ActionType {
return plugintypes.ActionTypeNondisruptive
}

func parseCtl(data string) (ctlFunctionType, string, variables.RuleVariable, string, error) {
func parseCtl(data string) (ctlFunctionType, string, variables.RuleVariable, string, *regexp.Regexp, error) {
action, ctlVal, ok := strings.Cut(data, "=")
if !ok {
return ctlUnknown, "", 0, "", errors.New("invalid syntax")
return ctlUnknown, "", 0, "", nil, errors.New("invalid syntax")
}
value, col, ok := strings.Cut(ctlVal, ";")
var colkey, colname string
if ok {
colname, colkey, _ = strings.Cut(col, ":")
}
collection, _ := variables.Parse(strings.TrimSpace(colname))
colkey = strings.ToLower(colkey)
var re *regexp.Regexp
if len(colkey) > 2 && colkey[0] == '/' && colkey[len(colkey)-1] == '/' {
var err error
re, err = regexp.Compile(colkey[1 : len(colkey)-1])
if err != nil {
return ctlUnknown, "", 0x00, "", nil, err
}
}
var act ctlFunctionType
switch action {
case "auditEngine":
Expand Down Expand Up @@ -430,9 +439,12 @@ func parseCtl(data string) (ctlFunctionType, string, variables.RuleVariable, str
case "debugLogLevel":
act = ctlDebugLogLevel
default:
return ctlUnknown, "", 0x00, "", fmt.Errorf("unknown ctl action %q", action)
return ctlUnknown, "", 0x00, "", nil, fmt.Errorf("unknown ctl action %q", action)
}
if re != nil {
return act, value, collection, strings.TrimSpace(colkey), re, nil
}
return act, value, collection, strings.TrimSpace(colkey), nil
return act, value, collection, strings.TrimSpace(strings.ToLower(colkey)), nil, nil
}

func rangeToInts(rules []corazawaf.Rule, input string) ([]int, error) {
Expand Down
25 changes: 22 additions & 3 deletions internal/actions/ctl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ func TestCtl(t *testing.T) {

func TestParseCtl(t *testing.T) {
t.Run("invalid ctl", func(t *testing.T) {
ctl, _, _, _, err := parseCtl("invalid")
ctl, _, _, _, _, err := parseCtl("invalid")
if err == nil {
t.Errorf("expected error, got nil")
}
Expand All @@ -379,7 +379,7 @@ func TestParseCtl(t *testing.T) {
})

t.Run("malformed ctl", func(t *testing.T) {
ctl, _, _, _, err := parseCtl("unknown=")
ctl, _, _, _, _, err := parseCtl("unknown=")
if err == nil {
t.Errorf("expected error, got nil")
}
Expand Down Expand Up @@ -417,10 +417,13 @@ func TestParseCtl(t *testing.T) {
for _, tCase := range tCases {
testName, _, _ := strings.Cut(tCase.input, "=")
t.Run(testName, func(t *testing.T) {
action, value, collection, colKey, err := parseCtl(tCase.input)
action, value, collection, colKey, rx, err := parseCtl(tCase.input)
if err != nil {
t.Fatalf("unexpected error: %s", err.Error())
}
if rx != nil {
t.Error("unexpected regex, want nil regex")
}
if action != tCase.expectAction {
t.Errorf("unexpected action, want: %d, have: %d", tCase.expectAction, action)
}
Expand All @@ -435,8 +438,24 @@ func TestParseCtl(t *testing.T) {
}
})
}
}

func TestCtlRegexColname(t *testing.T) {
_, _, _, _, rx, err := parseCtl("ruleRemoveTargetById=2;ARGS:/user/")
if err != nil {
t.Fatalf("unexpected error: %s", err.Error())
}
if rx == nil {
t.Error("unexpected nil regex")
}
if rx.String() != "user" {
t.Errorf("unexpected regex, want: user, have: %s", rx.String())
}
if !rx.MatchString("user") {
t.Error("unexpected match")
}
}

func TestCtlParseRange(t *testing.T) {
rules := []corazawaf.Rule{
{
Expand Down
Loading