svcb_rr_patch 0.0.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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +29 -0
  3. data/.gitignore +17 -0
  4. data/.rubocop.yml +27 -0
  5. data/Gemfile +13 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +43 -0
  8. data/Rakefile +10 -0
  9. data/lib/svcb_rr_patch.rb +8 -0
  10. data/lib/svcb_rr_patch/https.rb +28 -0
  11. data/lib/svcb_rr_patch/svc_params.rb +96 -0
  12. data/lib/svcb_rr_patch/svc_params/alpn.rb +38 -0
  13. data/lib/svcb_rr_patch/svc_params/ech.rb +66 -0
  14. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents.rb +74 -0
  15. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/extension.rb +34 -0
  16. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config.rb +77 -0
  17. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_kem_id.rb +22 -0
  18. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_public_key.rb +20 -0
  19. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite.rb +41 -0
  20. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite/hpke_aead_id.rb +22 -0
  21. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite/hpke_kdf_id.rb +22 -0
  22. data/lib/svcb_rr_patch/svc_params/ipv4hint.rb +21 -0
  23. data/lib/svcb_rr_patch/svc_params/ipv6hint.rb +21 -0
  24. data/lib/svcb_rr_patch/svc_params/mandatory.rb +21 -0
  25. data/lib/svcb_rr_patch/svc_params/no_default_alpn.rb +10 -0
  26. data/lib/svcb_rr_patch/svc_params/port.rb +21 -0
  27. data/lib/svcb_rr_patch/svcb.rb +55 -0
  28. data/lib/svcb_rr_patch/version.rb +5 -0
  29. data/spec/alpn_spec.rb +30 -0
  30. data/spec/ipv4hint_spec.rb +38 -0
  31. data/spec/ipv6hint_spec.rb +33 -0
  32. data/spec/mandatory_spec.rb +39 -0
  33. data/spec/no_default_alpn_spec.rb +35 -0
  34. data/spec/port_spec.rb +30 -0
  35. data/spec/spec_helper.rb +5 -0
  36. data/spec/svc_params_spec.rb +75 -0
  37. data/svcb_rr_patch.gemspec +24 -0
  38. metadata +101 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fe01826cf1fe78d4b2d6db7d53bb474234121dceba9f7cd8dc26b25ca2d3e00a
