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 +4 -4
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/test.yml +31 -0
- data/.gitignore +10 -0
- data/Gemfile +7 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/resolv.rb +78 -106
- data/resolv.gemspec +29 -0
- metadata +11 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 56680c64e918a60193f43e3ca4a7093db20bbe66f516da79a159d9a3c05860d8
|
|
4
|
+
data.tar.gz: f017a2c89fbcdf946b69ce57d41a67537b73f54ec6e99d18cc62865fd6ec1633
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d57f866a30bc2b8da6dbcdb8c65d0a5db4630af4ec0244aa490e37370ba7b27c3031e153e76055e7f4f63114bd477944326b05dbb7319f97bf59478f8518d76a
|
|
7
|
+
data.tar.gz: f07e85287b3bb9973c90900c1fbdc272e193d91493e63b407e696cc9f52de29fc0716f2ec11aba56d37d89a12b6d3fec55d21bd8ce756f02d56577940c454b06
|
|
@@ -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
data/Gemfile
ADDED
data/Rakefile
ADDED
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
data/lib/resolv.rb
CHANGED
|
@@ -37,7 +37,7 @@ end
|
|
|
37
37
|
|
|
38
38
|
class Resolv
|
|
39
39
|
|
|
40
|
-
VERSION = "0.
|
|
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,
|
|
197
|
+
addr, *hostnames = line.split(/\s+/)
|
|
198
198
|
next unless addr
|
|
199
|
-
@addr2name[addr]
|
|
200
|
-
@
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1540
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
1940
|
-
|
|
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
|
-
#
|
|
2259
|
-
|
|
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
|
|
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.
|
|
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:
|
|
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.
|
|
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: []
|