svcb_rr_patch 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -5
  3. data/.rubocop.yml +1 -1
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -3
  6. data/README.md +11 -12
  7. data/lib/svcb_rr_patch/https.rb +1 -6
  8. data/lib/svcb_rr_patch/svc_params/alpn.rb +1 -1
  9. data/lib/svcb_rr_patch/svc_params/ech.rb +8 -45
  10. data/lib/svcb_rr_patch/svc_params/ipv4hint.rb +1 -1
  11. data/lib/svcb_rr_patch/svc_params/ipv6hint.rb +1 -1
  12. data/lib/svcb_rr_patch/svc_params/mandatory.rb +3 -9
  13. data/lib/svcb_rr_patch/svc_params/port.rb +1 -1
  14. data/lib/svcb_rr_patch/svc_params.rb +44 -22
  15. data/lib/svcb_rr_patch/svcb.rb +7 -9
  16. data/lib/svcb_rr_patch/version.rb +1 -1
  17. data/lib/svcb_rr_patch.rb +1 -0
  18. data/spec/alpn_spec.rb +1 -1
  19. data/spec/ipv4hint_spec.rb +1 -1
  20. data/spec/ipv6hint_spec.rb +1 -1
  21. data/spec/mandatory_spec.rb +8 -8
  22. data/spec/no_default_alpn_spec.rb +1 -1
  23. data/spec/port_spec.rb +1 -1
  24. data/spec/svc_params_spec.rb +4 -3
  25. data/svcb_rr_patch.gemspec +2 -1
  26. metadata +19 -12
  27. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/extension.rb +0 -34
  28. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_kem_id.rb +0 -22
  29. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_public_key.rb +0 -20
  30. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite/hpke_aead_id.rb +0 -22
  31. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite/hpke_kdf_id.rb +0 -22
  32. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config/hpke_symmetric_cipher_suite.rb +0 -41
  33. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents/hpke_key_config.rb +0 -77
  34. data/lib/svcb_rr_patch/svc_params/ech/echconfig_contents.rb +0 -69
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 607172ae2b63afd7c66a3cfe87456873eb1f436c28f0380a52edeeb31d9f3902
4
- data.tar.gz: b8a3b83f4820b78fb3efcb27b675a3cf07a58f360fe7d3c3a93fdd7161ced077
3
+ metadata.gz: 7a695feb098bc9703ae3959c87c0b70ae5818f10b124c2e8ba538ba0e76d4cd0
4
+ data.tar.gz: 1f8dd380eddbc47c974563508fea1517110c4fd223ae631f9a2a782fd6f51e9c
5
5
  SHA512:
6
- metadata.gz: 7125f6c9205f872a12574801bf5026073cd4d028640afbaefdf2a2ee69f11cc832167d4612341c475605306705af0742bb724fc241f482c85af8fe1e8a4f61d1
7
- data.tar.gz: 9217eca73420740086db7877bd5ff05e024ece6f6ecda1ad0d6b30e50cb1966da733b32f3daab8518a1180d25c6a0de1a8c7dab4105e132e186ae21a956e419b
6
+ metadata.gz: 004cfdf5b89a512e9c48e4d10d2fca603c8b59f6e8564bd35544b6c0d8915f1c07404d2358f9bd32468ac5cf7f13a1859f0ab9e7ada4e24bb67cc1dbd0da60fa
7
+ data.tar.gz: b7be41bd51be17ec5737463157fdf1fae4de250dda739c3074bf21931fe97e3589a9b3724400f87a9082f0e7c6c3b5247510f739fad5edf76d9d4a183fb2c64b
@@ -3,7 +3,7 @@ name: CI
3
3
  on:
4
4
  push:
5
5
  branches:
6
- - master
6
+ - main
7
7
  pull_request:
8
8
  branches:
9
9
  - '*'
@@ -13,11 +13,12 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- ruby-version: ['2.7.x', '3.0.x']
16
+ ruby-version: ['2.7.x', '3.0.x', '3.1.x']
17
17
  steps:
18
- - name: Set up Ruby
19
- uses: actions/setup-ruby@v1
20
- - uses: actions/checkout@v1
18
+ - uses: actions/checkout@v3
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
21
22
  - name: Install dependencies
22
23
  run: |
23
24
  gem --version
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.6
2
+ TargetRubyVersion: 2.7
3
3
 
4
4
  Style/ConditionalAssignment:
5
5
  Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.2
data/Gemfile CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'rake'
5
+ gem 'ech_config'
6
6
 
7
7
  group :test do
8
8
  gem 'byebug'
9
- gem 'rspec', '3.9.0'
10
- gem 'rubocop', '0.78.0'
9
+ gem 'rake'
10
+ gem 'rspec', '3.11'
11
+ gem 'rubocop', '1.35'
11
12
  end
12
13
 
13
14
  gemspec
data/README.md CHANGED
@@ -6,16 +6,16 @@
6
6
 
7
7
  `svcb_rr_patch` is the patch that adds SVCB Resource Record and HTTPS Resource Record.
8
8
 
9
- - https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-06
9
+ - https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-06.html
10
10
 
11
- `svcb_rr_patch` supports "ech" SvcParamKey that ECHConfig.version is `0xfe0d`.
11
+ `svcb_rr_patch` supports "ech" SvcParamKey that ECHConfig.version is `0xfe0b` ~ `0xfe0f`.
12
12
 
13
- - https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-13#section-4
13
+ - https://author-tools.ietf.org/iddiff?url2=draft-ietf-tls-esni-11.txt#context-3
14
14
 
15
15
 
16
16
  ## Installation
17
17
 
18
- he gem is available at [rubygems.org](https://rubygems.org/gems/svcb_rr_patch). You can install it the following.
18
+ The gem is available at [rubygems.org](https://rubygems.org/gems/svcb_rr_patch). You can install it the following.
19
19
 
20
20
  ```sh-session
21
21
  $ gem install svcb_rr_patch
@@ -26,20 +26,19 @@ $ gem install svcb_rr_patch
26
26
 
27
27
  You can resolve HTTPS resources.
28
28
 
29
- ```sh-session
29
+ ```ruby
30
30
  $ irb
31
31
  irb(main):001:0> require 'svcb_rr_patch'
32
32
  => true
33
- irb(main):002:1* Resolv::DNS.new.getresources(
34
- irb(main):003:1* "blog.cloudflare.com",
33
+ irb(main):002:1* rr = Resolv::DNS.new.getresources(
34
+ irb(main):003:1* "crypto.cloudflare.com",
35
35
  irb(main):004:1* Resolv::DNS::Resource::IN::HTTPS
36
36
  irb(main):005:0> )
37
37
  =>
38
- [#<Resolv::DNS::Resource::IN::HTTPS:0x0000000000000001
39
- @svc_params={"alpn"=>h3,h3-29,h3-28,h3-27,h2, "ipv4hint"=>104.18.26.46,104.18.27.46, "ipv6hint"=>2606:4700::6812:1a2e,2606:4700::6812:1b2e},
40
- @svc_priority=1,
41
- @target_name="",
42
- @ttl=300>]
38
+ [#<Resolv::DNS::Resource::IN::HTTPS:0x0000000000000000
39
+ ...
40
+ irb(main):006:0> rr.first.svc_params.to_s
41
+ => "alpn=http/1.1,h2 ipv4hint=162.159.137.85,162.159.138.85 ech=AEb+DQBC4wAgACCaqAJAAhqN4e1k2RSa+rFgJCpJNOapZy5FdQZUN5ITXAAEAAEAAQATY2xvdWRmbGFyZS1lc25pLmNvbQAA ipv6hint=2606:4700:7::a29f:8955,2606:4700:7::a29f:8a55"
43
42
  ```
44
43
 
45
44
 
@@ -8,11 +8,6 @@ class Resolv::DNS::Resource::IN::HTTPS < Resolv::DNS::Resource::IN::SVCB
8
8
  ClassValue = IN::ClassValue
9
9
  ClassHash[[TypeValue, ClassValue]] = self
10
10
 
11
- def initialize(svc_priority, target_name, svc_params)
12
- # https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-06
13
- super(svc_priority, target_name, svc_params)
14
- end
15
-
16
11
  class << self
17
12
  # :nodoc:
18
13
  def decode_rdata(msg)
@@ -21,7 +16,7 @@ class Resolv::DNS::Resource::IN::HTTPS < Resolv::DNS::Resource::IN::SVCB
21
16
  return new(svc_priority, target_name, {}) if svc_priority.zero?
22
17
 
23
18
  # the SvcParams, consuming the remainder of the record
24
- svc_params = ::SvcbRrPatch::SvcParams.decode(msg.get_bytes)
19
+ svc_params = ::SvcbRrPatch::SvcParams::Hash.decode(msg.get_bytes)
25
20
  new(svc_priority, target_name, svc_params)
26
21
  end
27
22
  end
@@ -37,7 +37,7 @@ class SvcbRrPatch::SvcParams::Alpn
37
37
  end
38
38
 
39
39
  # :nodoc:
40
- def inspect
40
+ def to_s
41
41
  @protocols.join(',')
42
42
  end
43
43
  end
@@ -18,56 +18,19 @@ class SvcbRrPatch::SvcParams::Ech
18
18
  raise ::Resolv::DNS::DecodeError \
19
19
  unless octet.length == octet.slice(0, 2).unpack1('n') + 2
20
20
 
21
- echconfiglist = ECHConfig.decode_vectors(octet.slice(2..))
21
+ begin
22
+ echconfiglist = ::ECHConfig.decode_vectors(octet.slice(2..))
23
+ rescue ::ECHConfig::Error
24
+ raise ::Resolv::DNS::DecodeError
25
+ end
26
+
22
27
  new(echconfiglist)
23
28
  end
24
29
 
25
- # https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-06#section-9
30
+ # https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-06.html#section-9
26
31
  # In presentation format, the value is a single ECHConfigList encoded in
27
32
  # Base64.
28
- def inspect
33
+ def to_s
29
34
  Base64.strict_encode64(encode)
30
35
  end
31
36
  end
32
-
33
- require_relative 'ech/echconfig_contents'
34
-
35
- class SvcbRrPatch::SvcParams::Ech::ECHConfig
36
- attr_reader :version
37
- attr_reader :echconfigcontents
38
-
39
- ECHConfigContents = ::SvcbRrPatch::SvcParams::Ech::ECHConfigContents
40
-
41
- # @param version [String]
42
- # @param echconfig_contents [ECHConfigContents]
43
- def initialize(version, echconfig_contents)
44
- @version = version
45
- @echconfig_contents = echconfig_contents
46
- end
47
-
48
- # @return [String]
49
- def encode
50
- @version + @echconfig_contents.encode.then { |s| [s.length].pack('n') + s }
51
- end
52
-
53
- # @return [Array of ECHConfig]
54
- def self.decode_vectors(octet)
55
- i = 0
56
- echconfigs = []
57
- while i < octet.length
58
- raise ::Resolv::DNS::DecodeError if i + 4 > octet.length
59
-
60
- version = octet.slice(i, 2)
61
- length = octet.slice(i + 2, 2).unpack1('n')
62
- i += 4
63
- raise ::Resolv::DNS::DecodeError if i + length > octet.length
64
-
65
- echconfig_contents = ECHConfigContents.decode(octet.slice(i, length))
66
- i += length
67
- echconfigs << new(version, echconfig_contents)
68
- end
69
- raise ::Resolv::DNS::DecodeError if i != octet.length
70
-
71
- echconfigs
72
- end
73
- end
@@ -20,7 +20,7 @@ class SvcbRrPatch::SvcParams::Ipv4hint
20
20
  end
21
21
 
22
22
  # :nodoc:
23
- def inspect
23
+ def to_s
24
24
  @addresses.join(',')
25
25
  end
26
26
  end
@@ -20,7 +20,7 @@ class SvcbRrPatch::SvcParams::Ipv6hint
20
20
  end
21
21
 
22
22
  # :nodoc:
23
- def inspect
23
+ def to_s
24
24
  @addresses.join(',')
25
25
  end
26
26
  end
@@ -17,18 +17,12 @@ class SvcbRrPatch::SvcParams::Mandatory
17
17
  def self.decode(octet)
18
18
  keys = octet.scan(/.{1,2}/)
19
19
  .map { |s| s.unpack1('n') }
20
- .filter { |i| i < 7 || i >= 65280 && i < 65535 }
21
20
  new(keys)
22
21
  end
23
22
 
24
23
  # :nodoc:
25
- def inspect
26
- @keys.map do |i|
27
- if i < 7 || i >= 65280 && i < 65535
28
- SvcbRrPatch::SvcParams::PARAMETER_REGISTRY[i]
29
- else
30
- ''
31
- end
32
- end.join(',')
24
+ def to_s
25
+ @keys.map { |i| SvcbRrPatch::SvcParams::PARAMETER_REGISTRY[i] }
26
+ .join(',')
33
27
  end
34
28
  end
@@ -20,7 +20,7 @@ class SvcbRrPatch::SvcParams::Port
20
20
  end
21
21
 
22
22
  # :nodoc:
23
- def inspect
23
+ def to_s
24
24
  @port.to_s
25
25
  end
26
26
  end
@@ -12,23 +12,32 @@ module SvcbRrPatch::SvcParams
12
12
  ipv6hint
13
13
  ]
14
14
  # rubocop:disable Security/Eval
15
+ (8...65280).each do |nnnn|
16
+ eval "registry[nnnn] = \"undefine#{nnnn}\"", binding, __FILE__, __LINE__
17
+ end
15
18
  (65280...65535).each do |nnnn|
16
19
  eval "registry[nnnn] = \"key#{nnnn}\"", binding, __FILE__, __LINE__
17
20
  end
18
21
  # rubocop:enable Security/Eval
19
22
  registry
20
23
  }.call.freeze