4
+ data.tar.gz: 7acaffe658b58b44b2d22c66fafe904acacf15d1b68a5a1288db11dfacad886c
5
+ SHA512:
6
+ metadata.gz: eea644f426005af15be66fc9dbdcb9d60530e6ce77014a8345ebb52c561a71b2d352a2e29f373311724074a53c72d399007406348b8f421b1e9658a31c1b0c93
7
+ data.tar.gz: 8b60ace84e7fe2ab8c67ee7aea3cf412d1926740de83a60f5fd5820f06bad4e7202ea64349d74aa623c3475b0ccc74a4dd0de65eefe7266b851a24623923be06
@@ -0,0 +1,29 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ branches:
9
+ - '*'
10
+
11
+ jobs:
12
+ ci:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ ruby-version: ['2.7.x', '3.0.x']
17
+ steps:
18
+ - name: Set up Ruby
19
+ uses: actions/setup-ruby@v1
20
+ - uses: actions/checkout@v1
21
+ - name: Install dependencies
22
+ run: |
23
+ gem --version
24
+ gem install bundler
25
+ bundle --version
26
+ bundle install
27
+ - name: Run test
28
+ run: |
29
+ bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ Gemfile.lock
4
+ .config
5
+ .rvmrc
6
+ /.bundle/
7
+ /vendor/
8
+ /lib/bundler/man/
9
+ /pkg/
10
+ /.yardoc/
11
+ /_yardoc/
12
+ /doc/
13
+ /rdoc/
14
+ /coverage/
15
+ /spec/reports/
16
+ /tmp/
17
+ *.rdb
data/.rubocop.yml ADDED
@@ -0,0 +1,27 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/ConditionalAssignment:
5
+ Enabled: false
6
+
7
+ Style/Documentation:
8
+ Enabled: false
9
+
10
+ Style/NumericLiterals:
11
+ Enabled: false
12
+
13
+ Style/ClassAndModuleChildren:
14
+ EnforcedStyle: compact
15
+
16
+ Metrics/AbcSize:
17
+ Max: 30
18
+
19
+ Metrics/MethodLength:
20
+ Max: 30
21
+
22
+ Naming/MethodParameterName:
23
+ MinNameLength: 1
24
+
25
+ Metrics/BlockLength:
26
+ Exclude:
27
+ - 'spec/*.rb'
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'rake'
6
+
7
+ group :test do
8
+ gem 'byebug'
9
+ gem 'rspec', '3.9.0'
10
+ gem 'rubocop', '0.78.0'
11
+ end
12
+
13
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Tomoya Kuwayama
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # svcb_rr_patch
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/svcb_rr_patch.svg)](https://badge.fury.io/rb/svcb_rr_patch)
4
+ [![CI](https://github.com/thekuwayama/svcb_rr_patch/workflows/CI/badge.svg)](https://github.com/thekuwayama/svcb_rr_patch/actions?workflow=CI)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/a1e5224a552014f2d4d5/maintainability)](https://codeclimate.com/github/thekuwayama/svcb_rr_patch/maintainability)
6
+
7
+ `svcb_rr_patch` is the patch that adds SVCB Resource Record and HTTPS Resource Record.
8
+
9
+ - https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-06
10
+
11
+ `svcb_rr_patch` supports "ech" SvcParamKey that ECHConfig.version is 0xfe0a.
12
+
13
+ - https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-10#section-4
14
+
15
+
16
+ ## Installation
17
+
18
+ he gem is available at [rubygems.org](https://rubygems.org/gems/svcb_rr_patch). You can install it the following.
19
+
20
+ ```bash
21
+ $ gem install svcb_rr_patch
22
+ ```
23
+
24
+
25
+ ## Usage
26
+
27
+ You can resolve HTTPS resources.
28
+
29
+ ```bash
30
+ $ irb
31
+ irb(main):001:0> require 'svcb_rr_patch'
32
+ => true
33
+ irb(main):002:1* Resolv::DNS.new.getresources(
34
+ irb(main):003:1* "blog.cloudflare.com",
35
+ irb(main):004:1* Resolv::DNS::Resource::IN::HTTPS
36
+ irb(main):005:0> ) { |rr| pp rr }
37
+ => [#<Resolv::DNS::Resource::IN::HTTPS:0x0000000000000001 @svc_priority=1, @svc_domain_name="", @svc_field_value={"alpn"=>#<SvcbRrPatch::SvcParams::Alpn:0x0000000000000002 @protocols=["h3-29", "h3-28", "h3-27", "h2"]>, "ipv4hint"=>#<SvcbRrPatch::SvcParams::Ipv4hint:0x0000000000000003 @addresses=[#<Resolv::IPv4 104.18.26.46>, #<Resolv::IPv4 104.18.27.46>]>, "ipv6hint"=>#<SvcbRrPatch::SvcParams::Ipv6hint:0x0000000000000004 @addresses=[#<Resolv::IPv6 2606:4700::6812:1a2e>, #<Resolv::IPv6 2606:4700::6812:1b2e>]>}, @ttl=300>]
38
+ ```
39
+
40
+
41
+ ## License
42
+
43
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RuboCop::RakeTask.new
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task default: %i[rubocop spec]
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'resolv'
4
+
5
+ require 'svcb_rr_patch/version'
6
+ require 'svcb_rr_patch/svc_params'
7
+ require 'svcb_rr_patch/svcb'
8
+ require 'svcb_rr_patch/https'
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The HTTPS DNS Resource Record
5
+
6
+ class Resolv::DNS::Resource::IN::HTTPS < Resolv::DNS::Resource::IN::SVCB
7
+ TypeValue = 65 # rubocop:disable Naming/ConstantName
8
+ ClassValue = IN::ClassValue
9
+ ClassHash[[TypeValue, ClassValue]] = self
10
+
11
+ def initialize(svc_priority, target_name, svc_params)
12
+ # https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-06
13
+ super(svc_priority, target_name, svc_params)
14
+ end
15
+
16
+ class << self
17
+ # :nodoc:
18
+ def decode_rdata(msg)
19
+ svc_priority = msg.get_bytes(2).unpack1('n')
20
+ target_name = msg.get_string
21
+ return new(svc_priority, target_name, {}) if svc_priority.zero?
22
+
23
+ # the SvcParams, consuming the remainder of the record
24
+ svc_params = ::SvcbRrPatch::SvcParams.decode(msg.get_bytes)
25
+ new(svc_priority, target_name, svc_params)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SvcbRrPatch::SvcParams
4
+ PARAMETER_REGISTRY = lambda {
5
+ registry = %w[
6
+ mandatory
7
+ alpn
8
+ no-default-alpn
9
+ port
10
+ ipv4hint
11
+ ech
12
+ ipv6hint
13
+ ]
14
+ # rubocop:disable Security/Eval
15
+ (65280..65535).each do |nnnn|
16
+ eval "registry[nnnn] = \"key#{nnnn}\"", binding, __FILE__, __LINE__
17
+ end
18
+ # rubocop:enable Security/Eval
19
+ registry
20
+ }.call.freeze
21
+ end
22
+
23
+ Dir[File.dirname(__FILE__) + '/svc_params/*.rb'].sort.each { |f| require f }
24
+
25
+ module SvcbRrPatch::SvcParams
26
+ # @return [String]
27
+ def self.encode(svc_params)
28
+ h = Hash[(0..PARAMETER_REGISTRY.size - 1).zip(PARAMETER_REGISTRY)].invert
29
+
30
+ svc_params
31
+ .map { |k, v| [h[k], v] }
32
+ .sort { |lh, rh| lh.first <=> rh.first }
33
+ .map do |k, v|
34
+ [k].pack('n') + v.encode.then { |s| [s.length].pack('n') + s }
35
+ end
36
+ .join
37
+ end
38
+
39
+ # @param octet [String]
40
+ #
41
+ # @return [Hash] Integer => SvcbRrPatch::$Object
42
+ # rubocop:disable Metrics/AbcSize
43
+ def self.decode(octet)
44
+ svc_params = {}
45
+ i = 0
46
+ h = Hash[(0..PARAMETER_REGISTRY.size - 1).zip(PARAMETER_REGISTRY)].invert
47
+ while i < octet.length
48
+ raise ::Resolv::DNS::DecodeError if i + 4 > octet.length
49
+
50
+ k = octet.slice(i, 2).unpack1('n')
51
+ # SvcParamKeys SHALL appear in increasing numeric order.
52
+ raise ::Resolv::DNS::DecodeError \
53
+ unless svc_params.keys.find { |already| h[already] >= k }.nil?
54
+
55
+ i += 2
56
+ vlen = octet.slice(i, 2).unpack1('n')
57
+ i += 2
58
+ raise ::Resolv::DNS::DecodeError if i + vlen > octet.length
59
+
60
+ v = octet.slice(i, vlen)
61
+ i += vlen
62
+ # Values are in a format specific to the SvcParamKey.
63
+ svc_param_key = PARAMETER_REGISTRY[k]
64
+ svc_param_values = decode_svc_params(svc_param_key, v)
65
+ svc_params.store(svc_param_key, svc_param_values)
66
+ end
67
+ raise ::Resolv::DNS::DecodeError if i != octet.length
68
+
69
+ svc_params
70
+ end
71
+ # rubocop:enable Metrics/AbcSize
72
+
73
+ # :nodoc:
74
+ # rubocop:disable Metrics/CyclomaticComplexity
75
+ def self.decode_svc_params(key, octet)
76
+ case key
77
+ when 'no name'
78
+ NoName.decode(octet)
79
+ when 'alpn'
80
+ Alpn.decode(octet)
81
+ when 'no-default-alpn'
82
+ NoDefaultAlpn.decode(octet)
83
+ when 'port'
84
+ Port.decode(octet)
85
+ when 'ipv4hint'
86
+ Ipv4hint.decode(octet)
87
+ when 'ech'
88
+ Ech.decode(octet)
89
+ when 'ipv6hint'
90
+ Ipv6hint.decode(octet)
91
+ else
92
+ octet
93
+ end
94
+ end
95
+ # rubocop:enable Metrics/CyclomaticComplexity
96
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Alpn
4
+ attr_reader :protocols
5
+
6
+ # @param protocols [Array of String]
7
+ def initialize(protocols)
8
+ @protocols = protocols
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ @protocols.map { |p| [p.length].pack('C') + p }.join
14
+ end
15
+
16
+ # :nodoc:
17
+ def self.decode_protocols(octet)
18
+ protocols = []
19
+ i = 0
20
+ while i < octet.length
21
+ raise ::Resolv::DNS::DecodeError if i + 1 > octet.length
22
+
23
+ id_len = octet.slice(i, 1).unpack1('C1')
24
+ i += 1
25
+ protocols << octet.slice(i, id_len)
26
+ i += id_len
27
+ end
28
+ raise ::Resolv::DNS::DecodeError if i != octet.length
29
+
30
+ protocols
31
+ end
32
+
33
+ # :nodec:
34
+ def self.decode(octet)
35
+ protocols = decode_protocols(octet)
36
+ new(protocols)
37
+ end
38
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech
4
+ attr_reader :echconfigs
5
+
6
+ # @param echconfiglist [Array of ECHConfig]
7
+ def initialize(echconfiglist)
8
+ @echconfiglist = echconfiglist
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ @echconfiglist.map(&:encode).join.then { |s| [s.length].pack('n') + s }
14
+ end
15
+
16
+ # :nodoc:
17
+ def self.decode(octet)
18
+ raise ::Resolv::DNS::DecodeError \
19
+ unless octet.length == octet.slice(0, 2).unpack1('n') + 2
20
+
21
+ echconfiglist = ECHConfig.decode_vectors(octet.slice(2..))
22
+ new(echconfiglist)
23
+ end
24
+ end
25
+
26
+ require_relative 'ech/echconfig_contents'
27
+
28
+ class SvcbRrPatch::SvcParams::Ech::ECHConfig
29
+ attr_reader :version
30
+ attr_reader :echconfigcontents
31
+
32
+ ECHConfigContents = ::SvcbRrPatch::SvcParams::Ech::ECHConfigContents
33
+
34
+ # @param version [String]
35
+ # @param echconfig_contents [ECHConfigContents]
36
+ def initialize(version, echconfig_contents)
37
+ @version = version
38
+ @echconfig_contents = echconfig_contents
39
+ end
40
+
41
+ # @return [String]
42
+ def encode
43
+ @version + @echconfig_contents.encode.then { |s| [s.length].pack('n') + s }
44
+ end
45
+
46
+ # @return [Array of ECHConfig]
47
+ def self.decode_vectors(octet)
48
+ i = 0
49
+ echconfigs = []
50
+ while i < octet.length
51
+ raise ::Resolv::DNS::DecodeError if i + 4 > octet.length
52
+
53
+ version = octet.slice(i, 2)
54
+ length = octet.slice(i + 2, 2).unpack1('n')
55
+ i += 4
56
+ raise ::Resolv::DNS::DecodeError if i + length > octet.length
57
+
58
+ echconfig_contents = ECHConfigContents.decode(octet.slice(i, length))
59
+ i += length
60
+ echconfigs << new(version, echconfig_contents)
61
+ end
62
+ raise ::Resolv::DNS::DecodeError if i != octet.length
63
+
64
+ echconfigs
65
+ end
66
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents
4
+ # define class
5
+ end
6
+
7
+ Dir[File.dirname(__FILE__) + '/echconfig_contents/*.rb']
8
+ .sort.each { |f| require f }
9
+
10
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents
11
+ attr_reader :key_config
12
+ attr_reader :maximum_name_length
13
+ attr_reader :public_name
14
+ attr_reader :extensions
15
+
16
+ # @param key_config [HpkeKeyConfig]
17
+ # @param maximum_name_length [Integer]
18
+ # @param public_name [String]
19
+ # @param extensions [Array of Extension]
20
+ def initialize(key_config,
21
+ maximum_name_length,
22
+ public_name,
23
+ extensions)
24
+ @key_config = key_config
25
+ @maximum_name_length = maximum_name_length
26
+ @public_name = public_name
27
+ @extensions = extensions
28
+ end
29
+
30
+ # @return [String]
31
+ def encode
32
+ @key_config.encode \
33
+ + [@maximum_name_length].pack('n') \
34
+ + @public_name.then { |s| [s.length].pack('n') + s } \
35
+ + @extensions.map(&:encode).join.then { |s| [s.length].pack('n') + s }
36
+ end
37
+
38
+ # :nodoc
39
+ # rubocop:disable Metrics/AbcSize
40
+ # rubocop:disable Metrics/CyclomaticComplexity
41
+ def self.decode(octet)
42
+ key_config, octet = HpkeKeyConfig.decode(octet)
43
+ raise ::Resolv::DNS::DecodeError if octet.length < 2
44
+
45
+ maximum_name_length = octet.slice(0, 2).unpack1('n')
46
+ i = 2
47
+ raise ::Resolv::DNS::DecodeError if i + 2 > octet.length
48
+
49
+ pn_len = octet.slice(i, 2).unpack1('n')
50
+ i += 2
51
+ raise ::Resolv::DNS::DecodeError if i + pn_len > octet.length
52
+
53
+ public_name = octet.slice(i, pn_len)
54
+ i += pn_len
55
+ raise ::Resolv::DNS::DecodeError if i + 2 > octet.length
56
+
57
+ ex_len = octet.slice(i, 2).unpack1('n')
58
+ i += 2
59
+ raise ::Resolv::DNS::DecodeError if i + ex_len > octet.length
60
+
61
+ extensions = Extension.decode_vectors(octet.slice(i, ex_len))
62
+ i += ex_len
63
+ raise ::Resolv::DNS::DecodeError if i != octet.length
64
+
65
+ new(
66
+ key_config,
67
+ maximum_name_length,
68
+ public_name,
69
+ extensions
70
+ )
71
+ end
72
+ # rubocop:enable Metrics/AbcSize
73
+ # rubocop:enable Metrics/CyclomaticComplexity
74
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::Extension
4
+ attr_reader :octet
5
+
6
+ # @param octet [String]
7
+ def initialize(octet)
8
+ @octet = octet # TODO
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ @octet # TODO
14
+ end
15
+
16
+ # @return [Array of Extension]
17
+ def self.decode_vectors(octet)
18
+ i = 0
19
+ extensions = []
20
+ while i < octet.length
21
+ raise ::Resolv::DNS::DecodeError if i + 4 > octet.length
22
+
23
+ ex_len = octet.slice(i + 2, 2)
24
+ i += 4
25
+ raise ::Resolv::DNS::DecodeError if i + ex_len > octet.length
26
+
27
+ extensions << new(octet.slice(i, ex_len)) # TODO
28
+ i += ex_len
29
+ end
30
+ raise ::Resolv::DNS::DecodeError if i != octet.length
31
+
32
+ extensions
33
+ end
34
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::HpkeKeyConfig
4
+ # define class
5
+ end
6
+
7
+ Dir[File.dirname(__FILE__) + '/hpke_key_config/*.rb']
8
+ .sort.each { |f| require f }
9
+
10
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::HpkeKeyConfig
11
+ attr_reader :config_id
12
+ attr_reader :kem_id
13
+ attr_reader :public_key
14
+ attr_reader :cipher_suites
15
+
16
+ # @param config_id [Integer]
17
+ # @param kem_id [HpkeKemId]
18
+ # @param public_key [HpkePublicKey]
19
+ # @param cipher_suites [Array of HpkeSymmetricCipherSuite]
20
+ def initialize(config_id,
21
+ kem_id,
22
+ public_key,
23
+ cipher_suites)
24
+ @config_id = config_id
25
+ @kem_id = kem_id
26
+ @public_key = public_key
27
+ @cipher_suites = cipher_suites
28
+ end
29
+
30
+ # @return [String]
31
+ def encode
32
+ [@config_id].pack('C') \
33
+ + @kem_id.encode \
34
+ + @public_key.encode \
35
+ + @cipher_suites.map(&:encode).join.then { |s| [s.length].pack('n') + s }
36
+ end
37
+
38
+ # :nodoc
39
+ # rubocop:disable Metrics/AbcSize
40
+ # rubocop:disable Metrics/CyclomaticComplexity
41
+ def self.decode(octet)
42
+ raise ::Resolv::DNS::DecodeError if octet.empty?
43
+
44
+ config_id = octet.slice(0, 1).unpack1('C')
45
+ i = 1
46
+ raise ::Resolv::DNS::DecodeError if i + 2 > octet.length
47
+
48
+ kem_id = HpkeKemId.decode(octet.slice(i, 2))
49
+ i += 2
50
+ raise ::Resolv::DNS::DecodeError if i + 2 > octet.length
51
+
52
+ pk_len = octet.slice(i, 2).unpack1('n')
53
+ i += 2
54
+ raise ::Resolv::DNS::DecodeError if i + pk_len > octet.length
55
+
56
+ public_key = HpkePublicKey.decode(octet.slice(i, pk_len))
57
+ i += pk_len
58
+ raise ::Resolv::DNS::DecodeError if i + 2 > octet.length
59
+
60
+ cs_len = octet.slice(i, 2).unpack1('n')
61
+ i += 2
62
+ raise ::Resolv::DNS::DecodeError if i + 2 > octet.length
63
+
64
+ cs_bin = octet.slice(i, cs_len)
65
+ i += cs_len
66
+ cipher_suites = HpkeSymmetricCipherSuite.decode_vectors(cs_bin)
67
+ hpke_key_config = new(
68
+ config_id,
69
+ kem_id,
70
+ public_key,
71
+ cipher_suites
72
+ )
73
+ [hpke_key_config, octet[i..]]
74
+ end
75
+ # rubocop:enable Metrics/AbcSize
76
+ # rubocop:enable Metrics/CyclomaticComplexity
77
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::HpkeKeyConfig::HpkeKemId
4
+ attr_reader :uint16
5
+
6
+ # @param uint16 [Integer]
7
+ def initialize(uint16)
8
+ @uint16 = uint16
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ [@uint16].pack('n')
14
+ end
15
+
16
+ # :nodoc
17
+ def self.decode(octet)
18
+ raise ::Resolv::DNS::DecodeError if octet.length != 2
19
+
20
+ new(octet.unpack1('n'))
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::HpkeKeyConfig::HpkePublicKey # rubocop:disable Layout/LineLength
4
+ attr_reader :opaque
5
+
6
+ # @param opaque [String]
7
+ def initialize(opaque)
8
+ @opaque = opaque
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ @opaque.then { |s| [s.length].pack('n') + s }
14
+ end
15
+
16
+ # :nodoc
17
+ def self.decode(octet)
18
+ new(octet)
19
+ end
20
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite # rubocop:disable Layout/LineLength
4
+ # define class
5
+ end
6
+
7
+ Dir[File.dirname(__FILE__) + '/hpke_symmetric_cipher_suite/*.rb']
8
+ .sort.each { |f| require f }
9
+
10
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite # rubocop:disable Layout/LineLength
11
+ attr_reader :kdf_id
12
+ attr_reader :aead_id
13
+
14
+ # @param kdf_id [HpkeKdfId]
15
+ # @param aead_id [HpkeAeadId]
16
+ def initialize(kdf_id, aead_id)
17
+ @kdf_id = kdf_id
18
+ @aead_id = aead_id
19
+ end
20
+
21
+ # @return [String]
22
+ def encode
23
+ @kdf_id.encode + @aead_id.encode
24
+ end
25
+
26
+ # @return [Array of HpkeSymmetricCipherSuite]
27
+ def self.decode_vectors(octet)
28
+ i = 0
29
+ cipher_suites = []
30
+ while i < octet.length
31
+ raise ::Resolv::DNS::DecodeError if i + 4 > octet.length
32
+
33
+ kdf_id = HpkeKdfId.decode(octet.slice(i, 2))
34
+ aead_id = HpkeAeadId.decode(octet.slice(i + 2, 2))
35
+ i += 4
36
+ cipher_suites << new(kdf_id, aead_id)
37
+ end
38
+
39
+ cipher_suites
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite::HpkeAeadId # rubocop:disable Layout/LineLength
4
+ attr_reader :uint16
5
+
6
+ # @param uint16 [Integer]
7
+ def initialize(uint16)
8
+ @uint16 = uint16
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ [@uint16].pack('n')
14
+ end
15
+
16
+ # :nodoc
17
+ def self.decode(octet)
18
+ raise ::Resolv::DNS::DecodeError if octet.length != 2
19
+
20
+ new(octet.unpack1('n'))
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ech::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite::HpkeKdfId # rubocop:disable Layout/LineLength
4
+ attr_reader :uint16
5
+
6
+ # @param uint16 [Integer]
7
+ def initialize(uint16)
8
+ @uint16 = uint16
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ [@uint16].pack('n')
14
+ end
15
+
16
+ # :nodoc
17
+ def self.decode(octet)
18
+ raise ::Resolv::DNS::DecodeError if octet.length != 2
19
+
20
+ new(octet.unpack1('n'))
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ipv4hint
4
+ attr_reader :addresses
5
+
6
+ # @param addresses [Array of Resolv::IPv4]
7
+ def initialize(addresses)
8
+ @addresses = addresses
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ @addresses.map(&:address).join
14
+ end
15
+
16
+ # :nodoc:
17
+ def self.decode(octet)
18
+ addresses = octet.scan(/.{1,4}/).map { |s| Resolv::IPv4.new(s) }
19
+ new(addresses)
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Ipv6hint
4
+ attr_reader :addresses
5
+
6
+ # @param addresses [Array of Resolv::IPv6]
7
+ def initialize(addresses)
8
+ @addresses = addresses
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ @addresses.map(&:address).join
14
+ end
15
+
16
+ # :nodoc:
17
+ def self.decode(octet)
18
+ addresses = octet.scan(/.{1,16}/).map { |s| Resolv::IPv6.new(s) }
19
+ new(addresses)
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Mandatory
4
+ attr_reader :keys
5
+
6
+ # @param keys [Array of Integer]]
7
+ def initialize(keys)
8
+ @keys = keys
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ @keys.sort.map { |k| [k].pack('n') }.join
14
+ end
15
+
16
+ # :nodoc:
17
+ def self.decode(octet)
18
+ keys = octet.scan(/.{1,2}/).map { |s| s.unpack1('n') }
19
+ new(keys)
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::NoDefaultAlpn <
4
+ SvcbRrPatch::SvcParams::Alpn
5
+ # :nodec:
6
+ def self.decode(octet)
7
+ protocols = decode_protocols(octet)
8
+ new(protocols)
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SvcbRrPatch::SvcParams::Port
4
+ attr_reader :port
5
+
6
+ # @param port [Integer]
7
+ def initialize(port)
8
+ @port = port
9
+ end
10
+
11
+ # @return [String]
12
+ def encode
13
+ [@port].pack('n')
14
+ end
15
+
16
+ # :nodoc:
17
+ def self.decode(octet)
18
+ port = octet.unpack1('n')
19
+ new(port)
20
+ end
21
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The SVCB(contraction of "service binding") DNS Resource Record
5
+
6
+ class Resolv::DNS::Resource::IN::SVCB < Resolv::DNS::Resource
7
+ TypeValue = 64 # rubocop: disable Naming/ConstantName
8
+ ClassValue = IN::ClassValue
9
+ ClassHash[[TypeValue, ClassValue]] = self
10
+
11
+ # @param svc_priority [Integer]
12
+ # @param target_name [String]
13
+ # @param svc_params [Map]
14
+ def initialize(svc_priority, target_name, svc_params)
15
+ # https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-06
16
+ @svc_priority = svc_priority
17
+ @target_name = target_name
18
+ @svc_params = svc_params
19
+ end
20
+
21
+ ##
22
+ # SvcPriority
23
+
24
+ attr_reader :svc_priority
25
+
26
+ ##
27
+ # TargetName
28
+
29
+ attr_reader :target_name
30
+
31
+ ##
32
+ # SvcParams
33
+
34
+ attr_reader :svc_params
35
+
36
+ # :nodoc:
37
+ def encode_rdata(msg)
38
+ msg.put_bytes([@svc_priority].pack('n'))
39
+ msg.put_string(@target_name)
40
+ msg.put_string(::SvcbRrPatch::SvcParams.encode(@svc_params))
41
+ end
42
+
43
+ class << self
44
+ # :nodoc:
45
+ def decode_rdata(msg)
46
+ svc_priority = msg.get_bytes(2).unpack1('n')
47
+ target_name = msg.get_string
48
+ return new(svc_priority, target_name, {}) if svc_priority.zero?
49
+
50
+ # the SvcParams, consuming the remainder of the record
51
+ svc_params = ::SvcbRrPatch::SvcParams.decode(msg.get_bytes)
52
+ new(svc_priority, target_name, svc_params)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SvcbRrPatch
4
+ VERSION = '0.0.1'
5
+ end
data/spec/alpn_spec.rb ADDED
@@ -0,0 +1,30 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe SvcbRrPatch::SvcParams::Alpn do
7
+ let(:octet) do
8
+ "\x05h3-29\x05h3-28\x05h3-27\x02h2"
9
+ end
10
+
11
+ context '#decode' do
12
+ let(:alpn) do
13
+ SvcbRrPatch::SvcParams::Alpn.decode(octet)
14
+ end
15
+
16
+ it 'could decode' do
17
+ expect(alpn.protocols).to eq %w[h3-29 h3-28 h3-27 h2]
18
+ end
19
+ end
20
+
21
+ context '#encode' do
22
+ let(:alpn) do
23
+ SvcbRrPatch::SvcParams::Alpn.new(%w[h3-29 h3-28 h3-27 h2])
24
+ end
25
+
26
+ it 'could encode' do
27
+ expect(alpn.encode).to eq octet
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe SvcbRrPatch::SvcParams::Ipv4hint do
7
+ let(:octet) do
8
+ "\xc0\xa8\x00\x01\xc0\xa8\x00\x02"
9
+ end
10
+
11
+ context '#decode' do
12
+ let(:ipv4hint) do
13
+ SvcbRrPatch::SvcParams::Ipv4hint.decode(octet)
14
+ end
15
+
16
+ it 'could decode' do
17
+ expect(ipv4hint.addresses).to eq [
18
+ Resolv::IPv4.create('192.168.0.1'),
19
+ Resolv::IPv4.create('192.168.0.2')
20
+ ]
21
+ end
22
+ end
23
+
24
+ context '#encode' do
25
+ let(:ipv4hint) do
26
+ SvcbRrPatch::SvcParams::Ipv4hint.new(
27
+ [
28
+ Resolv::IPv4.create('192.168.0.1'),
29
+ Resolv::IPv4.create('192.168.0.2')
30
+ ]
31
+ )
32
+ end
33
+
34
+ it 'could encode' do
35
+ expect(ipv4hint.encode).to eq octet
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe SvcbRrPatch::SvcParams::Ipv6hint do
7
+ let(:octet) do
8
+ "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
9
+ end
10
+
11
+ context '#decode' do
12
+ let(:ipv6hint) do
13
+ SvcbRrPatch::SvcParams::Ipv6hint.decode(octet)
14
+ end
15
+
16
+ it 'could decode' do
17
+ expect(ipv6hint.addresses)
18
+ .to eq [Resolv::IPv6.create('101:101:101:101:101:101:101:101')]
19
+ end
20
+ end
21
+
22
+ context '#encode' do
23
+ let(:ipv6hint) do
24
+ SvcbRrPatch::SvcParams::Ipv6hint.new(
25
+ [Resolv::IPv6.create('101:101:101:101:101:101:101:101')]
26
+ )
27
+ end
28
+
29
+ it 'could encode' do
30
+ expect(ipv6hint.encode).to eq octet
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe SvcbRrPatch::SvcParams::Mandatory do
7
+ let(:octet) do
8
+ "\x00\x05\xff\xa4"
9
+ end
10
+
11
+ let(:keys) do
12
+ h = Hash[
13
+ (0..SvcbRrPatch::SvcParams::PARAMETER_REGISTRY.size - 1)
14
+ .zip(SvcbRrPatch::SvcParams::PARAMETER_REGISTRY)
15
+ ].invert
16
+
17
+ [h['ech'], h['key65444']]
18
+ end
19
+
20
+ context '#decode' do
21
+ let(:mandatory) do
22
+ SvcbRrPatch::SvcParams::Mandatory.decode(octet)
23
+ end
24
+
25
+ it 'could decode' do
26
+ expect(mandatory.keys).to eq keys
27
+ end
28
+ end
29
+
30
+ context '#encode' do
31
+ let(:mandatory) do
32
+ SvcbRrPatch::SvcParams::Mandatory.new(keys)
33
+ end
34
+
35
+ it 'could encode' do
36
+ expect(mandatory.encode).to eq octet
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe SvcbRrPatch::SvcParams::NoDefaultAlpn do
7
+ let(:octet) do
8
+ "\x05h3-29\x05h3-28\x05h3-27\x02h2"
9
+ end
10
+
11
+ context '#decode' do
12
+ let(:no_default_alpn) do
13
+ SvcbRrPatch::SvcParams::NoDefaultAlpn
14
+ .decode(octet)
15
+ end
16
+
17
+ it 'could decode' do
18
+ expect(no_default_alpn.protocols).to eq %w[h3-29 h3-28 h3-27 h2]
19
+ expect(no_default_alpn)
20
+ .to be_a(SvcbRrPatch::SvcParams::NoDefaultAlpn)
21
+ end
22
+ end
23
+
24
+ context '#encode' do
25
+ let(:no_default_alpn) do
26
+ SvcbRrPatch::SvcParams::NoDefaultAlpn.new(%w[h3-29 h3-28 h3-27 h2])
27
+ end
28
+
29
+ it 'could encode' do
30
+ expect(no_default_alpn)
31
+ .to be_a(SvcbRrPatch::SvcParams::NoDefaultAlpn)
32
+ expect(no_default_alpn.encode).to eq octet
33
+ end
34
+ end
35
+ end
data/spec/port_spec.rb ADDED
@@ -0,0 +1,30 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe SvcbRrPatch::SvcParams::Port do
7
+ let(:octet) do
8
+ "\x01\xbb"
9
+ end
10
+
11
+ context '#decode' do
12
+ let(:port) do
13
+ SvcbRrPatch::SvcParams::Port.decode(octet)
14
+ end
15
+
16
+ it 'could decode' do
17
+ expect(port.port).to eq 443
18
+ end
19
+ end
20
+
21
+ context '#encode' do
22
+ let(:port) do
23
+ SvcbRrPatch::SvcParams::Port.new(443)
24
+ end
25
+
26
+ it 'could encode' do
27
+ expect(port.encode).to eq octet
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.configure(&:disable_monkey_patching!)
4
+
5
+ require 'svcb_rr_patch'
@@ -0,0 +1,75 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe SvcbRrPatch::SvcParams do
7
+ let(:octet) do
8
+ <<-BIN.split.map(&:hex).map(&:chr).join
9
+ 00 01 00 15 05 68 33 2d 32 39 05 68 33 2d 32 38
10
+ 05 68 33 2d 32 37 02 68 32 00 04 00 08 c0 a8 00
11
+ 01 c0 a8 00 02 00 06 00 10 01 01 01 01 01 01 01
12
+ 01 01 01 01 01 01 01 01 01 ff 35 00 03 01 02 03
13
+ BIN
14
+ end
15
+
16
+ let(:alpn) do
17
+ SvcbRrPatch::SvcParams::Alpn.new(%w[h3-29 h3-28 h3-27 h2])
18
+ end
19
+
20
+ let(:ipv4hint) do
21
+ SvcbRrPatch::SvcParams::Ipv4hint.new(
22
+ [
23
+ Resolv::IPv4.create('192.168.0.1'),
24
+ Resolv::IPv4.create('192.168.0.2')
25
+ ]
26
+ )
27
+ end
28
+
29
+ let(:ipv6hint) do
30
+ SvcbRrPatch::SvcParams::Ipv6hint.new(
31
+ [Resolv::IPv6.create('101:101:101:101:101:101:101:101')]
32
+ )
33
+ end
34
+
35
+ let(:key65333) do
36
+ "\x01\x02\x03"
37
+ end
38
+
39
+ context '#keyNNNNN' do
40
+ it 'could be defined' do
41
+ expect(SvcbRrPatch::SvcParams::PARAMETER_REGISTRY[65333])
42
+ .to eq 'key65333'
43
+ end
44
+ end
45
+
46
+ context '#decode' do
47
+ let(:svc_params) do
48
+ SvcbRrPatch::SvcParams.decode(octet)
49
+ end
50
+
51
+ it 'could decode' do
52
+ expect(svc_params.keys).to eq %w[alpn ipv4hint ipv6hint key65333]
53
+
54
+ expect(svc_params['alpn'].protocols).to eq alpn.protocols
55
+ expect(svc_params['ipv4hint'].addresses).to eq ipv4hint.addresses
56
+ expect(svc_params['ipv6hint'].addresses).to eq ipv6hint.addresses
57
+ expect(svc_params['key65333']).to eq key65333
58
+ end
59
+ end
60
+
61
+ context '#encode' do
62
+ let(:svc_params) do
63
+ {
64
+ 'alpn' => alpn,
65
+ 'ipv4hint' => ipv4hint,
66
+ 'ipv6hint' => ipv6hint,
67
+ 'key65333' => key65333
68
+ }
69
+ end
70
+
71
+ it 'could encode' do
72
+ expect(SvcbRrPatch::SvcParams.encode(svc_params)).to eq octet
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'svcb_rr_patch/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'svcb_rr_patch'
9
+ spec.version = SvcbRrPatch::VERSION
10
+ spec.authors = ['thekuwayama']
11
+ spec.email = ['thekuwayama@gmail.com']
12
+ spec.summary = 'the patch that adds SVCB Resource Record' \
13
+ ' and HTTPS Resource Record'
14
+ spec.description = spec.summary
15
+ spec.homepage = 'https://github.com/thekuwayama/svcb_rr_patch'
16
+ spec.license = 'MIT'
17
+ spec.required_ruby_version = '>=2.6.0'
18
+
19
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'bundler'
24
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: svcb_rr_patch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - thekuwayama
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-07-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: the patch that adds SVCB Resource Record and HTTPS Resource Record
28
+ email:
29
+ - thekuwayama@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".github/workflows/ci.yml"
35
+ - ".gitignore"
36
+ - ".rubocop.yml"
37
+ - Gemfile
38
+ - LICENSE.txt
39
+ - README.md
40
+ - Rakefile
41
+ - lib/svcb_rr_patch.rb
42
+ - lib/svcb_rr_patch/https.rb
43
+ - lib/svcb_rr_patch/svc_params.rb
44
+ - lib/svcb_rr_patch/svc_params/alpn.rb
45
+ - lib/svcb_rr_patch/svc_params/ech.rb
46
+ - lib/svcb_rr_patch/svc_params/ech/echconfig_contents.rb
47
+ - lib/svcb_rr_patch/svc_params/ech/echconfig_contents/extension.rb
48
+ - lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config.rb
49
+ - lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_kem_id.rb
50
+ - lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_public_key.rb
51
+ - lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite.rb
52
+ - lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite/hpke_aead_id.rb
53
+ - lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite/hpke_kdf_id.rb
54
+ - lib/svcb_rr_patch/svc_params/ipv4hint.rb
55
+ - lib/svcb_rr_patch/svc_params/ipv6hint.rb
56
+ - lib/svcb_rr_patch/svc_params/mandatory.rb
57
+ - lib/svcb_rr_patch/svc_params/no_default_alpn.rb
58
+ - lib/svcb_rr_patch/svc_params/port.rb
59
+ - lib/svcb_rr_patch/svcb.rb
60
+ - lib/svcb_rr_patch/version.rb
61
+ - spec/alpn_spec.rb
62
+ - spec/ipv4hint_spec.rb
63
+ - spec/ipv6hint_spec.rb
64
+ - spec/mandatory_spec.rb
65
+ - spec/no_default_alpn_spec.rb
66
+ - spec/port_spec.rb
67
+ - spec/spec_helper.rb
68
+ - spec/svc_params_spec.rb
69
+ - svcb_rr_patch.gemspec
70
+ homepage: https://github.com/thekuwayama/svcb_rr_patch
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.6.0
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubygems_version: 3.2.3
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: the patch that adds SVCB Resource Record and HTTPS Resource Record
93
+ test_files:
94
+ - spec/alpn_spec.rb
95
+ - spec/ipv4hint_spec.rb
96
+ - spec/ipv6hint_spec.rb
97
+ - spec/mandatory_spec.rb
98
+ - spec/no_default_alpn_spec.rb
99
+ - spec/port_spec.rb
100
+ - spec/spec_helper.rb
101
+ - spec/svc_params_spec.rb