ddtrace 1.6.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -2
  3. data/README.md +2 -2
  4. data/ext/ddtrace_profiling_loader/extconf.rb +5 -2
  5. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +1 -1
  6. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +3 -2
  7. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +81 -47
  8. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +1 -1
  9. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +332 -125
  10. data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.c +142 -0
  11. data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.h +14 -0
  12. data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.c +241 -0
  13. data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.h +3 -0
  14. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +11 -13
  15. data/ext/ddtrace_profiling_native_extension/extconf.rb +22 -8
  16. data/ext/ddtrace_profiling_native_extension/helpers.h +5 -0
  17. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +8 -0
  18. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +111 -26
  19. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +9 -0
  20. data/ext/ddtrace_profiling_native_extension/profiling.c +205 -0
  21. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +86 -0
  22. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +28 -6
  23. data/ext/ddtrace_profiling_native_extension/setup_signal_handler.c +115 -0
  24. data/ext/ddtrace_profiling_native_extension/setup_signal_handler.h +11 -0
  25. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +84 -35
  26. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +1 -0
  27. data/ext/ddtrace_profiling_native_extension/time_helpers.c +17 -0
  28. data/ext/ddtrace_profiling_native_extension/time_helpers.h +10 -0
  29. data/lib/datadog/appsec/assets/blocked.html +98 -3
  30. data/lib/datadog/appsec/assets/blocked.json +1 -0
  31. data/lib/datadog/appsec/assets/blocked.text +5 -0
  32. data/lib/datadog/appsec/assets/waf_rules/recommended.json +35 -46
  33. data/lib/datadog/appsec/assets/waf_rules/risky.json +1 -1
  34. data/lib/datadog/appsec/assets/waf_rules/strict.json +46 -1
  35. data/lib/datadog/appsec/assets.rb +2 -2
  36. data/lib/datadog/appsec/configuration/settings.rb +6 -0
  37. data/lib/datadog/appsec/configuration.rb +4 -0
  38. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +4 -8
  39. data/lib/datadog/appsec/contrib/rack/request.rb +17 -0
  40. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +2 -2
  41. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +2 -2
  42. data/lib/datadog/appsec/contrib/rails/patcher.rb +3 -6
  43. data/lib/datadog/appsec/contrib/sinatra/ext.rb +1 -0
  44. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +1 -1
  45. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +11 -8
  46. data/lib/datadog/appsec/extensions.rb +10 -0
  47. data/lib/datadog/appsec/processor.rb +18 -0
  48. data/lib/datadog/appsec/response.rb +54 -0
  49. data/lib/datadog/core/configuration/components.rb +27 -6
  50. data/lib/datadog/core/configuration/ext.rb +18 -0
  51. data/lib/datadog/core/configuration/settings.rb +14 -341
  52. data/lib/datadog/core/diagnostics/health.rb +4 -22
  53. data/lib/datadog/core/environment/variable_helpers.rb +58 -10
  54. data/lib/datadog/core/runtime/ext.rb +1 -1
  55. data/lib/datadog/core/utils.rb +0 -21
  56. data/lib/datadog/core.rb +21 -1
  57. data/lib/datadog/opentracer/distributed_headers.rb +7 -9
  58. data/lib/datadog/opentracer/rack_propagator.rb +0 -3
  59. data/lib/datadog/opentracer/text_map_propagator.rb +5 -7
  60. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +10 -4
  61. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +20 -5
  62. data/lib/datadog/profiling/collectors/dynamic_sampling_rate.rb +14 -0
  63. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +68 -0
  64. data/lib/datadog/profiling/collectors/old_stack.rb +7 -0
  65. data/lib/datadog/profiling/exporter.rb +5 -0
  66. data/lib/datadog/profiling/old_recorder.rb +8 -0
  67. data/lib/datadog/profiling/profiler.rb +7 -0
  68. data/lib/datadog/profiling/scheduler.rb +4 -7
  69. data/lib/datadog/profiling/stack_recorder.rb +36 -0
  70. data/lib/datadog/profiling/tasks/setup.rb +0 -7
  71. data/lib/datadog/profiling.rb +2 -0
  72. data/lib/datadog/tracing/configuration/ext.rb +33 -3
  73. data/lib/datadog/tracing/configuration/settings.rb +433 -0
  74. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +4 -1
  75. data/lib/datadog/tracing/contrib/aws/ext.rb +1 -0
  76. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +4 -1
  77. data/lib/datadog/tracing/contrib/dalli/ext.rb +1 -0
  78. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +4 -0
  79. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +5 -1
  80. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +1 -0
  81. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +6 -1
  82. data/lib/datadog/tracing/contrib/ethon/ext.rb +1 -0
  83. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +5 -1
  84. data/lib/datadog/tracing/contrib/excon/ext.rb +1 -0
  85. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +5 -1
  86. data/lib/datadog/tracing/contrib/faraday/ext.rb +1 -0
  87. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +6 -1
  88. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -1
  89. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +6 -12
  90. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +27 -0
  91. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +43 -0
  92. data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
  93. data/lib/datadog/tracing/contrib/grpc/patcher.rb +0 -2
  94. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +6 -1
  95. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +32 -0
  96. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +38 -0
  97. data/lib/datadog/tracing/contrib/http/ext.rb +1 -0
  98. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +6 -1
  99. data/lib/datadog/tracing/contrib/httpclient/ext.rb +1 -0
  100. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +6 -1
  101. data/lib/datadog/tracing/contrib/httprb/ext.rb +1 -0
  102. data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -0
  103. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +1 -0
  104. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +1 -0
  105. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +5 -1
  106. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  107. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
  108. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +4 -1
  109. data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -0
  110. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +2 -2
  111. data/lib/datadog/tracing/contrib/patcher.rb +3 -2
  112. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +4 -1
  113. data/lib/datadog/tracing/contrib/pg/ext.rb +1 -0
  114. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +12 -2
  115. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +4 -1
  116. data/lib/datadog/tracing/contrib/presto/ext.rb +1 -0
  117. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +1 -0
  118. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +10 -12
  119. data/lib/datadog/tracing/contrib/que/tracer.rb +2 -0
  120. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +4 -1
  121. data/lib/datadog/tracing/contrib/racecar/events/message.rb +4 -1
  122. data/lib/datadog/tracing/contrib/rack/middlewares.rb +2 -0
  123. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +4 -1
  124. data/lib/datadog/tracing/contrib/redis/ext.rb +1 -0
  125. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +30 -21
  126. data/lib/datadog/tracing/contrib/redis/integration.rb +34 -2
  127. data/lib/datadog/tracing/contrib/redis/patcher.rb +18 -14
  128. data/lib/datadog/tracing/contrib/redis/quantize.rb +12 -9
  129. data/lib/datadog/tracing/contrib/redis/tags.rb +4 -6
  130. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +72 -0
  131. data/lib/datadog/tracing/contrib/resque/resque_job.rb +2 -0
  132. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +6 -1
  133. data/lib/datadog/tracing/contrib/rest_client/ext.rb +1 -0
  134. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +2 -0
  135. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +5 -0
  136. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -0
  137. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +2 -0
  138. data/lib/datadog/{core → tracing}/diagnostics/ext.rb +1 -6
  139. data/lib/datadog/tracing/diagnostics/health.rb +40 -0
  140. data/lib/datadog/tracing/distributed/b3_multi.rb +66 -0
  141. data/lib/datadog/tracing/distributed/b3_single.rb +66 -0
  142. data/lib/datadog/tracing/distributed/datadog.rb +153 -0
  143. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -0
  144. data/lib/datadog/tracing/distributed/fetcher.rb +30 -0
  145. data/lib/datadog/tracing/distributed/headers/ext.rb +18 -16
  146. data/lib/datadog/tracing/distributed/helpers.rb +9 -7
  147. data/lib/datadog/tracing/distributed/none.rb +19 -0
  148. data/lib/datadog/tracing/distributed/propagation.rb +127 -0
  149. data/lib/datadog/tracing/distributed/trace_context.rb +369 -0
  150. data/lib/datadog/tracing/metadata/ext.rb +1 -1
  151. data/lib/datadog/tracing/propagation/http.rb +3 -106
  152. data/lib/datadog/tracing/sampling/priority_sampler.rb +11 -0
  153. data/lib/datadog/tracing/sampling/rate_sampler.rb +3 -3
  154. data/lib/datadog/tracing/span.rb +3 -19
  155. data/lib/datadog/tracing/span_operation.rb +5 -4
  156. data/lib/datadog/tracing/trace_digest.rb +75 -2
  157. data/lib/datadog/tracing/trace_operation.rb +5 -4
  158. data/lib/datadog/tracing/trace_segment.rb +1 -1
  159. data/lib/datadog/tracing/utils.rb +50 -0
  160. data/lib/ddtrace/transport/trace_formatter.rb +2 -5
  161. data/lib/ddtrace/version.rb +2 -2
  162. metadata +35 -15
  163. data/lib/datadog/tracing/distributed/headers/b3.rb +0 -55
  164. data/lib/datadog/tracing/distributed/headers/b3_single.rb +0 -67
  165. data/lib/datadog/tracing/distributed/headers/datadog.rb +0 -144
  166. data/lib/datadog/tracing/distributed/headers/parser.rb +0 -37
  167. data/lib/datadog/tracing/distributed/metadata/b3.rb +0 -55
  168. data/lib/datadog/tracing/distributed/metadata/b3_single.rb +0 -66
  169. data/lib/datadog/tracing/distributed/metadata/datadog.rb +0 -73
  170. data/lib/datadog/tracing/distributed/metadata/parser.rb +0 -34
  171. data/lib/datadog/tracing/propagation/grpc.rb +0 -98
