ddtrace 1.10.0 → 1.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d6ef41c3e2f14b483d24a4aca9955a2a4b0ddf850d25e5e19932e62299c3905
4
- data.tar.gz: de145f2e113f13e6d5d3360967e5fc3dc0273fb62c47dc6fae5d455e9c5f088c
3
+ metadata.gz: 005fcbaaa9553287f8652a9f437abd144c2ba2ca0f26c83f67de171646f5aae3
4
+ data.tar.gz: 032c0d3f09ea01779b17ba45a95086ab890b3869208c84b82b548b3cbd41a977
5
5
  SHA512:
6
- metadata.gz: a3d6558cd4d7bbc1d8c6cdcb0500dec28eb8d451b9a92086db9cb70fec0ebf6f183c5a0b2b31287c364f9f322b3c9ad303f12b9826c808723684bab713e79563
7
- data.tar.gz: 7ed0b3255a67e3d8016dc0a6a0769cbd95f960f6a6324ec79a27f16026e08dd3b3e9bb8e28d728797a72e6eca8b1ab73646ff815bae32a52358481c0501b864d
6
+ metadata.gz: bc868d2e56e5282771cbc7e9447f1fa7504212d31b5bc94db4db9e5f029a00b0a9f988bcab7111f1889eb1f203fffcd81b73700c69f433be4bdaa2045dbfba72
7
+ data.tar.gz: d2679f725e7991bfa2e34dc6de650e928a59aa02124239d340a396ea40f331ff0a4a2159067df5ade22c1c36daab8e7cbe25db3ddaf55b8c8cb14137e7b2d220
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.10.1] - 2023-03-10
6
+
7
+ ### Fixed
8
+
9
+ * CI: Update TeamCity environment variable support ([#2668][])
10
+ * Core: Fix spurious dependency on AppSec when loading CI with `require 'datadog/ci'` ([#2679][])
11
+ * Core: Allow multiple headers and multiple IPs per header for client IP ([#2665][])
12
+ * AppSec: prevent side-effect on AppSec login event tracking method arguments ([#2663][]) ([@coneill-enhance][])
13
+
5
14
  ## [1.10.0] - 2023-03-06
6
15
 
7
16
  ### Added
@@ -2314,7 +2323,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
2314
2323
 
2315
2324
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
2316
2325
 
2317
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.10.0...master
2326
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.10.1...master
2327
+ [1.10.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.10.0...v1.10.1
2318
2328
  [1.10.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.9.0...v1.10.0
2319
2329
  [1.9.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.8.0...v1.9.0
2320
2330
  [1.8.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.7.0...v1.8.0
@@ -3321,6 +3331,10 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3321
3331
  [#2657]: https://github.com/DataDog/dd-trace-rb/issues/2657
3322
3332
  [#2659]: https://github.com/DataDog/dd-trace-rb/issues/2659
3323
3333
  [#2662]: https://github.com/DataDog/dd-trace-rb/issues/2662
3334
+ [#2663]: https://github.com/DataDog/dd-trace-rb/issues/2663
3335
+ [#2665]: https://github.com/DataDog/dd-trace-rb/issues/2665
3336
+ [#2668]: https://github.com/DataDog/dd-trace-rb/issues/2668
3337
+ [#2679]: https://github.com/DataDog/dd-trace-rb/issues/2679
3324
3338
  [@AdrianLC]: https://github.com/AdrianLC
3325
3339
  [@Azure7111]: https://github.com/Azure7111
3326
3340
  [@BabyGroot]: https://github.com/BabyGroot
@@ -3365,6 +3379,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3365
3379
  [@cjford]: https://github.com/cjford
3366
3380
  [@ck3g]: https://github.com/ck3g
3367
3381
  [@components]: https://github.com/components
3382
+ [@coneill-enhance]: https://github.com/coneill-enhance
3368
3383
  [@cswatt]: https://github.com/cswatt
3369
3384
  [@cwoodcox]: https://github.com/cwoodcox
3370
3385
  [@danhodge]: https://github.com/danhodge
@@ -3466,4 +3481,4 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3466
3481
  [@y-yagi]: https://github.com/y-yagi
3467
3482
  [@yujideveloper]: https://github.com/yujideveloper
3468
3483
  [@yukimurasawa]: https://github.com/yukimurasawa
3469
- [@zachmccormick]: https://github.com/zachmccormick
3484
+ [@zachmccormick]: https://github.com/zachmccormick
data/LICENSE-3rdparty.csv CHANGED
@@ -5,3 +5,4 @@ lib/datadog/tracing/contrib/utils/quantization/http.rb,https://github.com/ruby/u
5
5
  ext/ddtrace_profiling_native_extension/private_vm_api_access,https://github.com/ruby/ruby,BSD-2-Clause,"Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved."
6
6
  msgpack,https://rubygems.org/gems/msgpack,Apache-2.0,"Copyright (c) 2008-2015 Sadayuki Furuhashi"
7
7
  debase-ruby_core_source,https://rubygems.org/gems/debase-ruby_core_source,MIT for gem and BSD-2-Clause for Ruby sources,"Copyright (c) 2012 Gabriel Horner. Files from Ruby sources are Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved."
8
+ lib/datadog/core/vendor/ipaddr,https://github.com/ruby/ipaddr/blob/master/lib/ipaddr.rb,BSD 2-Clause "Simplified" License,"Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org> Copyright (c) 2007-2017 Akinori MUSHA <knu@iDaemons.org>"
@@ -8,7 +8,7 @@ module Datadog
8
8
  class Component
9
9
  class << self
10
10
  def build_appsec_component(settings)
11
- return unless settings.enabled
11
+ return unless settings.respond_to?(:appsec) && settings.appsec.enabled
12
12
 
13
13
  processor = create_processor
14
14
  new(processor: processor)
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../../instrumentation/gateway/argument'
4
+ require_relative '../../../../core/header_collection'
4
5
  require_relative '../../../../tracing/client_ip'
5
- require_relative '../../../../tracing/contrib/rack/header_collection'
6
6
 
7
7
  module Datadog
8
8
  module AppSec
@@ -85,16 +85,9 @@ module Datadog
85
85
 
86
86
  def client_ip
87
87
  remote_ip = remote_addr
88
- headers = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
88
+ header_collection = Datadog::Core::HeaderCollection.from_hash(headers)
89
89
 
90
- result = Datadog::Tracing::ClientIp.raw_ip_from_request(headers, remote_ip)
91
-
92
- if result.raw_ip
93
- ip = Datadog::Tracing::ClientIp.strip_decorations(result.raw_ip)
94
- return unless Datadog::Tracing::ClientIp.valid_ip?(ip)
95
-
96
- ip
97
- end
90
+ Datadog::Tracing::ClientIp.extract_client_ip(header_collection, remote_ip)
98
91
  end
99
92
  end
100
93
  end
@@ -174,9 +174,6 @@ module Datadog
174
174
  TAG_PIPELINE_URL => url,
175
175
  TAG_PROVIDER_NAME => 'bitbucket',
176
176
  TAG_WORKSPACE_PATH => env['BITBUCKET_CLONE_DIR'],
177
- Core::Git::Ext::TAG_COMMIT_AUTHOR_NAME => env['BUILD_REQUESTEDFORID'],
178
- Core::Git::Ext::TAG_COMMIT_AUTHOR_EMAIL => env['BUILD_REQUESTEDFOREMAIL'],
179
- Core::Git::Ext::TAG_COMMIT_MESSAGE => env['BUILD_SOURCEVERSIONMESSAGE']
180
177
  }
181
178
  end
182
179
 
@@ -265,9 +262,6 @@ module Datadog
265
262
  TAG_PIPELINE_URL => pipeline_url,
266
263
  TAG_PROVIDER_NAME => 'github',
267
264
  TAG_WORKSPACE_PATH => env['GITHUB_WORKSPACE'],
268
- Core::Git::Ext::TAG_COMMIT_AUTHOR_NAME => env['BUILD_REQUESTEDFORID'],
269
- Core::Git::Ext::TAG_COMMIT_AUTHOR_EMAIL => env['BUILD_REQUESTEDFOREMAIL'],
270
- Core::Git::Ext::TAG_COMMIT_MESSAGE => env['BUILD_SOURCEVERSIONMESSAGE'],
271
265
  TAG_CI_ENV_VARS => {
272
266
  'GITHUB_SERVER_URL' => env['GITHUB_SERVER_URL'],
273
267
  'GITHUB_REPOSITORY' => env['GITHUB_REPOSITORY'],
@@ -325,9 +319,6 @@ module Datadog
325
319
  TAG_PIPELINE_URL => env['BUILD_URL'],
326
320
  TAG_PROVIDER_NAME => 'jenkins',
327
321
  TAG_WORKSPACE_PATH => env['WORKSPACE'],
328
- Core::Git::Ext::TAG_COMMIT_AUTHOR_NAME => env['BUILD_REQUESTEDFORID'],
329
- Core::Git::Ext::TAG_COMMIT_AUTHOR_EMAIL => env['BUILD_REQUESTEDFOREMAIL'],
330
- Core::Git::Ext::TAG_COMMIT_MESSAGE => env['BUILD_SOURCEVERSIONMESSAGE'],
331
322
  TAG_CI_ENV_VARS => {
332
323
  'DD_CUSTOM_TRACE_ID' => env['DD_CUSTOM_TRACE_ID']
333
324
  }.to_json
@@ -337,17 +328,8 @@ module Datadog
337
328
  def extract_teamcity(env)
338
329
  {
339
330
  TAG_PROVIDER_NAME => 'teamcity',
340
- Core::Git::Ext::TAG_REPOSITORY_URL => env['BUILD_VCS_URL'],
341
- Core::Git::Ext::TAG_COMMIT_SHA => env['BUILD_VCS_NUMBER'],
342
- TAG_WORKSPACE_PATH => env['BUILD_CHECKOUTDIR'],
343
- TAG_PIPELINE_ID => env['BUILD_ID'],
344
- TAG_PIPELINE_NUMBER => env['BUILD_NUMBER'],
345
- TAG_PIPELINE_URL => (
346
- env['SERVER_URL'] && env['BUILD_ID'] ? "#{env['SERVER_URL']}/viewLog.html?buildId=#{env['BUILD_ID']}" : nil
347
- ),
348
- Core::Git::Ext::TAG_COMMIT_AUTHOR_NAME => env['BUILD_REQUESTEDFORID'],
349
- Core::Git::Ext::TAG_COMMIT_AUTHOR_EMAIL => env['BUILD_REQUESTEDFOREMAIL'],
350
- Core::Git::Ext::TAG_COMMIT_MESSAGE => env['BUILD_SOURCEVERSIONMESSAGE']
331
+ TAG_JOB_NAME => env['TEAMCITY_BUILDCONF_NAME'],
332
+ TAG_JOB_URL => env['BUILD_URL'],
351
333
  }
352
334
  end
353
335
 
@@ -88,7 +88,7 @@ module Datadog
88
88
  @telemetry = self.class.build_telemetry(settings)
89
89
 
90
90
  # AppSec
91
- @appsec = Datadog::AppSec::Component.build_appsec_component(settings.appsec)
91
+ @appsec = Datadog::AppSec::Component.build_appsec_component(settings)
92
92
  end
93
93
 
94
94
  # Starts up components
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require_relative '../vendor/ipaddr'
5
+
6
+ module Datadog
7
+ module Core
8
+ module Utils
9
+ # Common Network utility functions.
10
+ module Network
11
+ DEFAULT_IP_HEADERS_NAMES = %w[
12
+ x-forwarded-for
13
+ x-real-ip
14
+ true-client-ip
15
+ x-client-ip
16
+ x-forwarded
17
+ forwarded-for
18
+ x-cluster-client-ip
19
+ fastly-client-ip
20
+ cf-connecting-ip
21
+ cf-connecting-ipv6
22
+ ].freeze
23
+
24
+ class << self
25
+ # Returns a client IP associated with the request if it was
26
+ # retrieved successfully.
27
+ #
28
+ #
29
+ # @param [Datadog::Core::HeaderCollection, #get, nil] headers The request headers
30
+ # @param [Array<String>] list of headers to check.
31
+ # @return [String] IP value without the port and the zone indentifier.
32
+ # @return [nil] when no valid IP value found.
33
+ def stripped_ip_from_request_headers(headers, ip_headers_to_check: DEFAULT_IP_HEADERS_NAMES)
34
+ ip = ip_header(headers, ip_headers_to_check)
35
+
36
+ ip ? ip.to_s : nil
37
+ end
38
+
39
+ # @param [String] IP value.
40
+ # @return [String] IP value without the port and the zone indentifier.
41
+ # @return [nil] when no valid IP value found.
42
+ def stripped_ip(ip)
43
+ ip = ip_to_ipaddr(ip)
44
+ ip ? ip.to_s : nil
45
+ end
46
+
47
+ private
48
+
49
+ # @param [String] IP value.
50
+ # @return [IPaddr]
51
+ # @return [nil] when no valid IP value found.
52
+ def ip_to_ipaddr(ip)
53
+ return unless ip
54
+
55
+ clean_ip = if likely_ipv4?(ip)
56
+ strip_ipv4_port(ip)
57
+ else
58
+ strip_zone_specifier(strip_ipv6_port(ip))
59
+ end
60
+
61
+ begin
62
+ IPAddr.new(clean_ip)
63
+ rescue IPAddr::Error
64
+ nil
65
+ end
66
+ end
67
+
68
+ def ip_header(headers, ip_headers_to_check)
69
+ return unless headers
70
+
71
+ ip_headers_to_check.each do |name|
72
+ value = headers.get(name)
73
+
74
+ next unless value
75
+
76
+ ips = value.split(',')
77
+ ips.each do |ip|
78
+ parsed_ip = ip_to_ipaddr(ip.strip)
79
+
80
+ return parsed_ip if global_ip?(parsed_ip)
81
+ end
82
+ end
83
+
84
+ nil
85
+ end
86
+
87
+ # Returns whether the given value is more likely to be an IPv4 than an IPv6 address.
88
+ #
89
+ # This is done by checking if a dot (`'.'`) character appears before a colon (`':'`) in the value.
90
+ # The rationale is that in valid IPv6 addresses, colons will always preced dots,
91
+ # and in valid IPv4 addresses dots will always preced colons.
92
+ def likely_ipv4?(value)
93
+ dot_index = value.index('.') || value.size
94
+ colon_index = value.index(':') || value.size
95
+
96
+ dot_index < colon_index
97
+ end
98
+
99
+ def strip_zone_specifier(ipv6)
100
+ ipv6.gsub(/%.*/, '')
101
+ end
102
+
103
+ def strip_ipv6_port(ip)
104
+ if /\[(.*)\](?::\d+)?/ =~ ip
105
+ Regexp.last_match(1)
106
+ else
107
+ ip
108
+ end
109
+ end
110
+
111
+ def strip_ipv4_port(ip)
112
+ ip.gsub(/:\d+\z/, '')
113
+ end
114
+
115
+ def global_ip?(parsed_ip)
116
+ parsed_ip && !private?(parsed_ip) && !loopback?(parsed_ip) && !link_local?(parsed_ip)
117
+ end
118
+
119
+ # TODO: remove once we drop support for ruby 2.1, 2.2, 2.3, 2.4
120
+ # replace with ip.private?
121
+ def private?(ip)
122
+ Datadog::Core::Vendor::IPAddr.private?(ip)
123
+ end
124
+
125
+ # TODO: remove once we drop support for ruby 2.1, 2.2, 2.3, 2.4
126
+ # replace with ip.link_local?
127
+ def link_local?(ip)
128
+ Datadog::Core::Vendor::IPAddr.link_local?(ip)
129
+ end
130
+
131
+ # TODO: remove once we drop support for ruby 2.1, 2.2, 2.3, 2.4
132
+ # replace with ip.loopback
133
+ def loopback?(ip)
134
+ Datadog::Core::Vendor::IPAddr.loopback?(ip)
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>
2
+ # Copyright (c) 2007-2017 Akinori MUSHA <knu@iDaemons.org>
3
+
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions
6
+ # are met:
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright
10
+ # notice, this list of conditions and the following disclaimer in the
11
+ # documentation and/or other materials provided with the distribution.
12
+
13
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
+ # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
+ # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
+ # SUCH DAMAGE.
24
+
25
+ module Datadog
26
+ module Core
27
+ module Vendor
28
+ # vendor code from https://github.com/ruby/ipaddr/blob/master/lib/ipaddr.rb
29
+ # Ruby version below 2.5 does not have the IpAddr#private? method
30
+ # We have to vendor the code because ruby versions below 2.5 did not extract ipaddr as a gem
31
+ # So we can not specify a specific version for ipaddr for ruby versions: 2.1, 2.2, 2.3, 2.4
32
+ module IPAddr
33
+ class << self
34
+ def private?(ip)
35
+ addr = ip.instance_variable_get(:@addr)
36
+
37
+ case ip.family
38
+ when Socket::AF_INET
39
+ addr & 0xff000000 == 0x0a000000 || # 10.0.0.0/8
40
+ addr & 0xfff00000 == 0xac100000 || # 172.16.0.0/12
41
+ addr & 0xffff0000 == 0xc0a80000 # 192.168.0.0/16
42
+ when Socket::AF_INET6
43
+ addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000
44
+ else
45
+ raise ::IPAddr::AddressFamilyError, 'unsupported address family'
46
+ end
47
+ end
48
+
49
+ def link_local?(ip)
50
+ addr = ip.instance_variable_get(:@addr)
51
+
52
+ case ip.family
53
+ when Socket::AF_INET
54
+ addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
55
+ when Socket::AF_INET6
56
+ addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000
57
+ else
58
+ raise ::IPAddr::AddressFamilyError, 'unsupported address family'
59
+ end
60
+ end
61
+
62
+ def loopback?(ip)
63
+ addr = ip.instance_variable_get(:@addr)
64
+
65
+ case ip.family
66
+ when Socket::AF_INET
67
+ addr & 0xff000000 == 0x7f000000
68
+ when Socket::AF_INET6
69
+ addr == 1
70
+ else
71
+ raise ::IPAddr::AddressFamilyError, 'unsupported address family'
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -23,7 +23,7 @@ module Datadog
23
23
  track(LOGIN_SUCCESS_EVENT, trace, **others)
24
24
 
25
25
  user_options = user.dup
26
- user_id = user.delete(:id)
26
+ user_id = user_options.delete(:id)
27
27
 
28
28
  raise ArgumentError, 'missing required key: :user => { :id }' if user_id.nil?
29
29
 
@@ -1,162 +1,61 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../core/configuration'
4
+ require_relative '../core/utils/network'
2
5
  require_relative 'metadata/ext'
3
6
  require_relative 'span'
4
7
 
5
- require 'ipaddr'
6
-
7
8
  module Datadog
8
9
  module Tracing
9
10
  # Common functions for supporting the `http.client_ip` span attribute.
10
11
  module ClientIp
11
- DEFAULT_IP_HEADERS_NAMES = %w[
12
- x-forwarded-for
13
- x-real-ip
14
- x-client-ip
15
- x-forwarded
16
- x-cluster-client-ip
17
- forwarded-for
18
- forwarded
19
- via
20
- true-client-ip
21
- ].freeze
22
-
23
- TAG_MULTIPLE_IP_HEADERS = '_dd.multiple-ip-headers'.freeze
24
-
25
- # Sets the `http.client_ip` tag on the given span.
26
- #
27
- # This function respects the user's settings: if they disable the client IP tagging,
28
- # or provide a different IP header name.
29
- #
30
- # If multiple IP headers are present in the request, this function will instead set
31
- # the `_dd.multiple-ip-headers` tag with the names of the present headers,
32
- # and **NOT** set the `http.client_ip` tag.
33
- #
34
- # @param [Span] span The span that's associated with the request.
35
- # @param [HeaderCollection, #get, nil] headers A collection with the request headers.
36
- # @param [String, nil] remote_ip The remote IP the request associated with the span is sent to.
37
- def self.set_client_ip_tag(span, headers: nil, remote_ip: nil)
38
- return unless configuration.enabled
39
-
40
- set_client_ip_tag!(span, headers: headers, remote_ip: remote_ip)
41
- end
42
-
43
- # Forcefully sets the `http.client_ip` tag on the given span.
44
- #
45
- # This function ignores the user's `enabled` setting.
46
- #
47
- # @param [Span] span The span that's associated with the request.
48
- # @param [HeaderCollection, #get, nil] headers A collection with the request headers.
49
- # @param [String, nil] remote_ip The remote IP the request associated with the span is sent to.
50
- def self.set_client_ip_tag!(span, headers: nil, remote_ip: nil)
51
- result = raw_ip_from_request(headers, remote_ip)
52
-
53
- if result.raw_ip
54
- ip = strip_decorations(result.raw_ip)
55
- return unless valid_ip?(ip)
56
-
57
- span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP, ip)
58
- elsif result.multiple_ip_headers
59
- span.set_tag(TAG_MULTIPLE_IP_HEADERS, result.multiple_ip_headers.keys.join(','))
12
+ class << self
13
+ # Sets the `http.client_ip` tag on the given span.
14
+ #
15
+ # This function respects the user's settings: if they disable the client IP tagging,
16
+ # or provide a different IP header name.
17
+ #
18
+ # @param [Span] span The span that's associated with the request.
19
+ # @param [HeaderCollection, #get, nil] headers A collection with the request headers.
20
+ # @param [String, nil] remote_ip The remote IP the request associated with the span is sent to.
21
+ def set_client_ip_tag(span, headers: nil, remote_ip: nil)
22
+ return unless configuration.enabled
23
+
24
+ set_client_ip_tag!(span, headers: headers, remote_ip: remote_ip)
60
25
  end
61
- end
62
-
63
- IpExtractionResult = Struct.new(:raw_ip, :multiple_ip_headers)
64
-
65
- # Returns a result struct that holds the raw client IP associated with the request if it was
66
- # retrieved successfully.
67
- #
68
- # The client IP is looked up by the following logic:
69
- # * If the user has configured a header name, return that header's value.
70
- # * If exactly one of the known IP headers is present, return that header's value.
71
- # * If none of the known IP headers are present, return the remote IP from the request.
72
- #
73
- # If more than one of the known IP headers is present, the result will have a `multiple_ip_headers`
74
- # field with the name of the present IP headers.
75
- #
76
- # @param [Datadog::Core::HeaderCollection, #get, nil] headers The request headers
77
- # @param [String] remote_ip The remote IP of the request.
78
- # @return [IpExtractionResult] A struct that holds the unprocessed IP value,
79
- # or `nil` if it wasn't found. Additionally, the `multiple_ip_headers` fields will hold the
80
- # name of known IP headers present in the request if more than one of these were found.
81
- def self.raw_ip_from_request(headers, remote_ip)
82
- return IpExtractionResult.new(headers && headers.get(configuration.header_name), nil) if configuration.header_name
83
26
 
84
- headers_present = ip_headers(headers)
85
-
86
- case headers_present.size
87
- when 0
88
- IpExtractionResult.new(remote_ip, nil)
89
- when 1
90
- IpExtractionResult.new(headers_present.values.first, nil)
91
- else
92
- IpExtractionResult.new(nil, headers_present)
27
+ # Forcefully sets the `http.client_ip` tag on the given span.
28
+ #
29
+ # This function ignores the user's `enabled` setting.
30
+ #
31
+ # @param [Span] span The span that's associated with the request.
32
+ # @param [HeaderCollection, #get, nil] headers A collection with the request headers.
33
+ # @param [String, nil] remote_ip The remote IP the request associated with the span is sent to.
34
+ def set_client_ip_tag!(span, headers: nil, remote_ip: nil)
35
+ ip = extract_client_ip(headers, remote_ip)
36
+
37
+ span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP, ip) if ip
93
38
  end
94
- end
95
39
 
96
- # Removes any port notations or zone specifiers from the IP address without
97
- # verifying its validity.
98
- def self.strip_decorations(address)
99
- return strip_ipv4_port(address) if likely_ipv4?(address)
40
+ def extract_client_ip(headers, remote_ip)
41
+ if headers && configuration.header_name
42
+ return Datadog::Core::Utils::Network.stripped_ip_from_request_headers(
43
+ headers,
44
+ ip_headers_to_check: Array(configuration.header_name)
45
+ )
46
+ end
100
47
 
101
- address = strip_ipv6_port(address)
102
-
103
- strip_zone_specifier(address)
104
- end
48
+ ip_from_headers = Datadog::Core::Utils::Network.stripped_ip_from_request_headers(headers) if headers
105
49
 
106
- def self.strip_zone_specifier(ipv6)
107
- ipv6.gsub(/%.*/, '')
108
- end
109
-
110
- def self.strip_ipv4_port(ip)
111
- ip.gsub(/:\d+\z/, '')
112
- end
113
-
114
- def self.strip_ipv6_port(ip)
115
- if /\[(.*)\](?::\d+)?/ =~ ip
116
- Regexp.last_match(1)
117
- else
118
- ip
50
+ ip_from_headers || Datadog::Core::Utils::Network.stripped_ip(remote_ip)
119
51
  end
120
- end
121
-
122
- # Returns whether the given value is more likely to be an IPv4 than an IPv6 address.
123
- #
124
- # This is done by checking if a dot (`'.'`) character appears before a colon (`':'`) in the value.
125
- # The rationale is that in valid IPv6 addresses, colons will always preced dots,
126
- # and in valid IPv4 addresses dots will always preced colons.
127
- def self.likely_ipv4?(value)
128
- dot_index = value.index('.') || value.size
129
- colon_index = value.index(':') || value.size
130
-
131
- dot_index < colon_index
132
- end
133
52
 
134
- # Determines whether the given string is a valid IPv4 or IPv6 address.
135
- def self.valid_ip?(ip)
136
- # Client IPs should not have subnet masks even though IPAddr can parse them.
137
- return false if ip.include?('/')
53
+ private
138
54
 
139
- begin
140
- IPAddr.new(ip)
141
-
142
- true
143
- rescue IPAddr::Error
144
- false
55
+ def configuration
56
+ Datadog.configuration.tracing.client_ip
145
57
  end
146
58
  end
147
-
148
- def self.ip_headers(headers)
149
- return {} unless headers
150
-
151
- DEFAULT_IP_HEADERS_NAMES.each_with_object({}) do |name, result|
152
- value = headers.get(name)
153
- result[name] = value unless value.nil?
154
- end
155
- end
156
-
157
- def self.configuration
158
- Datadog.configuration.tracing.client_ip
159
- end
160
59
  end
161
60
  end
162
61
  end
@@ -25,7 +25,7 @@ module Datadog
25
25
 
26
26
  # Extensions for HTTP client
27
27
  module Client
28
- def send_payload(request)
28
+ def send_traces_payload(request)
29
29
  send_request(request) do |api, env|
30
30
  api.send_traces(env)
31
31
  end
@@ -128,7 +128,7 @@ module Datadog
128
128
  responses = chunker.encode_in_chunks(traces.lazy).map do |encoded_traces, trace_count|
129
129
  request = Request.new(EncodedParcel.new(encoded_traces, trace_count))
130
130
 
131
- client.send_payload(request).tap do |response|
131
+ client.send_traces_payload(request).tap do |response|
132
132
  if downgrade?(response)
133
133
  downgrade!
134
134
  return send_traces(traces)
@@ -2,7 +2,7 @@ module DDTrace
2
2
  module VERSION
3
3
  MAJOR = 1
4
4
  MINOR = 10
5
- PATCH = 0
5
+ PATCH = 1
6
6
  PRE = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ddtrace
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 1.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-06 00:00:00.000000000 Z
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -281,12 +281,14 @@ files:
281
281
  - lib/datadog/core/utils.rb
282
282
  - lib/datadog/core/utils/compression.rb
283
283
  - lib/datadog/core/utils/forking.rb
284
+ - lib/datadog/core/utils/network.rb
284
285
  - lib/datadog/core/utils/object_set.rb
285
286
  - lib/datadog/core/utils/only_once.rb
286
287
  - lib/datadog/core/utils/safe_dup.rb
287
288
  - lib/datadog/core/utils/sequence.rb
288
289
  - lib/datadog/core/utils/string_table.rb
289
290
  - lib/datadog/core/utils/time.rb
291
+ - lib/datadog/core/vendor/ipaddr.rb
290
292
  - lib/datadog/core/vendor/multipart-post/LICENSE
291
293
  - lib/datadog/core/vendor/multipart-post/multipart.rb
292
294
  - lib/datadog/core/vendor/multipart-post/multipart/post.rb
@@ -826,7 +828,7 @@ licenses:
826
828
  - BSD-3-Clause
827
829
  metadata:
828
830
  allowed_push_host: https://rubygems.org
829
- post_install_message:
831
+ post_install_message:
830
832
  rdoc_options: []
831
833
  require_paths:
832
834
  - lib
@@ -844,8 +846,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
844
846
  - !ruby/object:Gem::Version
845
847
  version: 2.0.0
846
848
  requirements: []
847
- rubygems_version: 3.3.15
848
- signing_key:
849
+ rubygems_version: 3.3.20
850
+ signing_key:
849
851
  specification_version: 4
850
852
  summary: Datadog tracing code for your Ruby applications
851
853
  test_files: []