24
+
25
+ PARAMETER_REGISTRY_INVERT = lambda {
26
+ Hash[(0..PARAMETER_REGISTRY.size - 1).zip(PARAMETER_REGISTRY)].invert
27
+ }.call.freeze
21
28
  end
22
29
 
23
- Dir[File.dirname(__FILE__) + '/svc_params/*.rb'].sort.each { |f| require f }
30
+ Dir["#{File.dirname(__FILE__)}/svc_params/*.rb"].sort.each { |f| require f }
24
31
 
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
32
+ class SvcbRrPatch::SvcParams::Hash
33
+ def initialize(hash)
34
+ @hash = hash
35
+ end
29
36
 
30
- svc_params
31
- .map { |k, v| [h[k], v] }
37
+ # @return [String]
38
+ def encode
39
+ @hash
40
+ .map { |k, v| [SvcbRrPatch::SvcParams::PARAMETER_REGISTRY_INVERT[k], v] }
32
41
  .sort { |lh, rh| lh.first <=> rh.first }
33
42
  .map do |k, v|
34
43
  [k].pack('n') + v.encode.then { |s| [s.length].pack('n') + s }
@@ -38,19 +47,18 @@ module SvcbRrPatch::SvcParams
38
47
 
39
48
  # @param octet [String]