@@ -0,0 +1 @@
1
+ {"errors": [{"title": "You've been blocked", "detail": "Sorry, you cannot access this page. Please contact the customer service team. Security provided by Datadog."}]}
@@ -0,0 +1,5 @@
1
+ You've been blocked
2
+
3
+ Sorry, you cannot access this page. Please contact the customer service team.
4
+
5
+ Security provided by Datadog.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.4.1"
4
+ "rules_version": "1.4.2"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -2853,51 +2853,6 @@
2853
2853
  ],
2854
2854
  "transformers": []
2855
2855
  },
2856
- {
2857
- "id": "crs-941-100",
2858
- "name": "XSS Attack Detected via libinjection",
2859
- "tags": {
2860
- "type": "xss",
2861
- "crs_id": "941100",
2862
- "category": "attack_attempt"
2863
- },
2864
- "conditions": [
2865
- {
2866
- "parameters": {
2867
- "inputs": [
2868
- {
2869
- "address": "server.request.headers.no_cookies",
2870
- "key_path": [
2871
- "user-agent"
2872
- ]
2873
- },
2874
- {
2875
- "address": "server.request.headers.no_cookies",
2876
- "key_path": [
2877
- "referer"
2878
- ]
2879
- },
2880
- {
2881
- "address": "server.request.query"
2882
- },
2883
- {
2884
- "address": "server.request.body"
2885
- },
2886
- {
2887
- "address": "server.request.path_params"
2888
- },
2889
- {
2890
- "address": "grpc.server.request.message"
2891
- }
2892
- ]
2893
- },
2894
- "operator": "is_xss"
2895
- }
2896
- ],
2897
- "transformers": [
2898
- "removeNulls"
2899
- ]
2900
- },
2901
2856
  {
2902
2857
  "id": "crs-941-110",
2903
2858
  "name": "XSS Filter - Category 1: Script Tag Vector",
@@ -4363,6 +4318,40 @@
4363
4318
  "keys_only"
4364
4319
  ]
