diff --git a/src/core/metrics/sources/nginx_access_log.go b/src/core/metrics/sources/nginx_access_log.go index f18dc9fb7..69d0dcf43 100644 --- a/src/core/metrics/sources/nginx_access_log.go +++ b/src/core/metrics/sources/nginx_access_log.go @@ -18,6 +18,10 @@ import ( "github.com/nginx/agent/v2/src/core/metrics/sources/tailer" ) +const ( + spaceDelim = " " +) + // This metrics source is used to tail the NGINX access logs to retrieve http metrics. type NginxAccessLog struct { @@ -207,26 +211,30 @@ func (c *NginxAccessLog) logStats(ctx context.Context, logFile, logFormat string } if access.Request != "" { - splitRequest := strings.Split(access.Request, " ") - n := fmt.Sprintf("method.%s", strings.ToLower(splitRequest[0])) + method, _, protocol := getParsedRequest(access.Request) + n := fmt.Sprintf("method.%s", strings.ToLower(method)) if isOtherMethod(n) { n = "method.others" } counters[n] = counters[n] + 1 if access.ServerProtocol == "" { - httpProtocolVersion := strings.Split(splitRequest[2], "/")[1] - httpProtocolVersion = strings.ReplaceAll(httpProtocolVersion, ".", "_") - n = fmt.Sprintf("v%s", httpProtocolVersion) - counters[n] = counters[n] + 1 + if strings.Count(protocol, "/") == 1 { + httpProtocolVersion := strings.Split(protocol, "/")[1] + httpProtocolVersion = strings.ReplaceAll(httpProtocolVersion, ".", "_") + n = fmt.Sprintf("v%s", httpProtocolVersion) + counters[n] = counters[n] + 1 + } } } if access.ServerProtocol != "" { - httpProtocolVersion := strings.Split(access.ServerProtocol, "/")[1] - httpProtocolVersion = strings.ReplaceAll(httpProtocolVersion, ".", "_") - n := fmt.Sprintf("v%s", httpProtocolVersion) - counters[n] = counters[n] + 1 + if strings.Count(access.ServerProtocol, "/") == 1 { + httpProtocolVersion := strings.Split(access.ServerProtocol, "/")[1] + httpProtocolVersion = strings.ReplaceAll(httpProtocolVersion, ".", "_") + n := fmt.Sprintf("v%s", httpProtocolVersion) + counters[n] = counters[n] + 1 + } } // don't need the http status for NGINX Plus @@ -294,6 +302,35 @@ func (c *NginxAccessLog) logStats(ctx context.Context, logFile, logFormat string } } +func getParsedRequest(request string) (method string, uri string, protocol string) { + if len(request) == 0 { + return + } + + startURIIdx := strings.Index(request, spaceDelim) + if startURIIdx == -1 { + return + } + + endURIIdx := strings.LastIndex(request, spaceDelim) + // Ideally, endURIIdx should never be -1 here, as startURIIdx should have handled it already + if endURIIdx == -1 { + return + } + + // For Example: GET /user/register?ahrefp' or ' HTTP/1.1 + + // method -> GET + method = request[:startURIIdx] + + // uri -> /user/register?ahrefp' or ' + uri = request[startURIIdx+1 : endURIIdx] + + // protocol -> HTTP/1.1 + protocol = request[endURIIdx+1:] + return +} + func getRequestLengthMetricValue(requestLengths []float64) float64 { value := 0.0 diff --git a/src/core/metrics/sources/nginx_access_log_test.go b/src/core/metrics/sources/nginx_access_log_test.go index 5f650a500..0b46f7e8e 100644 --- a/src/core/metrics/sources/nginx_access_log_test.go +++ b/src/core/metrics/sources/nginx_access_log_test.go @@ -74,7 +74,7 @@ func TestAccessLogStats(t *testing.T) { `$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"`, []string{ "127.0.0.1 - - [19/May/2022:09:30:39 +0000] \"GET /nginx_status HTTP/1.1\" 200 98 \"-\" \"Go-http-client/1.1\" \"-\"\n", - "127.0.0.1 - - [19/May/2022:09:30:39 +0000] \"GET /nginx_status HTTP/1.1\" 200 98 \"-\" \"Go-http-client/1.1\" \"-\"\n", + `127.0.0.1 - - [19/May/2022:09:30:39 +0000] "GET /user/register?ahref HTTP/1.1" 200 98 "-" "-" "-"`, }, make(chan *proto.StatsEntity, 1), &proto.StatsEntity{ diff --git a/src/extensions/nginx-app-protect/monitoring/processor/nap.go b/src/extensions/nginx-app-protect/monitoring/processor/nap.go index ea34ce712..4ee606406 100644 --- a/src/extensions/nginx-app-protect/monitoring/processor/nap.go +++ b/src/extensions/nginx-app-protect/monitoring/processor/nap.go @@ -81,7 +81,6 @@ var ( subViolations, supportID, threatCampaignNames, - httpURI, violationRating, httpHostname, xForwardedForHeaderVal, @@ -97,6 +96,7 @@ var ( clientApplication, clientApplicationVersion, transportProtocol, + httpURI, } ) diff --git a/src/extensions/nginx-app-protect/monitoring/processor/testdata/expanded_nap_waf.log.txt b/src/extensions/nginx-app-protect/monitoring/processor/testdata/expanded_nap_waf.log.txt index d2d9b3a78..3580c2d44 100644 --- a/src/extensions/nginx-app-protect/monitoring/processor/testdata/expanded_nap_waf.log.txt +++ b/src/extensions/nginx-app-protect/monitoring/processor/testdata/expanded_nap_waf.log.txt @@ -1 +1 @@ -N/A,80,127.0.0.1,,GET,app_protect_default_policy,HTTP,blocked,0,Critical,::,{Cross Site Scripting Signatures;High Accuracy Signatures}::{Cross Site Scripting Signatures;High Accuracy Signatures},61478,HTTP protocol compliance failed:Host header contains IP address,4355056874564592513,N/A,/,5,1-localhost:1-/,N/A,REJECTED,SECURITY_WAF_VIOLATION,HTTP protocol compliance failed::Illegal meta character in value::Attack signature detected::Violation Rating Threat detected::Bot Client Detected,410000000200c00-3a03030c30000072-8000000000000000-0477f0ffcbbd0fea-befbf35cb000007e-8000000000000000-00-20-0-00-0-0-042VIOL_ATTACK_SIGNATUREparameterglobalYQ==alpha-numericPHNjcmlwdD4=query*002000014753YT08c2NyaXB0Pg==372000000983YT08c2NyaXB0Pg==2714VIOL_HTTP_PROTOCOL20482048SG9zdCBoZWFkZXIgd2l0aCBJUCB2YWx1ZTogMTAuMTQ2LjE3OS4xMTk=24VIOL_PARAMETER_VALUE_METACHARglobalYQ==alpha-numericPHNjcmlwdD4=query*046062,curl,HTTP Library,N/A,N/A,Untrusted Bot,N/A,N/A,GET /?a=