40
49
  #
41
- # @return [Hash] Integer => SvcbRrPatch::$Object
42
- # rubocop:disable Metrics/AbcSize
50
+ # @return [Hash]
43
51
  def self.decode(octet)
44
52
  svc_params = {}
45
53
  i = 0
46
- h = Hash[(0..PARAMETER_REGISTRY.size - 1).zip(PARAMETER_REGISTRY)].invert
47
54
  while i < octet.length
48
55
  raise ::Resolv::DNS::DecodeError if i + 4 > octet.length
49
56
 
50
57
  k = octet.slice(i, 2).unpack1('n')
51
58
  # SvcParamKeys SHALL appear in increasing numeric order.
52
- raise ::Resolv::DNS::DecodeError \
53
- unless svc_params.keys.find { |already| h[already] >= k }.nil?
59
+ raise ::Resolv::DNS::DecodeError unless svc_params.keys.find do |key|
60
+ SvcbRrPatch::SvcParams::PARAMETER_REGISTRY_INVERT[key] >= k
61
+ end.nil?
54
62
 
55
63
  i += 2
56
64
  vlen = octet.slice(i, 2).unpack1('n')
@@ -60,37 +68,51 @@ module SvcbRrPatch::SvcParams
60
68
  v = octet.slice(i, vlen)
61
69
  i += vlen
62
70
  # Values are in a format specific to the SvcParamKey.
63
- svc_param_key = PARAMETER_REGISTRY[k]
71
+ svc_param_key = SvcbRrPatch::SvcParams::PARAMETER_REGISTRY[k]
64
72
  svc_param_values = decode_svc_params(svc_param_key, v)
65
73
  svc_params.store(svc_param_key, svc_param_values)
66
74
  end
67
75
  raise ::Resolv::DNS::DecodeError if i != octet.length
68
76
 
69
- svc_params
77
+ new(svc_params)
70
78
  end
71
- # rubocop:enable Metrics/AbcSize
72
79
 
73
80
  # :nodoc:
74
81
  # rubocop:disable Metrics/CyclomaticComplexity
75
82
  def self.decode_svc_params(key, octet)
76
83
  case key
