diff --git a/README.md b/README.md index 7f37f9d3..3ffb38d6 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,9 @@ gor --input-raw :8080 --output-http staging.com --http-disallow-url /api ``` # only forward requests with an api version of 1.0x gor --input-raw :8080 --output-http staging.com --http-allow-header api-version:^1\.0\d + +# only forward requests NOT containing User-Agent header value "Replayed by Gor" +gor --input-raw :8080 --output-http staging.com --http-disallow-header "User-Agent: Replayed by Gor" ``` #### Filter based on http method @@ -260,6 +263,8 @@ https://github.com/buger/gor/releases ``` -http-allow-header=[]: A regexp to match a specific header against. Requests with non-matching headers will be dropped: gor --input-raw :8080 --output-http staging.com --http-allow-header api-version:^v1 + -http-disallow-header=[]: A regexp to match a specific header against. Requests with matching headers will be dropped: + gor --input-raw :8080 --output-http staging.com --http-disallow-header "User-Agent: Replayed by Gor" -http-allow-method=[]: Whitelist of HTTP methods to replay. Anything else will be dropped: gor --input-raw :8080 --output-http staging.com --http-allow-method GET --http-allow-method OPTIONS -http-allow-url=[]: A regexp to match requests against. Filter get matched agains full url with domain. Anything else will be dropped: diff --git a/http_modifier.go b/http_modifier.go index d820df66..4efa684a 100644 --- a/http_modifier.go +++ b/http_modifier.go @@ -2,8 +2,9 @@ package main import ( "bytes" - "github.com/buger/gor/proto" "hash/fnv" + + "github.com/buger/gor/proto" ) type HTTPModifier struct { @@ -16,6 +17,7 @@ func NewHTTPModifier(config *HTTPModifierConfig) *HTTPModifier { len(config.urlNegativeRegexp) == 0 && len(config.urlRewrite) == 0 && len(config.headerFilters) == 0 && + len(config.headerNegativeFilters) == 0 && len(config.headerHashFilters) == 0 && len(config.paramHashFilters) == 0 && len(config.params) == 0 && @@ -94,6 +96,16 @@ func (m *HTTPModifier) Rewrite(payload []byte) (response []byte) { } } + if len(m.config.headerNegativeFilters) > 0 { + for _, f := range m.config.headerNegativeFilters { + value, s, _, _ := proto.Header(payload, f.name) + + if s != -1 && f.regexp.Match(value) { + return + } + } + } + if len(m.config.headerHashFilters) > 0 { for _, f := range m.config.headerHashFilters { value, s, _, _ := proto.Header(payload, f.name) diff --git a/http_modifier_settings.go b/http_modifier_settings.go index 854b11a1..43f81d17 100644 --- a/http_modifier_settings.go +++ b/http_modifier_settings.go @@ -9,12 +9,13 @@ import ( ) type HTTPModifierConfig struct { - urlNegativeRegexp HTTPUrlRegexp - urlRegexp HTTPUrlRegexp - urlRewrite UrlRewriteMap - headerFilters HTTPHeaderFilters - headerHashFilters HTTPHashFilters - paramHashFilters HTTPHashFilters + urlNegativeRegexp HTTPUrlRegexp + urlRegexp HTTPUrlRegexp + urlRewrite UrlRewriteMap + headerFilters HTTPHeaderFilters + headerNegativeFilters HTTPHeaderFilters + headerHashFilters HTTPHashFilters + paramHashFilters HTTPHashFilters params HTTPParams headers HTTPHeaders @@ -22,7 +23,7 @@ type HTTPModifierConfig struct { } // -// Handling of --http-allow-header options +// Handling of --http-allow-header, --http-disallow-header options // type headerFilter struct { name []byte diff --git a/http_modifier_test.go b/http_modifier_test.go index 40e5ec48..d92829e5 100644 --- a/http_modifier_test.go +++ b/http_modifier_test.go @@ -39,6 +39,33 @@ func TestHTTPModifierHeaderFilters(t *testing.T) { } } +func TestHTTPModifierHeaderNegativeFilters(t *testing.T) { + filters := HTTPHeaderFilters{} + filters.Set("Host:^www.w3.org$") + + modifier := NewHTTPModifier(&HTTPModifierConfig{ + headerNegativeFilters: filters, + }) + + payload := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w4.org\r\n\r\na=1&b=2") + + if len(modifier.Rewrite(payload)) == 0 { + t.Error("Request should pass filters") + } + + filters = HTTPHeaderFilters{} + // Setting filter that not match our header + filters.Set("Host:^www.w4.org$") + + modifier = NewHTTPModifier(&HTTPModifierConfig{ + headerNegativeFilters: filters, + }) + + if len(modifier.Rewrite(payload)) != 0 { + t.Error("Request should not pass filters") + } +} + func TestHTTPModifierURLRewrite(t *testing.T) { var url, new_url []byte diff --git a/settings.go b/settings.go index 8c345e7b..3e6d6d0e 100644 --- a/settings.go +++ b/settings.go @@ -107,6 +107,8 @@ func init() { flag.Var(&Settings.modifierConfig.headerFilters, "http-allow-header", "A regexp to match a specific header against. Requests with non-matching headers will be dropped:\n\t gor --input-raw :8080 --output-http staging.com --http-allow-header api-version:^v1") flag.Var(&Settings.modifierConfig.headerFilters, "output-http-header-filter", "WARNING: `--output-http-header-filter` DEPRECATED, use `--http-allow-header` instead") + flag.Var(&Settings.modifierConfig.headerFilters, "http-disallow-header", "A regexp to match a specific header against. Requests with matching headers will be dropped:\n\t gor --input-raw :8080 --output-http staging.com --http-disallow-header \"User-Agent: Replayed by Gor\"") + flag.Var(&Settings.modifierConfig.headerHashFilters, "http-header-limiter", "Takes a fraction of requests, consistently taking or rejecting a request based on the FNV32-1A hash of a specific header:\n\t gor --input-raw :8080 --output-http staging.com --http-header-imiter user-id:25%") flag.Var(&Settings.modifierConfig.headerHashFilters, "output-http-header-hash-filter", "WARNING: `output-http-header-hash-filter` DEPRECATED, use `--http-header-hash-limiter` instead")