4365
4320
  },
4321
+ {
4322
+ "id": "dog-000-007",
4323
+ "name": "Server side template injection: Velocity & Freemarker",
4324
+ "tags": {
4325
+ "type": "java_code_injection",
4326
+ "category": "attack_attempt"
4327
+ },
4328
+ "conditions": [
4329
+ {
4330
+ "parameters": {
4331
+ "inputs": [
4332
+ {
4333
+ "address": "server.request.query"
4334
+ },
4335
+ {
4336
+ "address": "server.request.body"
4337
+ },
4338
+ {
4339
+ "address": "server.request.path_params"
4340
+ },
4341
+ {
4342
+ "address": "server.request.headers.no_cookies"
4343
+ },
4344
+ {
4345
+ "address": "grpc.server.request.message"
4346
+ }
4347
+ ],
4348
+ "regex": "#(?:set|foreach|macro|parse|if)\\(.*\\)|<#assign.*>"
4349
+ },
4350
+ "operator": "match_regex"
4351
+ }
4352
+ ],
4353
+ "transformers": []
4354
+ },
4366
4355
  {
4367
4356
  "id": "nfd-000-001",
4368
4357
  "name": "Detect common directory discovery scans",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.4.1"
4
+ "rules_version": "1.4.2"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.4.1"
4
+ "rules_version": "1.4.2"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -855,6 +855,51 @@
855
855
  ],
