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

Update go.mod file for v2 #45

Merged
merged 5 commits into from
Nov 14, 2023
Merged
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
19 changes: 14 additions & 5 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,24 @@ func (context *Context) Run(addressData RunAddressData, timeout time.Duration) (
context.totalOverallRuntimeNs.Add(uint64(dt.Nanoseconds()))
}()

// We can ignore the encoding error because it can only tell us that the user values are incompatible with the WAF
// which is not something we care about here.
// At this point, the only error we can get is an error in case the top level object is a nil map, but this
// behaviour is expected since either persistent or ephemeral addresses are allowed to be null one at a time.
// In this case, EncodeAddresses will return nil contrary to Encode which will return an nil wafObject,
// which is what we need to send to ddwaf_run to signal that the address data is empty.
var persistentData *wafObject = nil
var ephemeralData *wafObject = nil
persistentEncoder := newLimitedEncoder()
persistentData, _ := persistentEncoder.Encode(addressData.Persistent)
ephemeralEncoder := newLimitedEncoder()
if addressData.Persistent != nil {
persistentData, _ = persistentEncoder.EncodeAddresses(addressData.Persistent)
}

if addressData.Ephemeral != nil {
ephemeralData, _ = ephemeralEncoder.EncodeAddresses(addressData.Ephemeral)

}
// The WAF releases ephemeral address data at the end of each run call, so we need not keep the Go values live beyond
// that in the same way we need for persistent data. We hence use a separate encoder.
ephemeralEncoder := newLimitedEncoder()
ephemeralData, _ := ephemeralEncoder.Encode(addressData.Ephemeral)

// ddwaf_run cannot run concurrently and the next append write on the context state so we need a mutex
context.mutex.Lock()
Expand Down
15 changes: 15 additions & 0 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@ func (encoder *encoder) Encode(data any) (*wafObject, error) {
return wo, nil
}

// EncodeAddresses takes a map of Go values and returns a wafObject pointer and an error.
// The returned wafObject is the root of the tree of nested wafObjects representing the Go values.
// This function is further optimized from Encode to take addresses as input and avoid further
// errors in case the top-level map with addresses as keys is nil.
// Since errors returned by Encode are not sent up between levels of the tree, this means that all errors come from the
// top layer of encoding, which is the map of addresses. Hence, all errors should be developer errors since the map of
// addresses is not user defined custom data.
func (encoder *encoder) EncodeAddresses(addresses map[string]any) (*wafObject, error) {
if addresses == nil {
return nil, errUnsupportedValue
}

return encoder.Encode(addresses)
}

func encodeNative[T native](val T, t wafObjectType, obj *wafObject) {
obj._type = t
obj.value = (uintptr)(val)
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/DataDog/go-libddwaf
module github.com/DataDog/go-libddwaf/v2

go 1.18

Expand All @@ -18,4 +18,5 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)

retract v1.6.0 // Breaking version, published too soon
// Version where import paths were not changed to go-libddwaf/v2
retract v2.0.0
2 changes: 1 addition & 1 deletion handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"fmt"
"sync"

"github.com/DataDog/go-libddwaf/internal/noopfree"
"github.com/DataDog/go-libddwaf/v2/internal/noopfree"
"go.uber.org/atomic"
)

Expand Down
2 changes: 1 addition & 1 deletion waf_dl.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"fmt"
"os"

"github.com/DataDog/go-libddwaf/internal/lib"
"github.com/DataDog/go-libddwaf/v2/internal/lib"
"github.com/ebitengine/purego"
)

Expand Down
2 changes: 1 addition & 1 deletion waf_dl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"runtime"
"testing"

"github.com/DataDog/go-libddwaf/internal/lib"
"github.com/DataDog/go-libddwaf/v2/internal/lib"
"github.com/stretchr/testify/require"
)

Expand Down
64 changes: 63 additions & 1 deletion waf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"text/template"
"time"

"github.com/DataDog/go-libddwaf/internal/lib"
"github.com/DataDog/go-libddwaf/v2/internal/lib"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -511,6 +511,68 @@ func TestMatchingEphemeral(t *testing.T) {
require.Nil(t, NewContext(waf))
}

func TestMatchingEphemeralOnly(t *testing.T) {
const (
input1 = "my.input.1"
input2 = "my.input.2"
)

waf, err := newDefaultHandle(newArachniTestRulePair(ruleInput{Address: input1}, ruleInput{Address: input2}))
require.NoError(t, err)
require.NotNil(t, waf)

addrs := waf.Addresses()
sort.Strings(addrs)
require.Equal(t, []string{input1, input2}, addrs)

wafCtx := NewContext(waf)
require.NotNil(t, wafCtx)

// Not matching because the address value doesn't match the rule
runAddresses := RunAddressData{
Ephemeral: map[string]interface{}{
input1: "go client",
},
}
res, err := wafCtx.Run(runAddresses, time.Second)
require.NoError(t, err)
require.Nil(t, res.Events)
require.Nil(t, res.Actions)

// Not matching because the address is not used by the rule
runAddresses = RunAddressData{
Ephemeral: map[string]interface{}{
"server.request.uri.raw": "something",
},
}
res, err = wafCtx.Run(runAddresses, time.Second)
require.NoError(t, err)
require.Nil(t, res.Events)
require.Nil(t, res.Actions)

// Not matching due to a timeout
runAddresses = RunAddressData{
Ephemeral: map[string]interface{}{
input1: "Arachni-1",
},
}
res, err = wafCtx.Run(runAddresses, 0)
require.Equal(t, ErrTimeout, err)
require.Nil(t, res.Events)
require.Nil(t, res.Actions)

// Matching
res, err = wafCtx.Run(runAddresses, time.Second)
require.NoError(t, err)
require.Len(t, res.Events, 1) // 1 ephemeral
require.Nil(t, res.Actions)

wafCtx.Close()
waf.Close()
// Using the WAF instance after it was closed leads to a nil WAF context
require.Nil(t, NewContext(waf))
}

func TestActions(t *testing.T) {
testActions := func(expectedActions []string) func(t *testing.T) {
return func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion waf_unsupported_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"errors"
"testing"

waf "github.com/DataDog/go-libddwaf"
waf "github.com/DataDog/go-libddwaf/v2"
"github.com/stretchr/testify/require"
)

Expand Down