77
84
  when 'mandatory'
78
- Mandatory.decode(octet)
85
+ SvcbRrPatch::SvcParams::Mandatory.decode(octet)
79
86
  when 'alpn'
80
- Alpn.decode(octet)
87
+ SvcbRrPatch::SvcParams::Alpn.decode(octet)
81
88
  when 'no-default-alpn'
82
- NoDefaultAlpn.decode(octet)
89
+ SvcbRrPatch::SvcParams::NoDefaultAlpn.decode(octet)
83
90
  when 'port'
84
- Port.decode(octet)
91
+ SvcbRrPatch::SvcParams::Port.decode(octet)
85
92
  when 'ipv4hint'
86
- Ipv4hint.decode(octet)
93
+ SvcbRrPatch::SvcParams::Ipv4hint.decode(octet)
87
94
  when 'ech'
88
- Ech.decode(octet)
95
+ SvcbRrPatch::SvcParams::Ech.decode(octet)
89
96
  when 'ipv6hint'
90
- Ipv6hint.decode(octet)
97
+ SvcbRrPatch::SvcParams::Ipv6hint.decode(octet)
91
98
  else
92
99
  octet
93
100
  end
94
101
  end
95
102
  # rubocop:enable Metrics/CyclomaticComplexity
103
+
104
+ # :nodoc:
105
+ def [](key)
106
+ @hash[key]
107
+ end
108
+
109
+ # :nodoc:
110
+ def keys
111
+ @hash.keys
112
+ end
113
+
114
+ # :nodoc:
115
+ def to_s
116
+ @hash.map { |k, v| "#{k}=#{v}" }.join(' ')
117
+ end
96
118
  end
@@ -10,34 +10,32 @@ class Resolv::DNS::Resource::IN::SVCB < Resolv::DNS::Resource
10
10
 
11
11
  # @param svc_priority [Integer]
12
12
  # @param target_name [String]
13
- # @param svc_params [Map]
13
+ # @param svc_params [Hash]
14
+ # rubocop: disable Lint/MissingSuper
14
15
  def initialize(svc_priority, target_name, svc_params)
15
- # https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-06
16
+ # https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-06.html
16
17
  @svc_priority = svc_priority
17
18
  @target_name = target_name
18
19
  @svc_params = svc_params
19
20
  end
21
+ # rubocop: enable Lint/MissingSuper
20
22
 
21
23
  ##
22
24
  # SvcPriority
23
25
 
24
- attr_reader :svc_priority
26
+ attr_reader :svc_priority, :target_name, :svc_params
25
27
 
26
28
  ##
27
29
  # TargetName
28
30
 
29
- attr_reader :target_name
30
-
31
31
  ##
32
32
  # SvcParams
33
33
 
34
- attr_reader :svc_params
35
-
36
34
  # :nodoc:
37
35
  def encode_rdata(msg)
38
36
  msg.put_bytes([@svc_priority].pack('n'))
39
37
  msg.put_string(@target_name)
40
- msg.put_string(::SvcbRrPatch::SvcParams.encode(@svc_params))
38
+ msg.put_string(@svc_params.encode)
41
39
  end
42
40
 
43
41
  class << self
@@ -48,7 +46,7 @@ class Resolv::DNS::Resource::IN::SVCB < Resolv::DNS::Resource
48
46
  return new(svc_priority, target_name, {}) if svc_priority.zero?
49
47
 
50
48
  # the SvcParams, consuming the remainder of the record
51
- svc_params = ::SvcbRrPatch::SvcParams.decode(msg.get_bytes)
49
+ svc_params = ::SvcbRrPatch::SvcParams::Hash.decode(msg.get_bytes)
52
50
  new(svc_priority, target_name, svc_params)
53
51
  end
54
52
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SvcbRrPatch
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.6'
5
5
  end
data/lib/svcb_rr_patch.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'base64'
4
+ require 'ech_config'
4
5
  require 'resolv'
5
6
 
6
7
  require 'svcb_rr_patch/version'
data/spec/alpn_spec.rb CHANGED
@@ -25,7 +25,7 @@ RSpec.describe SvcbRrPatch::SvcParams::Alpn do
25
25
 
26
26
  it 'could encode' do
27
27
  expect(alpn.encode).to eq octet
28
- expect(alpn.inspect).to eq 'h3-29,h3-28,h3-27,h2'
28
+ expect(alpn.to_s).to eq 'h3-29,h3-28,h3-27,h2'
29
29
  end