856
856
  "transformers": []
857
857
  },
858
+ {
859
+ "id": "crs-941-100",
860
+ "name": "XSS Attack Detected via libinjection",
861
+ "tags": {
862
+ "type": "xss",
863
+ "crs_id": "941100",
864
+ "category": "attack_attempt"
865
+ },
866
+ "conditions": [
867
+ {
868
+ "parameters": {
869
+ "inputs": [
870
+ {
871
+ "address": "server.request.headers.no_cookies",
872
+ "key_path": [
873
+ "user-agent"
874
+ ]
875
+ },
876
+ {
877
+ "address": "server.request.headers.no_cookies",
878
+ "key_path": [
879
+ "referer"
880
+ ]
881
+ },
882
+ {
883
+ "address": "server.request.query"
884
+ },
885
+ {
886
+ "address": "server.request.body"
887
+ },
888
+ {
889
+ "address": "server.request.path_params"
890
+ },
891
+ {
892
+ "address": "grpc.server.request.message"
893
+ }
894
+ ]
895
+ },
896
+ "operator": "is_xss"
897
+ }
898
+ ],
899
+ "transformers": [
900
+ "removeNulls"
901
+ ]
902
+ },
858
903
  {
859
904
  "id": "crs-941-130",
860
905
  "name": "XSS Filter - Category 3: Attribute Vector",
@@ -12,8 +12,8 @@ module Datadog
12
12
  read("waf_rules/#{kind}.json")
13
13
  end
14
14
 
15
- def blocked
16
- @blocked ||= read('blocked.html')
15
+ def blocked(format: :html)
16
+ (@blocked ||= {})[format] ||= read("blocked.#{format}")
17
17
  end
18
18
 
19
19
  def path
@@ -128,6 +128,12 @@ module Datadog
128
128
  @options[:ruleset]
129
129
  end
130
130
 
131
+ # EXPERIMENTAL: This configurable is not meant to be publicly used, but
132
+ # is very useful for testing. It may change at any point in time.
133
+ def ip_denylist
134
+ @options[:ip_denylist]
135
+ end
136
+
131
137
  def waf_timeout
132
138
  @options[:waf_timeout]
133
139
  end
@@ -34,6 +34,10 @@ module Datadog
34
34
  options[:ruleset] = value
35
35
  end
36
36
 
37
+ def ip_denylist=(value)
38
+ options[:ip_denylist] = value
39
+ end
40
+
37
41
  # in microseconds
38
42
  def waf_timeout=(value)
39
43
  options[:waf_timeout] = value
@@ -15,9 +15,7 @@ module Datadog
15
15
  op.publish('request.headers', Rack::Request.headers(request))
16
16
  op.publish('request.uri.raw', Rack::Request.url(request))
17
17
  op.publish('request.cookies', Rack::Request.cookies(request))
18
- # op.publish('request.body.raw', Rack::Request.body(request))
19
- # TODO: op.publish('request.path_params', { k: v }) # route params only?
20
- # TODO: op.publish('request.path', request.script_name + request.path) # unused for now
18
+ op.publish('request.client_ip', Rack::Request.client_ip(request))
21
19
 
22
20
  nil
23
21
  end
@@ -30,8 +28,7 @@ module Datadog
30
28
  'request.uri.raw',
31
29
  'request.query',
32
30
  'request.cookies',
33
- # 'request.body.raw',
34
- # TODO: 'request.path_params',
31
+ 'request.client_ip',
35
32
  ]
36
33
 
37
34
  op.subscribe(*addresses) do |*values|
@@ -41,16 +38,15 @@ module Datadog
41
38
  uri_raw = values[1]
42
39
  query = values[2]
43
40
  cookies = values[3]
44
- # body = values[4]
41
+ client_ip = values[4]
45
42
 
46
43
  waf_args = {
47
44
  'server.request.cookies' => cookies,
48
- # 'server.request.body.raw' => body,
49
45
  'server.request.query' => query,
50
46
  'server.request.uri.raw' => uri_raw,
51
47
  'server.request.headers' => headers,
52
48
  'server.request.headers.no_cookies' => headers_no_cookies,
53
- # TODO: 'server.request.path_params' => path_params,
49
+ 'http.client_ip' => client_ip,
54
50
  }
55
51
 
56
52
  waf_timeout = Datadog::AppSec.settings.waf_timeout
