svcb_rr_patch 0.0.1

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