ddtrace 1.6.1 → 1.8.0

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.
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