@@ -1,5 +1,8 @@
1
1
  # typed: true
2
2
 
3
+ require_relative '../../../tracing/client_ip'
4
+ require_relative '../../../tracing/contrib/rack/header_collection'
5
+
3
6
  module Datadog
4
7
  module AppSec
5
8
  module Contrib
@@ -54,6 +57,20 @@ module Datadog
54
57
  # Hash<String,String||Array||Hash> when e.g coming from JSON
55
58
  request.env['rack.request.form_hash']
56
59
  end
60
+
61
+ def self.client_ip(request)
62
+ remote_ip = request.env['REMOTE_ADDR']
63
+ headers = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(request.env)
64
+
65
+ result = Datadog::Tracing::ClientIp.raw_ip_from_request(headers, remote_ip)
66
+
67
+ if result.raw_ip
68
+ ip = Datadog::Tracing::ClientIp.strip_decorations(result.raw_ip)
69
+ return unless Datadog::Tracing::ClientIp.valid_ip?(ip)
70
+
71
+ ip
72
+ end
73
+ end
57
74
  end
58
75
  end
59
76
  end
@@ -1,7 +1,7 @@
1
1
  # typed: ignore
2
2
 
3
3
  require_relative '../../instrumentation/gateway'
4
- require_relative '../../assets'
4
+ require_relative '../../response'
5
5
 
6
6
  module Datadog
7
7
  module AppSec
@@ -29,7 +29,7 @@ module Datadog
29
29
  end
30
30
 
31
31
  if request_response && request_response.any? { |action, _event| action == :block }
32
- request_return = [403, { 'Content-Type' => 'text/html' }, [Datadog::AppSec::Assets.blocked]]
32
+ request_return = AppSec::Response.negotiate(env).to_rack
33
33
  end
34
34
 
35
35
  request_return
@@ -4,7 +4,7 @@ require 'json'
4
4
 
5
5
  require_relative '../../instrumentation/gateway'
6
6
  require_relative '../../processor'
7
- require_relative '../../assets'
7
+ require_relative '../../response'
8
8
 
9
9
  require_relative '../../../tracing/client_ip'
10
10
  require_relative '../../../tracing/contrib/rack/header_collection'
@@ -40,7 +40,7 @@ module Datadog
40
40
  end
41
41
 
42
42
  if request_response && request_response.any? { |action, _event| action == :block }
43
- request_return = [403, { 'Content-Type' => 'text/html' }, [Datadog::AppSec::Assets.blocked]]
43
+ request_return = AppSec::Response.negotiate(env).to_rack
44
44
  end
45
45
 
46
46
  response = ::Rack::Response.new(request_return[2], request_return[0], request_return[1])
@@ -4,6 +4,7 @@ require_relative '../../../core/utils/only_once'
4
4
 
5
5
  require_relative '../patcher'
6
6
  require_relative 'framework'
7
+ require_relative '../../response'
7
8
  require_relative '../rack/request_middleware'
8
9
  require_relative '../rack/request_body_middleware'
9
10
  require_relative 'gateway/watcher'
@@ -83,11 +84,7 @@ module Datadog
83
84
  end
84
85
 
85
86
  if request_response && request_response.any? { |action, _event| action == :block }
86
- @_response = ::ActionDispatch::Response.new(
87
- 403,
88
- { 'Content-Type' => 'text/html' },
89
- [Datadog::AppSec::Assets.blocked]
90
- )
87
+ @_response = AppSec::Response.negotiate(env).to_action_dispatch_response
91
88
  request_return = @_response.body
92
89
  end
93
90
 
@@ -96,7 +93,7 @@ module Datadog
96
93
  end
97
94
 
98
95
  def patch_process_action
99
- ActionController::Instrumentation.prepend(ProcessActionPatch)
96
+ ::ActionController::Metal.prepend(ProcessActionPatch)
100
97
  end
101
98
 
102
99
  def include_middleware?(middleware, app)
@@ -8,6 +8,7 @@ module Datadog
8
8
  module Ext
9
9
  APP = 'sinatra'.freeze
10
10
  ENV_ENABLED = 'DD_TRACE_SINATRA_ENABLED'.freeze
11
+ ROUTE_INTERRUPT = :datadog_appsec_contrib_sinatra_route_interrupt
11
12
  end
12
13
  end
13
14
  end
@@ -11,7 +11,7 @@ module Datadog
11
11
  module Contrib
