ddtrace 1.4.1 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +144 -1
- data/LICENSE-3rdparty.csv +1 -0
- data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +9 -2
- data/ext/ddtrace_profiling_loader/extconf.rb +17 -0
- data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +38 -2
- data/ext/ddtrace_profiling_native_extension/clock_id.h +1 -0
- data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +1 -0
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +517 -42
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +3 -0
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +208 -30
- data/ext/ddtrace_profiling_native_extension/collectors_stack.c +156 -46
- data/ext/ddtrace_profiling_native_extension/collectors_stack.h +11 -2
- data/ext/ddtrace_profiling_native_extension/extconf.rb +11 -1
- data/ext/ddtrace_profiling_native_extension/http_transport.c +83 -64
- data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +4 -4
- data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +3 -4
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +59 -0
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +3 -0
- data/ext/ddtrace_profiling_native_extension/profiling.c +10 -0
- data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +0 -1
- data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +4 -2
- data/ext/ddtrace_profiling_native_extension/stack_recorder.c +45 -29
- data/ext/ddtrace_profiling_native_extension/stack_recorder.h +7 -7
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +1169 -275
- data/lib/datadog/appsec/assets/waf_rules/risky.json +78 -78
- data/lib/datadog/appsec/assets/waf_rules/strict.json +278 -88
- data/lib/datadog/appsec/configuration/settings.rb +0 -2
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +25 -20
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/request.rb +3 -0
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +46 -19
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -6
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +11 -11
- data/lib/datadog/appsec/contrib/rails/request.rb +3 -0
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +14 -12
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +11 -11
- data/lib/datadog/appsec/event.rb +6 -10
- data/lib/datadog/appsec/instrumentation/gateway.rb +16 -2
- data/lib/datadog/appsec/processor.rb +18 -2
- data/lib/datadog/ci/ext/environment.rb +16 -4
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +0 -3
- data/lib/datadog/core/configuration/components.rb +28 -16
- data/lib/datadog/core/configuration/settings.rb +127 -8
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/core/diagnostics/environment_logger.rb +5 -1
- data/lib/datadog/core/header_collection.rb +41 -0
- data/lib/datadog/core/telemetry/collector.rb +0 -2
- data/lib/datadog/core/utils/compression.rb +5 -1
- data/lib/datadog/core/workers/async.rb +0 -2
- data/lib/datadog/core.rb +0 -54
- data/lib/datadog/opentracer/tracer.rb +4 -6
- data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +12 -2
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +5 -3
- data/lib/datadog/profiling/collectors/old_stack.rb +1 -1
- data/lib/datadog/profiling/exporter.rb +2 -4
- data/lib/datadog/profiling/http_transport.rb +1 -1
- data/lib/datadog/profiling.rb +1 -1
- data/lib/datadog/tracing/client_ip.rb +164 -0
- data/lib/datadog/tracing/configuration/ext.rb +14 -0
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +2 -0
- data/lib/datadog/tracing/contrib/aws/services.rb +0 -2
- data/lib/datadog/tracing/contrib/dalli/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +4 -0
- data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +2 -0
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +3 -0
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +2 -2
- data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +2 -0
- data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -0
- data/lib/datadog/tracing/contrib/ext.rb +25 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +3 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +0 -2
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +5 -0
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +7 -1
- data/lib/datadog/tracing/contrib/grpc/ext.rb +2 -0
- data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +47 -0
- data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +22 -0
- data/lib/datadog/tracing/contrib/hanami/ext.rb +24 -0
- data/lib/datadog/tracing/contrib/hanami/integration.rb +44 -0
- data/lib/datadog/tracing/contrib/hanami/patcher.rb +33 -0
- data/lib/datadog/tracing/contrib/hanami/plugin.rb +23 -0
- data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +41 -0
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +44 -0
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +2 -0
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +2 -0
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +2 -0
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +7 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +4 -0
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +12 -0
- data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +16 -0
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +12 -0
- data/lib/datadog/tracing/contrib/pg/ext.rb +2 -1
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +38 -21
- data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +43 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +32 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +28 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +49 -0
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +35 -0
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +105 -43
- data/lib/datadog/tracing/contrib/redis/ext.rb +2 -0
- data/lib/datadog/tracing/contrib/redis/instrumentation.rb +4 -2
- data/lib/datadog/tracing/contrib/redis/integration.rb +2 -1
- data/lib/datadog/tracing/contrib/redis/patcher.rb +40 -0
- data/lib/datadog/tracing/contrib/redis/tags.rb +5 -0
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +2 -0
- data/lib/datadog/tracing/contrib/sinatra/env.rb +12 -23
- data/lib/datadog/tracing/contrib/sinatra/ext.rb +7 -3
- data/lib/datadog/tracing/contrib/sinatra/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/sinatra/tracer.rb +8 -80
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +14 -9
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +92 -10
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +84 -0
- data/lib/datadog/tracing/distributed/headers/datadog.rb +122 -30
- data/lib/datadog/tracing/distributed/headers/ext.rb +2 -0
- data/lib/datadog/tracing/flush.rb +57 -35
- data/lib/datadog/tracing/metadata/ext.rb +11 -9
- data/lib/datadog/tracing/metadata/tagging.rb +9 -0
- data/lib/datadog/tracing/propagation/http.rb +9 -1
- data/lib/datadog/tracing/sampling/ext.rb +31 -0
- data/lib/datadog/tracing/sampling/priority_sampler.rb +46 -4
- data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +8 -9
- data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +29 -5
- data/lib/datadog/tracing/sampling/rate_limiter.rb +3 -0
- data/lib/datadog/tracing/sampling/rate_sampler.rb +20 -3
- data/lib/datadog/tracing/sampling/rule_sampler.rb +4 -3
- data/lib/datadog/tracing/sampling/span/ext.rb +25 -0
- data/lib/datadog/tracing/sampling/span/matcher.rb +9 -0
- data/lib/datadog/tracing/sampling/span/rule.rb +82 -0
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +104 -0
- data/lib/datadog/tracing/sampling/span/sampler.rb +75 -0
- data/lib/datadog/tracing/span_operation.rb +0 -2
- data/lib/datadog/tracing/trace_digest.rb +3 -0
- data/lib/datadog/tracing/trace_operation.rb +32 -3
- data/lib/datadog/tracing/trace_segment.rb +7 -2
- data/lib/datadog/tracing/tracer.rb +34 -6
- data/lib/datadog/tracing/writer.rb +7 -0
- data/lib/ddtrace/transport/trace_formatter.rb +7 -0
- data/lib/ddtrace/transport/traces.rb +3 -1
- data/lib/ddtrace/version.rb +1 -1
- metadata +36 -18
- data/lib/datadog/profiling/old_ext.rb +0 -42
- data/lib/datadog/profiling/transport/http/api/endpoint.rb +0 -85
- data/lib/datadog/profiling/transport/http/api/instance.rb +0 -38
- data/lib/datadog/profiling/transport/http/api/spec.rb +0 -42
- data/lib/datadog/profiling/transport/http/api.rb +0 -45
- data/lib/datadog/profiling/transport/http/builder.rb +0 -30
- data/lib/datadog/profiling/transport/http/client.rb +0 -37
- data/lib/datadog/profiling/transport/http/response.rb +0 -21
- data/lib/datadog/profiling/transport/http.rb +0 -118
|
@@ -5,7 +5,6 @@ module Datadog
|
|
|
5
5
|
module Configuration
|
|
6
6
|
# Configuration settings, acting as an integration registry
|
|
7
7
|
# TODO: as with Configuration, this is a trivial implementation
|
|
8
|
-
# rubocop:disable Metrics/ClassLength
|
|
9
8
|
class Settings
|
|
10
9
|
class << self
|
|
11
10
|
def boolean
|
|
@@ -188,7 +187,6 @@ module Datadog
|
|
|
188
187
|
initialize
|
|
189
188
|
end
|
|
190
189
|
end
|
|
191
|
-
# rubocop:enable Metrics/ClassLength
|
|
192
190
|
end
|
|
193
191
|
end
|
|
194
192
|
end
|
|
@@ -13,12 +13,13 @@ module Datadog
|
|
|
13
13
|
module Rack
|
|
14
14
|
module Gateway
|
|
15
15
|
# Watcher for Rack gateway events
|
|
16
|
-
# rubocop:disable Metrics/ModuleLength
|
|
17
16
|
module Watcher
|
|
18
17
|
# rubocop:disable Metrics/AbcSize
|
|
19
18
|
# rubocop:disable Metrics/MethodLength
|
|
19
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
20
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
20
21
|
def self.watch
|
|
21
|
-
Instrumentation.gateway.watch('rack.request') do |stack, request|
|
|
22
|
+
Instrumentation.gateway.watch('rack.request', :appsec) do |stack, request|
|
|
22
23
|
block = false
|
|
23
24
|
event = nil
|
|
24
25
|
waf_context = request.env['datadog.waf.context']
|
|
@@ -27,23 +28,24 @@ module Datadog
|
|
|
27
28
|
trace = active_trace
|
|
28
29
|
span = active_span
|
|
29
30
|
|
|
30
|
-
Rack::Reactive::Request.subscribe(op, waf_context) do |
|
|
31
|
-
|
|
32
|
-
if record
|
|
31
|
+
Rack::Reactive::Request.subscribe(op, waf_context) do |result, _block|
|
|
32
|
+
if result.status == :match
|
|
33
33
|
# TODO: should this hash be an Event instance instead?
|
|
34
34
|
event = {
|
|
35
35
|
waf_result: result,
|
|
36
36
|
trace: trace,
|
|
37
37
|
span: span,
|
|
38
38
|
request: request,
|
|
39
|
-
|
|
39
|
+
actions: result.actions
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
span.set_tag('appsec.event', 'true') if span
|
|
43
|
+
|
|
42
44
|
waf_context.events << event
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
_result, block = Rack::Reactive::Request.publish(op, request)
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
next [nil, [[:block, event]]] if block
|
|
@@ -58,7 +60,7 @@ module Datadog
|
|
|
58
60
|
[ret, res]
|
|
59
61
|
end
|
|
60
62
|
|
|
61
|
-
Instrumentation.gateway.watch('rack.response') do |stack, response|
|
|
63
|
+
Instrumentation.gateway.watch('rack.response', :appsec) do |stack, response|
|
|
62
64
|
block = false
|
|
63
65
|
event = nil
|
|
64
66
|
waf_context = response.instance_eval { @waf_context }
|
|
@@ -67,23 +69,24 @@ module Datadog
|
|
|
67
69
|
trace = active_trace
|
|
68
70
|
span = active_span
|
|
69
71
|
|
|
70
|
-
Rack::Reactive::Response.subscribe(op, waf_context) do |
|
|
71
|
-
|
|
72
|
-
if record
|
|
72
|
+
Rack::Reactive::Response.subscribe(op, waf_context) do |result, _block|
|
|
73
|
+
if result.status == :match
|
|
73
74
|
# TODO: should this hash be an Event instance instead?
|
|
74
75
|
event = {
|
|
75
76
|
waf_result: result,
|
|
76
77
|
trace: trace,
|
|
77
78
|
span: span,
|
|
78
79
|
response: response,
|
|
79
|
-
|
|
80
|
+
actions: result.actions
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
span.set_tag('appsec.event', 'true') if span
|
|
84
|
+
|
|
82
85
|
waf_context.events << event
|
|
83
86
|
end
|
|
84
87
|
end
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
_result, block = Rack::Reactive::Response.publish(op, response)
|
|
87
90
|
end
|
|
88
91
|
|
|
89
92
|
next [nil, [[:block, event]]] if block
|
|
@@ -98,7 +101,7 @@ module Datadog
|
|
|
98
101
|
[ret, res]
|
|
99
102
|
end
|
|
100
103
|
|
|
101
|
-
Instrumentation.gateway.watch('rack.request.body') do |stack, request|
|
|
104
|
+
Instrumentation.gateway.watch('rack.request.body', :appsec) do |stack, request|
|
|
102
105
|
block = false
|
|
103
106
|
event = nil
|
|
104
107
|
waf_context = request.env['datadog.waf.context']
|
|
@@ -107,23 +110,24 @@ module Datadog
|
|
|
107
110
|
trace = active_trace
|
|
108
111
|
span = active_span
|
|
109
112
|
|
|
110
|
-
Rack::Reactive::RequestBody.subscribe(op, waf_context) do |
|
|
111
|
-
|
|
112
|
-
if record
|
|
113
|
+
Rack::Reactive::RequestBody.subscribe(op, waf_context) do |result, _block|
|
|
114
|
+
if result.status == :match
|
|
113
115
|
# TODO: should this hash be an Event instance instead?
|
|
114
116
|
event = {
|
|
115
117
|
waf_result: result,
|
|
116
118
|
trace: trace,
|
|
117
119
|
span: span,
|
|
118
120
|
request: request,
|
|
119
|
-
|
|
121
|
+
actions: result.actions
|
|
120
122
|
}
|
|
121
123
|
|
|
124
|
+
span.set_tag('appsec.event', 'true') if span
|
|
125
|
+
|
|
122
126
|
waf_context.events << event
|
|
123
127
|
end
|
|
124
128
|
end
|
|
125
129
|
|
|
126
|
-
|
|
130
|
+
_result, block = Rack::Reactive::RequestBody.publish(op, request)
|
|
127
131
|
end
|
|
128
132
|
|
|
129
133
|
next [nil, [[:block, event]]] if block
|
|
@@ -138,6 +142,8 @@ module Datadog
|
|
|
138
142
|
[ret, res]
|
|
139
143
|
end
|
|
140
144
|
end
|
|
145
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
146
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
141
147
|
# rubocop:enable Metrics/MethodLength
|
|
142
148
|
# rubocop:enable Metrics/AbcSize
|
|
143
149
|
|
|
@@ -161,7 +167,6 @@ module Datadog
|
|
|
161
167
|
end
|
|
162
168
|
end
|
|
163
169
|
end
|
|
164
|
-
# rubocop:enable Metrics/ModuleLength
|
|
165
170
|
end
|
|
166
171
|
end
|
|
167
172
|
end
|
|
@@ -54,27 +54,27 @@ module Datadog
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
waf_timeout = Datadog::AppSec.settings.waf_timeout
|
|
57
|
-
|
|
57
|
+
result = waf_context.run(waf_args, waf_timeout)
|
|
58
58
|
|
|
59
59
|
Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
when :monitor
|
|
61
|
+
case result.status
|
|
62
|
+
when :match
|
|
64
63
|
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
yield [
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
|
|
65
|
+
block = result.actions.include?('block')
|
|
66
|
+
|
|
67
|
+
yield [result, block]
|
|
68
|
+
|
|
69
|
+
throw(:block, [result, true]) if block
|
|
70
|
+
when :ok
|
|
71
71
|
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
|
72
72
|
when :invalid_call
|
|
73
73
|
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
|
74
74
|
when :invalid_rule, :invalid_flow, :no_rule
|
|
75
75
|
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
|
76
76
|
else
|
|
77
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{
|
|
77
|
+
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
end
|
|
@@ -32,27 +32,27 @@ module Datadog
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
waf_timeout = Datadog::AppSec.settings.waf_timeout
|
|
35
|
-
|
|
35
|
+
result = waf_context.run(waf_args, waf_timeout)
|
|
36
36
|
|
|
37
37
|
Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
when :monitor
|
|
39
|
+
case result.status
|
|
40
|
+
when :match
|
|
42
41
|
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
yield [
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
|
|
43
|
+
block = result.actions.include?('block')
|
|
44
|
+
|
|
45
|
+
yield [result, block]
|
|
46
|
+
|
|
47
|
+
throw(:block, [result, true]) if block
|
|
48
|
+
when :ok
|
|
49
49
|
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
|
50
50
|
when :invalid_call
|
|
51
51
|
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
|
52
52
|
when :invalid_rule, :invalid_flow, :no_rule
|
|
53
53
|
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
|
54
54
|
else
|
|
55
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{
|
|
55
|
+
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -32,27 +32,27 @@ module Datadog
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
waf_timeout = Datadog::AppSec.settings.waf_timeout
|
|
35
|
-
|
|
35
|
+
result = waf_context.run(waf_args, waf_timeout)
|
|
36
36
|
|
|
37
37
|
Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
when :monitor
|
|
39
|
+
case result.status
|
|
40
|
+
when :match
|
|
42
41
|
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
yield [
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
|
|
43
|
+
block = result.actions.include?('block')
|
|
44
|
+
|
|
45
|
+
yield [result, block]
|
|
46
|
+
|
|
47
|
+
throw(:block, [result, true]) if block
|
|
48
|
+
when :ok
|
|
49
49
|
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
|
50
50
|
when :invalid_call
|
|
51
51
|
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
|
52
52
|
when :invalid_rule, :invalid_flow, :no_rule
|
|
53
53
|
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
|
54
54
|
else
|
|
55
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{
|
|
55
|
+
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -47,6 +47,9 @@ module Datadog
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def self.form_hash(request)
|
|
50
|
+
# force form data processing
|
|
51
|
+
request.POST if request.form_data?
|
|
52
|
+
|
|
50
53
|
# usually Hash<String,String> but can be a more complex
|
|
51
54
|
# Hash<String,String||Array||Hash> when e.g coming from JSON
|
|
52
55
|
request.env['rack.request.form_hash']
|
|
@@ -6,6 +6,9 @@ require_relative '../../instrumentation/gateway'
|
|
|
6
6
|
require_relative '../../processor'
|
|
7
7
|
require_relative '../../assets'
|
|
8
8
|
|
|
9
|
+
require_relative '../../../tracing/client_ip'
|
|
10
|
+
require_relative '../../../tracing/contrib/rack/header_collection'
|
|
11
|
+
|
|
9
12
|
module Datadog
|
|
10
13
|
module AppSec
|
|
11
14
|
module Contrib
|
|
@@ -21,7 +24,7 @@ module Datadog
|
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
def call(env)
|
|
24
|
-
return @app.call(env) unless @processor.ready?
|
|
27
|
+
return @app.call(env) unless Datadog.configuration.appsec.enabled && @processor.ready?
|
|
25
28
|
|
|
26
29
|
# TODO: handle exceptions, except for @app.call
|
|
27
30
|
|
|
@@ -30,7 +33,7 @@ module Datadog
|
|
|
30
33
|
env['datadog.waf.context'] = context
|
|
31
34
|
request = ::Rack::Request.new(env)
|
|
32
35
|
|
|
33
|
-
add_appsec_tags
|
|
36
|
+
add_appsec_tags(active_trace, active_span, env)
|
|
34
37
|
|
|
35
38
|
request_return, request_response = Instrumentation.gateway.push('rack.request', request) do
|
|
36
39
|
@app.call(env)
|
|
@@ -56,7 +59,8 @@ module Datadog
|
|
|
56
59
|
|
|
57
60
|
request_return
|
|
58
61
|
ensure
|
|
59
|
-
add_waf_runtime_tags(context) if context
|
|
62
|
+
add_waf_runtime_tags(active_trace, context) if context
|
|
63
|
+
context.finalize if context
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
private
|
|
@@ -69,41 +73,64 @@ module Datadog
|
|
|
69
73
|
Datadog::Tracing.active_trace
|
|
70
74
|
end
|
|
71
75
|
|
|
72
|
-
def
|
|
73
|
-
|
|
76
|
+
def active_span
|
|
77
|
+
# TODO: factor out tracing availability detection
|
|
78
|
+
|
|
79
|
+
return unless defined?(Datadog::Tracing)
|
|
80
|
+
|
|
81
|
+
Datadog::Tracing.active_span
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def add_appsec_tags(trace, span, env)
|
|
85
|
+
return unless trace
|
|
86
|
+
|
|
87
|
+
trace.set_tag('_dd.appsec.enabled', 1)
|
|
88
|
+
trace.set_tag('_dd.runtime_family', 'ruby')
|
|
89
|
+
trace.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING)
|
|
74
90
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
91
|
+
if span && span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
|
|
92
|
+
request_header_collection = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
|
|
93
|
+
|
|
94
|
+
# always collect client ip, as this is part of AppSec provided functionality
|
|
95
|
+
Datadog::Tracing::ClientIp.set_client_ip_tag!(
|
|
96
|
+
span,
|
|
97
|
+
headers: request_header_collection,
|
|
98
|
+
remote_ip: env['REMOTE_ADDR']
|
|
99
|
+
)
|
|
100
|
+
end
|
|
78
101
|
|
|
79
102
|
if @processor.ruleset_info
|
|
80
|
-
|
|
103
|
+
trace.set_tag('_dd.appsec.event_rules.version', @processor.ruleset_info[:version])
|
|
81
104
|
|
|
82
105
|
unless @oneshot_tags_sent
|
|
83
106
|
# Small race condition, but it's inoccuous: worst case the tags
|
|
84
107
|
# are sent a couple of times more than expected
|
|
85
108
|
@oneshot_tags_sent = true
|
|
86
109
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
110
|
+
trace.set_tag('_dd.appsec.event_rules.loaded', @processor.ruleset_info[:loaded].to_f)
|
|
111
|
+
trace.set_tag('_dd.appsec.event_rules.error_count', @processor.ruleset_info[:failed].to_f)
|
|
112
|
+
trace.set_tag('_dd.appsec.event_rules.errors', JSON.dump(@processor.ruleset_info[:errors]))
|
|
113
|
+
trace.set_tag('_dd.appsec.event_rules.addresses', JSON.dump(@processor.addresses))
|
|
91
114
|
|
|
92
115
|
# Ensure these tags reach the backend
|
|
93
|
-
|
|
116
|
+
trace.keep!
|
|
117
|
+
trace.set_tag(
|
|
118
|
+
Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
|
|
119
|
+
Datadog::Tracing::Sampling::Ext::Decision::ASM
|
|
120
|
+
)
|
|
94
121
|
end
|
|
95
122
|
end
|
|
96
123
|
end
|
|
97
124
|
|
|
98
|
-
def add_waf_runtime_tags(context)
|
|
99
|
-
return unless
|
|
125
|
+
def add_waf_runtime_tags(trace, context)
|
|
126
|
+
return unless trace
|
|
100
127
|
return unless context
|
|
101
128
|
|
|
102
|
-
|
|
129
|
+
trace.set_tag('_dd.appsec.waf.timeouts', context.timeouts)
|
|
103
130
|
|
|
104
131
|
# these tags expect time in us
|
|
105
|
-
|
|
106
|
-
|
|
132
|
+
trace.set_tag('_dd.appsec.waf.duration', context.time_ns / 1000.0)
|
|
133
|
+
trace.set_tag('_dd.appsec.waf.duration_ext', context.time_ext_ns / 1000.0)
|
|
107
134
|
end
|
|
108
135
|
end
|
|
109
136
|
end
|
|
@@ -13,7 +13,7 @@ module Datadog
|
|
|
13
13
|
# Watcher for Rails gateway events
|
|
14
14
|
module Watcher
|
|
15
15
|
def self.watch
|
|
16
|
-
Instrumentation.gateway.watch('rails.request.action') do |stack, request|
|
|
16
|
+
Instrumentation.gateway.watch('rails.request.action', :appsec) do |stack, request|
|
|
17
17
|
block = false
|
|
18
18
|
event = nil
|
|
19
19
|
waf_context = request.env['datadog.waf.context']
|
|
@@ -22,23 +22,24 @@ module Datadog
|
|
|
22
22
|
trace = active_trace
|
|
23
23
|
span = active_span
|
|
24
24
|
|
|
25
|
-
Rails::Reactive::Action.subscribe(op, waf_context) do |
|
|
26
|
-
|
|
27
|
-
if record
|
|
25
|
+
Rails::Reactive::Action.subscribe(op, waf_context) do |result, _block|
|
|
26
|
+
if result.status == :match
|
|
28
27
|
# TODO: should this hash be an Event instance instead?
|
|
29
28
|
event = {
|
|
30
29
|
waf_result: result,
|
|
31
30
|
trace: trace,
|
|
32
31
|
span: span,
|
|
33
32
|
request: request,
|
|
34
|
-
|
|
33
|
+
actions: result.actions
|
|
35
34
|
}
|
|
36
35
|
|
|
36
|
+
span.set_tag('appsec.event', 'true') if span
|
|
37
|
+
|
|
37
38
|
waf_context.events << event
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
_result, block = Rails::Reactive::Action.publish(op, request)
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
next [nil, [[:block, event]]] if block
|
|
@@ -36,27 +36,27 @@ module Datadog
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
waf_timeout = Datadog::AppSec.settings.waf_timeout
|
|
39
|
-
|
|
39
|
+
result = waf_context.run(waf_args, waf_timeout)
|
|
40
40
|
|
|
41
41
|
Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
when :monitor
|
|
43
|
+
case result.status
|
|
44
|
+
when :match
|
|
46
45
|
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
yield [
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
|
|
47
|
+
block = result.actions.include?('block')
|
|
48
|
+
|
|
49
|
+
yield [result, block]
|
|
50
|
+
|
|
51
|
+
throw(:block, [result, true]) if block
|
|
52
|
+
when :ok
|
|
53
53
|
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
|
54
54
|
when :invalid_call
|
|
55
55
|
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
|
56
56
|
when :invalid_rule, :invalid_flow, :no_rule
|
|
57
57
|
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
|
58
58
|
else
|
|
59
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{
|
|
59
|
+
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|
|
@@ -7,6 +7,9 @@ module Datadog
|
|
|
7
7
|
# Normalized extration of data from ActionDispatch::Request
|
|
8
8
|
module Request
|
|
9
9
|
def self.parsed_body(request)
|
|
10
|
+
# force body parameter parsing, which is done lazily by Rails
|
|
11
|
+
request.parameters
|
|
12
|
+
|
|
10
13
|
# usually Hash<String,String> but can be a more complex
|
|
11
14
|
# Hash<String,String||Array||Hash> when e.g coming from JSON or
|
|
12
15
|
# with Rails advanced param square bracket parsing
|
|
@@ -15,7 +15,7 @@ module Datadog
|
|
|
15
15
|
module Watcher
|
|
16
16
|
# rubocop:disable Metrics/MethodLength
|
|
17
17
|
def self.watch
|
|
18
|
-
Instrumentation.gateway.watch('sinatra.request.dispatch') do |stack, request|
|
|
18
|
+
Instrumentation.gateway.watch('sinatra.request.dispatch', :appsec) do |stack, request|
|
|
19
19
|
block = false
|
|
20
20
|
event = nil
|
|
21
21
|
waf_context = request.env['datadog.waf.context']
|
|
@@ -24,23 +24,24 @@ module Datadog
|
|
|
24
24
|
trace = active_trace
|
|
25
25
|
span = active_span
|
|
26
26
|
|
|
27
|
-
Rack::Reactive::RequestBody.subscribe(op, waf_context) do |
|
|
28
|
-
|
|
29
|
-
if record
|
|
27
|
+
Rack::Reactive::RequestBody.subscribe(op, waf_context) do |result, _block|
|
|
28
|
+
if result.status == :match
|
|
30
29
|
# TODO: should this hash be an Event instance instead?
|
|
31
30
|
event = {
|
|
32
31
|
waf_result: result,
|
|
33
32
|
trace: trace,
|
|
34
33
|
span: span,
|
|
35
34
|
request: request,
|
|
36
|
-
|
|
35
|
+
actions: result.actions
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
span.set_tag('appsec.event', 'true') if span
|
|
39
|
+
|
|
39
40
|
waf_context.events << event
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
_result, block = Rack::Reactive::RequestBody.publish(op, request)
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
next [nil, [[:block, event]]] if block
|
|
@@ -55,7 +56,7 @@ module Datadog
|
|
|
55
56
|
[ret, res]
|
|
56
57
|
end
|
|
57
58
|
|
|
58
|
-
Instrumentation.gateway.watch('sinatra.request.routed') do |stack, (request, route_params)|
|
|
59
|
+
Instrumentation.gateway.watch('sinatra.request.routed', :appsec) do |stack, (request, route_params)|
|
|
59
60
|
block = false
|
|
60
61
|
event = nil
|
|
61
62
|
waf_context = request.env['datadog.waf.context']
|
|
@@ -64,23 +65,24 @@ module Datadog
|
|
|
64
65
|
trace = active_trace
|
|
65
66
|
span = active_span
|
|
66
67
|
|
|
67
|
-
Sinatra::Reactive::Routed.subscribe(op, waf_context) do |
|
|
68
|
-
|
|
69
|
-
if record
|
|
68
|
+
Sinatra::Reactive::Routed.subscribe(op, waf_context) do |result, _block|
|
|
69
|
+
if result.status == :match
|
|
70
70
|
# TODO: should this hash be an Event instance instead?
|
|
71
71
|
event = {
|
|
72
72
|
waf_result: result,
|
|
73
73
|
trace: trace,
|
|
74
74
|
span: span,
|
|
75
75
|
request: request,
|
|
76
|
-
|
|
76
|
+
actions: result.actions
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
span.set_tag('appsec.event', 'true') if span
|
|
80
|
+
|
|
79
81
|
waf_context.events << event
|
|
80
82
|
end
|
|
81
83
|
end
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
_result, block = Sinatra::Reactive::Routed.publish(op, [request, route_params])
|
|
84
86
|
end
|
|
85
87
|
|
|
86
88
|
next [nil, [[:block, event]]] if block
|
|
@@ -31,27 +31,27 @@ module Datadog
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
waf_timeout = Datadog::AppSec.settings.waf_timeout
|
|
34
|
-
|
|
34
|
+
result = waf_context.run(waf_args, waf_timeout)
|
|
35
35
|
|
|
36
36
|
Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
when :monitor
|
|
38
|
+
case result.status
|
|
39
|
+
when :match
|
|
41
40
|
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
yield [
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
|
|
42
|
+
block = result.actions.include?('block')
|
|
43
|
+
|
|
44
|
+
yield [result, block]
|
|
45
|
+
|
|
46
|
+
throw(:block, [result, true]) if block
|
|
47
|
+
when :ok
|
|
48
48
|
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
|
49
49
|
when :invalid_call
|
|
50
50
|
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
|
51
51
|
when :invalid_rule, :invalid_flow, :no_rule
|
|
52
52
|
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
|
53
53
|
else
|
|
54
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{
|
|
54
|
+
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
end
|