ddtrace 1.10.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
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: []