12
12
  module Sinatra
13
13
  module Gateway
14
- # Watcher for Rails gateway events
14
+ # Watcher for Sinatra gateway events
15
15
  module Watcher
16
16
  # rubocop:disable Metrics/MethodLength
17
17
  def self.watch
@@ -3,6 +3,7 @@
3
3
  require_relative '../../../tracing/contrib/rack/middlewares'
4
4
 
5
5
  require_relative '../patcher'
6
+ require_relative '../../response'
6
7
  require_relative '../rack/request_middleware'
7
8
  require_relative 'framework'
8
9
  require_relative 'gateway/watcher'
@@ -57,15 +58,12 @@ module Datadog
57
58
  # TODO: handle exceptions, except for super
58
59
 
59
60
  request_return, request_response = Instrumentation.gateway.push('sinatra.request.dispatch', request) do
60
- super
61
+ # handle process_route interruption
62
+ catch(Ext::ROUTE_INTERRUPT) { super }
61
63
  end
62
64
 
63
65
  if request_response && request_response.any? { |action, _event| action == :block }
64
- self.response = ::Sinatra::Response.new(
65
- [Datadog::AppSec::Assets.blocked],
66
- 403,
67
- { 'Content-Type' => 'text/html' }
68
- )
66
+ self.response = AppSec::Response.negotiate(env).to_sinatra_response
69
67
  request_return = nil
70
68
  end
71
69
 
@@ -94,9 +92,14 @@ module Datadog
94
92
  # At this point params has both route params and normal params.
95
93
  route_params = params.each.with_object({}) { |(k, v), h| h[k] = v unless base_params.key?(k) }
96
94
 
97
- Instrumentation.gateway.push('sinatra.request.routed', [request, route_params])
95
+ _, request_response = Instrumentation.gateway.push('sinatra.request.routed', [request, route_params])
98
96
 
99
- # TODO: handle block
97
+ if request_response && request_response.any? { |action, _event| action == :block }
98
+ self.response = AppSec::Response.negotiate(env).to_sinatra_response
99
+
100
+ # interrupt request and return response to dispatch! for consistency
101
+ throw(Ext::ROUTE_INTERRUPT, response)
102
+ end
100
103
 
101
104
  yield(*args)
102
105
  end
@@ -53,6 +53,12 @@ module Datadog
53
53
  @settings.merge(dsl)
54
54
  end
55
55
 
56
+ def ip_denylist=(arg)
57
+ dsl = AppSec::Configuration::DSL.new
58
+ dsl.ip_denylist = arg
59
+ @settings.merge(dsl)
60
+ end
61
+
56
62
  def instrument(*args)
57
63
  dsl = AppSec::Configuration::DSL.new
58
64
  dsl.instrument(*args)
@@ -86,6 +92,10 @@ module Datadog
86
92
  @settings.ruleset
87
93
  end
88
94
 
95
+ def ruledata
96
+ @settings.ruledata
97
+ end
98
+
89
99
  def waf_timeout
90
100
  @settings.waf_timeout
91
101
  end
@@ -57,7 +57,11 @@ module Datadog
57
57
 
58
58
  unless load_libddwaf && load_ruleset && create_waf_handle
59
59
  Datadog.logger.warn { 'AppSec is disabled, see logged errors above' }
60
+
61
+ return
60
62
  end
63
+
64
+ update_ip_denylist
61
65
  end
62
66
 
63
67
  def ready?
@@ -76,6 +80,20 @@ module Datadog
76
80
  @handle.toggle_rules(map)
77
81
  end
78
82
 
83
+ def update_ip_denylist(denylist = Datadog::AppSec.settings.ip_denylist, id: 'blocked_ips')
84
+ denylist ||= []
85
+
86
+ ruledata_setting = [
87
+ {
88
+ 'id' => id,
89
+ 'type' => 'data_with_expiration',
90
+ 'data' => denylist.map { |ip| { 'value' => ip.to_s, 'expiration' => 2**63 } }
91
+ }
92
+ ]
93
+
94
+ update_rule_data(ruledata_setting)
95
+ end
96
+
79
97
  def finalize
80
98
  @handle.finalize
81
99
  end