30
30
  end
31
31
  end
@@ -33,7 +33,7 @@ RSpec.describe SvcbRrPatch::SvcParams::Ipv4hint do
33
33
 
34
34
  it 'could encode' do
35
35
  expect(ipv4hint.encode).to eq octet
36
- expect(ipv4hint.inspect).to eq '192.0.2.1,192.0.2.2'
36
+ expect(ipv4hint.to_s).to eq '192.0.2.1,192.0.2.2'
37
37
  end
38
38
  end
39
39
  end
@@ -36,7 +36,7 @@ RSpec.describe SvcbRrPatch::SvcParams::Ipv6hint do
36
36
 
37
37
  it 'could encode' do
38
38
  expect(ipv6hint.encode).to eq octet
39
- expect(ipv6hint.inspect).to eq '2001:db8::1,2001:db8::2'
39
+ expect(ipv6hint.to_s).to eq '2001:db8::1,2001:db8::2'
40
40
  end
41
41
  end
42
42
  end
@@ -5,16 +5,16 @@ require_relative 'spec_helper'
5
5
 
6
6
  RSpec.describe SvcbRrPatch::SvcParams::Mandatory do
7
7
  let(:octet) do
8
- "\x00\x05\x00\x06\xff\xa4"
8
+ "\x00\x05\x00\x06\x00\x08\xff\xa4"
9
9
  end
10
10
 
11
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['ipv6hint'], h['key65444']]
12
+ [
13
+ SvcbRrPatch::SvcParams::PARAMETER_REGISTRY_INVERT['ech'],
14
+ SvcbRrPatch::SvcParams::PARAMETER_REGISTRY_INVERT['ipv6hint'],
15
+ SvcbRrPatch::SvcParams::PARAMETER_REGISTRY_INVERT['undefine8'],
16
+ SvcbRrPatch::SvcParams::PARAMETER_REGISTRY_INVERT['key65444']
17
+ ]
18
18
  end
19
19
 
20
20
  context '#decode' do
@@ -34,7 +34,7 @@ RSpec.describe SvcbRrPatch::SvcParams::Mandatory do
34
34
 
35
35
  it 'could encode' do
36
36
  expect(mandatory.encode).to eq octet
37
- expect(mandatory.inspect).to eq 'ech,ipv6hint,key65444'
37
+ expect(mandatory.to_s).to eq 'ech,ipv6hint,undefine8,key65444'
38
38
  end
39
39
  end
40
40
  end
@@ -30,7 +30,7 @@ RSpec.describe SvcbRrPatch::SvcParams::NoDefaultAlpn do
30
30
  expect(no_default_alpn)
31
31
  .to be_a(SvcbRrPatch::SvcParams::NoDefaultAlpn)
32
32
  expect(no_default_alpn.encode).to eq octet
33
- expect(no_default_alpn.inspect).to eq 'h3-29,h3-28,h3-27,h2'
33
+ expect(no_default_alpn.to_s).to eq 'h3-29,h3-28,h3-27,h2'
34
34
  end
35
35
  end
36
36
  end
data/spec/port_spec.rb CHANGED
@@ -25,7 +25,7 @@ RSpec.describe SvcbRrPatch::SvcParams::Port do
25
25
 
26
26
  it 'could encode' do
27
27
  expect(port.encode).to eq octet
28
- expect(port.inspect).to eq '443'
28
+ expect(port.to_s).to eq '443'
29
29
  end
30
30
  end
31
31
  end
@@ -45,7 +45,7 @@ RSpec.describe SvcbRrPatch::SvcParams do
45
45
 
46
46
  context '#decode' do
47
47
  let(:svc_params) do
48
- SvcbRrPatch::SvcParams.decode(octet)
48
+ SvcbRrPatch::SvcParams::Hash.decode(octet)
49
49
  end
50
50
 
51
51
  it 'could decode' do
@@ -60,16 +60,17 @@ RSpec.describe SvcbRrPatch::SvcParams do
60
60
 
61
61
  context '#encode' do
62
62
  let(:svc_params) do
