resolv 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82cf1416dbd548bac4a243078cb8b93a0990f906169eff49752840d3145d0a0a
4
- data.tar.gz: baf98405285dd3a553873a2f10e20d188e1e73cf066bf5f430b8d206c553978f
3
+ metadata.gz: 56680c64e918a60193f43e3ca4a7093db20bbe66f516da79a159d9a3c05860d8
4
+ data.tar.gz: f017a2c89fbcdf946b69ce57d41a67537b73f54ec6e99d18cc62865fd6ec1633
5
5
  SHA512:
6
- metadata.gz: 646bccbb40a992224d079ddd8a586a231a69f67f628d424f79e1079dce4fcc346254ec0288d874ec356e199cfffb5c694b0cea8b51ed2435299a72ec29d88759
7
- data.tar.gz: 28f34daddd2b5e3262e1b6b4381933c40683c8938129efad0914d495ae522f0c0b53bcbd6108073c1b3b1b4beb7f67d5e8af4b2af17387812c7275bed11c696d
6
+ metadata.gz: d57f866a30bc2b8da6dbcdb8c65d0a5db4630af4ec0244aa490e37370ba7b27c3031e153e76055e7f4f63114bd477944326b05dbb7319f97bf59478f8518d76a
7
+ data.tar.gz: f07e85287b3bb9973c90900c1fbdc272e193d91493e63b407e696cc9f52de29fc0716f2ec11aba56d37d89a12b6d3fec55d21bd8ce756f02d56577940c454b06
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -0,0 +1,31 @@
1
+ name: test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ ruby-versions:
7
+ uses: ruby/actions/.github/workflows/ruby_versions.yml@master
8
+ with:
9
+ engine: cruby
10
+ min_version: 2.5
11
+
12
+ build:
13
+ needs: ruby-versions
14
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
15
+ strategy:
16
+ matrix:
17
+ ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
18
+ os: [ ubuntu-latest, macos-latest, windows-latest ]
19
+ include:
20
+ - ruby: mswin
21
+ os: windows-latest
22
+ runs-on: ${{ matrix.os }}
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - name: Set up Ruby
26
+ uses: ruby/setup-ruby@v1
27
+ with:
28
+ ruby-version: ${{ matrix.ruby }}
29
+ bundler-cache: true
30
+ - name: Run test
31
+ run: bundle exec rake test
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake"
6
+ gem "test-unit"
7
+ gem "test-unit-ruby-core"
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.ruby_opts << "-rhelper"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "resolv"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/resolv.rb CHANGED
@@ -37,7 +37,7 @@ end
37
37
 
38
38
  class Resolv
39
39
 
40
- VERSION = "0.3.2"
40
+ VERSION = "0.4.0"
41
41
 
42
42
  ##
43
43
  # Looks up the first IP address for +name+.