@@ -0,0 +1,54 @@
1
+ # typed: false
2
+
3
+ require_relative 'assets'
4
+
5
+ module Datadog
6
+ module AppSec
7
+ # AppSec response
8
+ class Response
9
+ attr_reader :status, :headers, :body
10
+
11
+ def initialize(status:, headers: {}, body: [])
12
+ @status = status
13
+ @headers = headers
14
+ @body = body
15
+ end
16
+
17
+ def to_rack
18
+ [status, headers, body]
19
+ end
20
+
21
+ def to_sinatra_response
22
+ ::Sinatra::Response.new(body, status, headers)
23
+ end
24
+
25
+ def to_action_dispatch_response
26
+ ::ActionDispatch::Response.new(status, headers, body)
27
+ end
28
+
29
+ class << self
30
+ def negotiate(env)
31
+ Response.new(
32
+ status: 403,
33
+ headers: { 'Content-Type' => 'text/html' },
34
+ body: [Datadog::AppSec::Assets.blocked(format: format(env))]
35
+ )
36
+ end
37
+
38
+ private
39
+
40
+ def format(env)
41
+ format = env['HTTP_ACCEPT'] && env['HTTP_ACCEPT'].split(',').any? do |accept|
42
+ if accept.start_with?('text/html')
43
+ break :html
44
+ elsif accept.start_with?('application/json')
45
+ break :json
46
+ end
47
+ end
48
+
49
+ format || :text
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -248,6 +248,8 @@ module Datadog
248
248
  # NOTE: Please update the Initialization section of ProfilingDevelopment.md with any changes to this method
249
249
 
250
250
  if settings.profiling.advanced.force_enable_new_profiler
251
+ print_new_profiler_warnings
252
+
251
253
  recorder = Datadog::Profiling::StackRecorder.new
252
254
  collector = Datadog::Profiling::Collectors::CpuAndWallTimeWorker.new(
253
255
  recorder: recorder,
@@ -331,20 +333,39 @@ module Datadog
331
333
  end
332
334
 
333
335
  def should_enable_gc_profiling?(settings)
334
- return true if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3')
335
-
336
336
  # See comments on the setting definition for more context on why it exists.
337
337
  if settings.profiling.advanced.force_enable_gc_profiling
338
- Datadog.logger.debug(
339
- 'Profiling time/resources spent in Garbage Collection force enabled. Do not use Ractors in combination ' \
340
- 'with this option as profiles will be incomplete.'
341
- )
338
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3')
339
+ Datadog.logger.debug(
340
+ 'Profiling time/resources spent in Garbage Collection force enabled. Do not use Ractors in combination ' \
341
+ 'with this option as profiles will be incomplete.'
342
+ )
343
+ end
342
344
 
343
345
  true
344
346
  else
345
347
  false
346
348
  end
347
349
  end
350
+
351
+ def print_new_profiler_warnings
352
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
353
+ Datadog.logger.warn(
354
+ 'New Ruby profiler has been force-enabled. This feature is in beta state. We do not yet recommend ' \
355
+ 'running it in production environments. Please report any issues ' \
356
+ 'you run into to Datadog support or via <https://github.com/datadog/dd-trace-rb/issues/new>!'
357
+ )
358
+ else
359
+ # For more details on the issue, see the "BIG Issue" comment on `gvl_owner` function in
360
+ # `private_vm_api_access.c`.
361
+ Datadog.logger.warn(
362
+ 'New Ruby profiler has been force-enabled on a legacy Ruby version (< 2.6). This is not recommended in ' \
363
+ 'production environments, as due to limitations in Ruby APIs, we suspect it may lead to crashes in very ' \
364
+ 'rare situations. Please report any issues you run into to Datadog support or ' \
365
+ 'via <https://github.com/datadog/dd-trace-rb/issues/new>!'
366
+ )
367
+ end
368
+ end
348
369
  end
349
370
 
350
371
  attr_reader \
@@ -0,0 +1,18 @@
1
+ # typed: true
2
+
3
+ module Datadog
4
+ module Core
5
+ module Configuration
6
+ # Constants for configuration settings
7
+ # e.g. Env vars, default values, enums, etc...
8
+ module Ext
9
+ # @public_api
10
+ module Diagnostics
11
+ ENV_DEBUG_ENABLED = 'DD_TRACE_DEBUG'.freeze
12
+ ENV_HEALTH_METRICS_ENABLED = 'DD_HEALTH_METRICS_ENABLED'.freeze
13
+ ENV_STARTUP_LOGS_ENABLED = 'DD_TRACE_STARTUP_LOGS'.freeze
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end