63
- {
63
+ h = {
64
64
  'alpn' => alpn,
65
65
  'ipv4hint' => ipv4hint,
66
66
  'ipv6hint' => ipv6hint,
67
67
  'key65333' => key65333
68
68
  }
69
+ SvcbRrPatch::SvcParams::Hash.new(h)
69
70
  end
70
71
 
71
72
  it 'could encode' do
72
- expect(SvcbRrPatch::SvcParams.encode(svc_params)).to eq octet
73
+ expect(svc_params.encode).to eq octet
73
74
  end
74
75
  end
75
76
  end
@@ -14,11 +14,12 @@ Gem::Specification.new do |spec|
14
14
  spec.description = spec.summary
15
15
  spec.homepage = 'https://github.com/thekuwayama/svcb_rr_patch'
16
16
  spec.license = 'MIT'
17
- spec.required_ruby_version = '>=2.6.0'
17
+ spec.required_ruby_version = '>=2.7.0'
18
18
 
19
19
  spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = ['lib']
22
22
 
23
23
  spec.add_development_dependency 'bundler'
24
+ spec.add_dependency 'ech_config'
24
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: svcb_rr_patch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - thekuwayama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-12 00:00:00.000000000 Z
11
+ date: 2023-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ech_config
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  description: the patch that adds SVCB Resource Record and HTTPS Resource Record
28
42
  email:
29
43
  - thekuwayama@gmail.com
@@ -34,6 +48,7 @@ files:
34
48
  - ".github/workflows/ci.yml"
35
49
  - ".gitignore"
36
50
  - ".rubocop.yml"
51
+ - ".ruby-version"
37
52
  - Gemfile
38
53
  - LICENSE.txt
39
54
  - README.md
@@ -43,14 +58,6 @@ files:
43
58
  - lib/svcb_rr_patch/svc_params.rb
44
59
  - lib/svcb_rr_patch/svc_params/alpn.rb
45
60
  - 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
61
  - lib/svcb_rr_patch/svc_params/ipv4hint.rb
55
62
  - lib/svcb_rr_patch/svc_params/ipv6hint.rb
56
63
  - lib/svcb_rr_patch/svc_params/mandatory.rb
@@ -79,14 +86,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
86
  requirements:
80
87
  - - ">="
81
88
  - !ruby/object:Gem::Version
82
- version: 2.6.0
89
+ version: 2.7.0
83
90
  required_rubygems_version: !ruby/object:Gem::Requirement
84
91
  requirements:
85
92
  - - ">="
86
93
  - !ruby/object:Gem::Version
87
94
  version: '0'
88
95
  requirements: []
89
- rubygems_version: 3.2.22
96
+ rubygems_version: 3.3.7
90
97
  signing_key:
91
98
  specification_version: 4
92
99
  summary: the patch that adds SVCB Resource Record and HTTPS Resource Record
@@ -1,34 +0,0 @@
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
@@ -1,22 +0,0 @@
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
@@ -1,20 +0,0 @@
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
@@ -1,22 +0,0 @@
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
@@ -1,22 +0,0 @@
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
@@ -1,41 +0,0 @@
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
@@ -1,77 +0,0 @@
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
@@ -1,69 +0,0 @@
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('C') \
34
- + @public_name.then { |s| [s.length].pack('C') + s } \
35
- + @extensions.map(&:encode).join.then { |s| [s.length].pack('n') + s }
36
- end
37
-
38
- # :nodoc
39
- # rubocop:disable Metrics/AbcSize
40
- def self.decode(octet)
41
- key_config, octet = HpkeKeyConfig.decode(octet)
42
- raise ::Resolv::DNS::DecodeError if octet.length < 2
43
-
44
- maximum_name_length = octet.slice(0, 1).unpack1('C')
45
- pn_len = octet.slice(1, 1).unpack1('C')
46
- i = 2
47
- raise ::Resolv::DNS::DecodeError if i + pn_len > octet.length
48
-
49
- public_name = octet.slice(i, pn_len)
50
- i += pn_len
51
- raise ::Resolv::DNS::DecodeError if i + 2 > octet.length
52
-
53
- ex_len = octet.slice(i, 2).unpack1('n')
54
- i += 2
55
- raise ::Resolv::DNS::DecodeError if i + ex_len > octet.length
56
-
57
- extensions = Extension.decode_vectors(octet.slice(i, ex_len))
58
- i += ex_len
59
- raise ::Resolv::DNS::DecodeError if i != octet.length
60
-
61
- new(
62
- key_config,
63
- maximum_name_length,
64
- public_name,
65
- extensions
66
- )
67
- end
68
- # rubocop:enable Metrics/AbcSize
69
- end