@@ -194,17 +194,10 @@ class Resolv
194
194
  File.open(@filename, 'rb') {|f|
195
195
  f.each {|line|
196
196
  line.sub!(/#.*/, '')
197
- addr, hostname, *aliases = line.split(/\s+/)
197
+ addr, *hostnames = line.split(/\s+/)
198
198
  next unless addr
199
- @addr2name[addr] = [] unless @addr2name.include? addr
200
- @addr2name[addr] << hostname
201
- @addr2name[addr].concat(aliases)
202
- @name2addr[hostname] = [] unless @name2addr.include? hostname
203
- @name2addr[hostname] << addr
204
- aliases.each {|n|
205
- @name2addr[n] = [] unless @name2addr.include? n
206
- @name2addr[n] << addr
207
- }
199
+ (@addr2name[addr] ||= []).concat(hostnames)
200
+ hostnames.each {|hostname| (@name2addr[hostname] ||= []) << addr}
208
201
  }
209
202
  }
210
203
  @name2addr.each {|name, arr| arr.reverse!}
@@ -1219,13 +1212,6 @@ class Resolv
1219
1212
 
1220
1213
  class Str # :nodoc:
1221
1214
  def initialize(string)
1222
- # A label is limited to 63 octets. [RFC 1035 2.3.4] Checking it here
1223
- # makes it an invariant of the object: every label, however it was
1224
- # built, fits in its length octet and cannot wrap it. Callers turn
1225
- # this into the error their own contract promises.
1226
- if string.bytesize > 63
1227
- raise ArgumentError, "DNS label is too long (#{string.bytesize} bytes, max 63): #{string.inspect}"
1228
- end
1229
1215
  @string = string
1230
1216
  # case insensivity of DNS labels doesn't apply non-ASCII characters. [RFC 4343]
1231
1217
  # This assumes @string is given in ASCII compatible encoding.
@@ -1271,26 +1257,7 @@ class Resolv
1271
1257
  when Name
1272
1258
  return arg
1273
1259
  when String
1274
- # A hostname is runtime data rather than a programming mistake, so
1275
- # both size limits surface as ResolvError to stay rescuable alongside
1276
- # the rest of name resolution. The type check below is a caller
1277
- # mistake and keeps raising ArgumentError.
1278
- begin
1279
- labels = Label.split(arg)
1280
- rescue ArgumentError => e
1281
- raise ResolvError.new(e.message)
1282
- end
1283
- # Label::Str enforces the per-label limit. Only the total is knowable
1284
- # here, and it counts the encoded form, so size starts at 1 for the
1285
- # root label's terminating zero octet. [RFC 1035 2.3.4, 3.1]
1286
- size = 1
1287
- labels.each do |label|
1288
- size += 1 + label.string.bytesize
1289
- if size > 255
1290
- raise ResolvError.new("DNS name is too long (#{size} octets, max 255): #{arg.inspect}")
1291
- end
1292
- end
1293
- return Name.new(labels, /\.\z/ =~ arg ? true : false)
1260
+ return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
1294
1261
  else
1295
1262
  raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
1296
1263
  end
@@ -1412,24 +1379,12 @@ class Resolv
1412
1379
  @rd == other.rd &&
1413
1380
  @ra == other.ra &&
1414
1381
  @rcode == other.rcode &&
1415
- question_equal?(other.question) &&
1382
+ @question == other.question &&
1416
1383
  @answer == other.answer &&
1417
1384
  @authority == other.authority &&
1418
1385
  @additional == other.additional
1419
1386
  end
1420
1387
 
1421
- # A question holds the resource class itself, and decoding creates a fresh
1422
- # class for each unknown type, so the classes cannot be compared by
1423
- # identity alone.
1424
- private def question_equal?(other_question) # :nodoc:
1425
- return false unless @question.length == other_question.length
1426
- @question.zip(other_question) {|(name, typeclass), (o_name, o_typeclass)|
1427
- return false unless name == o_name &&
1428
- Resource::Generic.type_class_equal?(typeclass, o_typeclass)
1429
- }
1430
- return true
1431
- end
1432
-
1433
1388
  def add_question(name, typeclass)
1434
1389
  @question << [Name.create(name), typeclass]
1435
1390
  end
@@ -1536,15 +1491,8 @@ class Resolv
1536
1491
  end
1537
1492
 
1538
1493
  def put_string(d)
1539
- s = d.to_s
1540
- # A character-string is prefixed by a single length octet, so it can
1541
- # hold at most 255 octets. [RFC 1035 3.3] Reject anything longer to
1542
- # avoid silently truncating the length to its low 8 bits (mod 256).
1543
- if s.bytesize > 255
1544
- raise ArgumentError, "character-string is too long (#{s.bytesize} bytes, max 255): #{s.inspect}"
1545
- end
1546
- self.put_pack("C", s.bytesize)
1547
- @data << s
1494
+ self.put_pack("C", d.length)
1495
+ @data << d
1548
1496
  end
1549
1497
 
1550
1498
  def put_string_list(ds)
@@ -1574,17 +1522,7 @@ class Resolv
1574
1522
  end
1575
1523
 
1576
1524
  def put_label(d)
1577
- s = d.to_s
1578
- # Label::Str applies this limit when a label is built, so what is left
1579
- # for here is a raw string handed straight to put_labels. The two ways
1580
- # an over-long label goes wrong differ: 64 to 255 octets write a length
1581
- # octet in the reserved or compression pointer range, and 256 or more
1582
- # wrap it mod 256. Either way the encoded name stops being the name the
1583
- # caller asked for. [RFC 1035 2.3.4, 4.1.4]
1584
- if s.bytesize > 63
1585
- raise ArgumentError, "DNS label is too long (#{s.bytesize} bytes, max 63): #{s.inspect}"
1586
- end
1587
- self.put_string(s)
1525
+ self.put_string(d.to_s)
1588
1526
  end
1589
1527
  end
1590
1528
 
@@ -1710,9 +1648,6 @@ class Resolv
1710
1648
  prev_index = @index
1711
1649
  save_index = nil
1712
1650
  d = []
1713
- # size counts the encoded form, so it starts at 1 for the root
1714
- # label's terminating zero octet. [RFC 1035 3.1]
1715
- size = 1
1716
1651
  while true
1717
1652
  raise DecodeError.new("limit exceeded") if @limit <= @index
1718
1653
  case @data.getbyte(@index)
@@ -1733,21 +1668,13 @@ class Resolv
1733
1668
  end
1734
1669
  @index = idx
1735
1670
  else
1736
- l = self.get_label
1737
- d << l
1738
- size += 1 + l.string.bytesize
1739
- raise DecodeError.new("name label data exceed 255 octets") if size > 255
1671
+ d << self.get_label
1740
1672
  end
1741
1673
  end
1742
1674
  end
1743
1675
 
1744
1676
  def get_label
1745
1677
  return Label::Str.new(self.get_string)
1746
- rescue ArgumentError => e
1747
- # A length octet of 64..191 is reserved rather than a label length,
1748
- # but this decoder used to read it as one. [RFC 1035 4.1.4] Report it
1749
- # the way the rest of a malformed message is reported.
1750
- raise DecodeError.new(e.message)
1751
1678
  end
1752
1679
 
1753
1680
  def get_question
@@ -1936,9 +1863,8 @@ class Resolv
1936
1863
  key_name = :"key#{key_number}"
1937
1864
  c.const_set(:KeyName, key_name)
1938
1865
  c.const_set(:KeyNumber, key_number)
1939
- # Not registered in a constant or in ClassHash. ClassHash creates a
1940
- # class for every unknown SvcParamKey, so registering them
1941
- # permanently would let a malicious response exhaust memory.
1866
+ self.const_set(:"Key#{key_number}", c)
1867
+ ClassHash[key_name] = ClassHash[key_number] = c
1942
1868
  return c
1943
1869
  end
1944
1870
  end
@@ -2236,28 +2162,12 @@ class Resolv
2236
2162
  return self.new(msg.get_bytes)
2237
2163
  end
2238
2164
 
2239
- # create makes a fresh class for each decoded resource, so the type and
2240
- # class values have to be compared instead of the class itself.
2241
- def self.type_class_equal?(klass, other) # :nodoc:
2242
- return true if klass.equal?(other)
2243
- Generic > klass && Generic > other &&
2244
- klass::TypeValue == other::TypeValue &&
2245
- klass::ClassValue == other::ClassValue
2246
- end
2247
-
2248
- def ==(other) # :nodoc:
2249
- return other.is_a?(Generic) &&
2250
- Generic.type_class_equal?(self.class, other.class) &&
2251
- @data == other.data
2252
- end
2253
-
2254
2165
  def self.create(type_value, class_value) # :nodoc:
2255
2166
  c = Class.new(Generic)
2256
2167
  c.const_set(:TypeValue, type_value)
2257
2168
  c.const_set(:ClassValue, class_value)
2258
- # Not registered in a constant or in ClassHash. get_class creates a
2259
- # class for every unknown (type, class) pair, so registering them
2260
- # permanently would let a malicious response exhaust memory.
2169
+ Generic.const_set("Type#{type_value}_Class#{class_value}", c)
2170
+ ClassHash[[type_value, class_value]] = c
2261
2171
  return c
2262
2172
  end
2263
2173
  end
@@ -2627,8 +2537,70 @@ class Resolv
2627
2537
  TypeValue = 255 # :nodoc:
2628
2538
  end
2629
2539
 
2540
+ ##
2541
+ # CAA resource record defined in RFC 8659
2542
+ #
2543
+ # These records identify certificate authority allowed to issue
2544
+ # certificates for the given domain.
2545
+
2546
+ class CAA < Resource
2547
+ TypeValue = 257
2548
+
2549
+ ##
2550
+ # Creates a new CAA for +flags+, +tag+ and +value+.
2551
+
2552
+ def initialize(flags, tag, value)
2553
+ unless (0..255) === flags
2554
+ raise ArgumentError.new('flags must be an Integer between 0 and 255')
2555
+ end
2556
+ unless (1..15) === tag.bytesize
2557
+ raise ArgumentError.new('length of tag must be between 1 and 15')
2558
+ end
2559
+
2560
+ @flags = flags
2561
+ @tag = tag
2562
+ @value = value
2563
+ end
2564
+
2565
+ ##
2566
+ # Flags for this proprty:
2567
+ # - Bit 0 : 0 = not critical, 1 = critical
2568
+
2569
+ attr_reader :flags
2570
+
2571
+ ##
2572
+ # Property tag ("issue", "issuewild", "iodef"...).
2573
+
2574
+ attr_reader :tag
2575
+
2576
+ ##
2577
+ # Property value.
2578
+
2579
+ attr_reader :value
2580
+
2581
+ ##
2582
+ # Whether the critical flag is set on this property.
2583
+
2584
+ def critical?
2585
+ flags & 0x80 != 0
2586
+ end
2587
+
2588
+ def encode_rdata(msg) # :nodoc:
2589
+ msg.put_pack('C', @flags)
2590
+ msg.put_string(@tag)
2591
+ msg.put_bytes(@value)
2592
+ end
2593
+
2594
+ def self.decode_rdata(msg) # :nodoc:
2595
+ flags, = msg.get_unpack('C')
2596
+ tag = msg.get_string
2597
+ value = msg.get_bytes
2598
+ self.new flags, tag, value
2599
+ end
2600
+ end
2601
+
2630
2602
  ClassInsensitiveTypes = [ # :nodoc:
2631
- NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY
2603
+ NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY, CAA
2632
2604
  ]
2633
2605
 
2634
2606
  ##
@@ -2854,7 +2826,7 @@ class Resolv
2854
2826
  attr_reader :target
2855
2827
 
2856
2828
  ##
2857
- # The service paramters for the target host.
2829
+ # The service parameters for the target host.
2858
2830
 
2859
2831
  attr_reader :params
2860
2832
 
data/resolv.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ name = File.basename(__FILE__, ".gemspec")
2
+ version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
3
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
4
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
5
+ end rescue nil
6
+ end
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = name
10
+ spec.version = version
11
+ spec.authors = ["Tanaka Akira"]
12
+ spec.email = ["akr@fsij.org"]
13
+
14
+ spec.summary = %q{Thread-aware DNS resolver library in Ruby.}
15
+ spec.description = %q{Thread-aware DNS resolver library in Ruby.}
16
+ spec.homepage = "https://github.com/ruby/resolv"
17
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
18
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
19
+
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = spec.homepage
22
+
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = []
28
+ spec.require_paths = ["lib"]
29
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resolv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanaka Akira
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2024-03-19 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: Thread-aware DNS resolver library in Ruby.
13
13
  email:
@@ -16,9 +16,17 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - ".github/dependabot.yml"
20
+ - ".github/workflows/test.yml"
21
+ - ".gitignore"
22
+ - Gemfile
19
23
  - LICENSE.txt
20
24
  - README.md
25
+ - Rakefile
26
+ - bin/console
27
+ - bin/setup
21
28
  - lib/resolv.rb
29
+ - resolv.gemspec
22
30
  homepage: https://github.com/ruby/resolv
23
31
  licenses:
24
32
  - Ruby
@@ -40,7 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
40
48
  - !ruby/object:Gem::Version
41
49
  version: '0'
42
50
  requirements: []
43
- rubygems_version: 3.6.9
51
+ rubygems_version: 3.6.0.dev
44
52
  specification_version: 4
45
53
  summary: Thread-aware DNS resolver library in Ruby.
46
54
  test_files: []