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

Content based block filter #2002

Merged
merged 32 commits into from
Aug 29, 2022
Merged

Content based block filter #2002

merged 32 commits into from
Aug 29, 2022

Conversation

MustafaSaber
Copy link
Member

@MustafaSaber MustafaSaber commented May 9, 2022

Intro

Body filter is a used to block requests based on body content

Implementation can be tested with proxy
./bin/skipper -address=:9999 -inline-routes='r: * -> block("foo") -> "http://127.0.0.1:9090";'

@MustafaSaber MustafaSaber self-assigned this May 10, 2022
@MustafaSaber MustafaSaber marked this pull request as ready for review May 18, 2022 13:23

func newMatcher(
input io.ReadCloser,
matchList []string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to store the []byte converted strings

type matchData struct { b []byte }

matchList []matchData,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var consumed int

for _, s := range m.matchList {
if bytes.Contains(b, []byte(s)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can prepare string s from matchList to be a []byte already, such that we do the conversion once.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log "github.com/sirupsen/logrus"
)

type maxBufferHandling int
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move the type to the iota const, such that these are close together


// init:
input io.ReadCloser
matchList []string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be either a map[int][]byte or a []buffer with type buffer []byte
see also https://go.dev/play/p/IKAa6eA91YD
I think the type is more memory efficient, but it does not really matter if we do not store millions of strings.


Block a request based on it's body content.

The filter max request body is 2MiB by default and can be overidden with `-max-matcher-buffer-size=<int>`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sentence is not correct because it is only using a 2MiB buffer as default and does not stop processing the body.


Parameters:

* toblockList (List of []bytes)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a list of string instead of list of []byte from the user perspective, which is what we document here.

Example:

```
* -> block("maliciousCotent") -> "http://example.com";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maliciousCotent -> malicious Content

return n, nil
}

// Closes closes the undelrying reader if it implements io.Closer.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

godoc: Closes -> Close first has to match the func name

Copy link
Member

@szuecs szuecs Jun 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also tell in the godoc that it's not safe for concurrent use and it is reentrant.

ready *bytes.Buffer
pending *bytes.Buffer

// metrices:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop this comment

//
type matcher struct {

// init:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop this comment

// metrices:
metrics metrics.Metrics

// final:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop this comment


if m.err == proxy.ErrBlocked {
m.metrics.IncCounter("blocked.requests")
log.Errorf("Content blocked: %v", proxy.ErrBlocked)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not log here, because it's more the library part.


if err == proxy.ErrBlocked {
m.metrics.IncCounter("blocked.requests")
log.Errorf("Content blocked: %v", proxy.ErrBlocked)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here drop the log

skipper.go Outdated
@@ -774,6 +775,10 @@ type Options struct {
// MaxAuditBody sets the maximum read size of the body read by the audit log filter
MaxAuditBody int

// MaxMatcherBufferSize sets the maximum read size of the body read by the block filter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say:

MaxMatcherBufferSize sets the maximum read buffer size of the block filter defaults to 2MiB in case of a zero value

@MustafaSaber
Copy link
Member Author

👍

szuecs and others added 8 commits August 29, 2022 12:25
Signed-off-by: Sandor Szücs <sandor.szuecs@zalando.de>
Make test pass when err is expected

Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Return the int output of the reader if the error was block otherwise it implies failing in reading.

Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Support having chunks of data for the same request.

Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Passing valid request without reading extra nil chunks of data.

Blocking non valid requests without going into infinite loops.

Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Move block entrypoint with with a global flag in config to control max body size.

Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Change string to []bytes for better memory utilization on the long term.

Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
Update docs & godocs.

Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
@MustafaSaber
Copy link
Member Author

👍


// Close closes the undelrying reader if it implements io.Closer.
// Not safe for concurrent usage and it's reentrant.
func (m *matcher) Close() error {
Copy link
Member

@szuecs szuecs Aug 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use sync.Once to only run this once. see also: https://github.com/zalando/skipper/blob/master/filters/shedder/admission.go#L324-L329

docs/reference/filters.md Outdated Show resolved Hide resolved
Signed-off-by: Mustafa Abdelrahman <mustafa.abdelrahman@zalando.de>
@szuecs
Copy link
Member

szuecs commented Aug 29, 2022

👍

1 similar comment
@MustafaSaber
Copy link
Member Author

👍

@MustafaSaber MustafaSaber merged commit 92ba2ed into master Aug 29, 2022
@MustafaSaber MustafaSaber deleted the feature/body-filtering-v2 branch August 29, 2022 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants