resolv 0.2.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/workflows/test.yml +13 -3
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/Rakefile +0 -7
- data/lib/resolv.rb +559 -27
- data/resolv.gemspec +9 -2
- metadata +3 -6
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
|
data/.github/workflows/test.yml
CHANGED
@@ -3,15 +3,25 @@ name: test
|
|
3
3
|
on: [push, pull_request]
|
4
4
|
|
5
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
|
+
|
6
12
|
build:
|
13
|
+
needs: ruby-versions
|
7
14
|
name: build (${{ matrix.ruby }} / ${{ matrix.os }})
|
8
15
|
strategy:
|
9
16
|
matrix:
|
10
|
-
ruby:
|
11
|
-
os: [ ubuntu-latest, macos-latest ]
|
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
|
12
22
|
runs-on: ${{ matrix.os }}
|
13
23
|
steps:
|
14
|
-
- uses: actions/checkout@
|
24
|
+
- uses: actions/checkout@v4
|
15
25
|
- name: Set up Ruby
|
16
26
|
uses: ruby/setup-ruby@v1
|
17
27
|
with:
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -7,11 +7,4 @@ Rake::TestTask.new(:test) do |t|
|
|
7
7
|
t.test_files = FileList["test/**/test_*.rb"]
|
8
8
|
end
|
9
9
|
|
10
|
-
task :sync_tool do
|
11
|
-
require 'fileutils'
|
12
|
-
FileUtils.cp "../ruby/tool/lib/core_assertions.rb", "./test/lib"
|
13
|
-
FileUtils.cp "../ruby/tool/lib/envutil.rb", "./test/lib"
|
14
|
-
FileUtils.cp "../ruby/tool/lib/find_executable.rb", "./test/lib"
|
15
|
-
end
|
16
|
-
|
17
10
|
task :default => :test
|
data/lib/resolv.rb
CHANGED
@@ -37,6 +37,8 @@ end
|
|
37
37
|
|
38
38
|
class Resolv
|
39
39
|
|
40
|
+
VERSION = "0.4.0"
|
41
|
+
|
40
42
|
##
|
41
43
|
# Looks up the first IP address for +name+.
|
42
44
|
|
@@ -82,8 +84,8 @@ class Resolv
|
|
82
84
|
##
|
83
85
|
# Creates a new Resolv using +resolvers+.
|
84
86
|
|
85
|
-
def initialize(resolvers=
|
86
|
-
@resolvers = resolvers
|
87
|
+
def initialize(resolvers=nil, use_ipv6: nil)
|
88
|
+
@resolvers = resolvers || [Hosts.new, DNS.new(DNS::Config.default_config_hash.merge(use_ipv6: use_ipv6))]
|
87
89
|
end
|
88
90
|
|
89
91
|
##
|
@@ -192,17 +194,10 @@ class Resolv
|
|
192
194
|
File.open(@filename, 'rb') {|f|
|
193
195
|
f.each {|line|
|
194
196
|
line.sub!(/#.*/, '')
|
195
|
-
addr,
|
197
|
+
addr, *hostnames = line.split(/\s+/)
|
196
198
|
next unless addr
|
197
|
-
@addr2name[addr]
|
198
|
-
@
|
199
|
-
@addr2name[addr] += aliases
|
200
|
-
@name2addr[hostname] = [] unless @name2addr.include? hostname
|
201
|
-
@name2addr[hostname] << addr
|
202
|
-
aliases.each {|n|
|
203
|
-
@name2addr[n] = [] unless @name2addr.include? n
|
204
|
-
@name2addr[n] << addr
|
205
|
-
}
|
199
|
+
(@addr2name[addr] ||= []).concat(hostnames)
|
200
|
+
hostnames.each {|hostname| (@name2addr[hostname] ||= []) << addr}
|
206
201
|
}
|
207
202
|
}
|
208
203
|
@name2addr.each {|name, arr| arr.reverse!}
|
@@ -310,6 +305,8 @@ class Resolv
|
|
310
305
|
# String:: Path to a file using /etc/resolv.conf's format.
|
311
306
|
# Hash:: Must contain :nameserver, :search and :ndots keys.
|
312
307
|
# :nameserver_port can be used to specify port number of nameserver address.
|
308
|
+
# :raise_timeout_errors can be used to raise timeout errors
|
309
|
+
# as exceptions instead of treating the same as an NXDOMAIN response.
|
313
310
|
#
|
314
311
|
# The value of :nameserver should be an address string or
|
315
312
|
# an array of address strings.
|
@@ -406,6 +403,11 @@ class Resolv
|
|
406
403
|
end
|
407
404
|
|
408
405
|
def use_ipv6? # :nodoc:
|
406
|
+
use_ipv6 = @config.use_ipv6?
|
407
|
+
unless use_ipv6.nil?
|
408
|
+
return use_ipv6
|
409
|
+
end
|
410
|
+
|
409
411
|
begin
|
410
412
|
list = Socket.ip_address_list
|
411
413
|
rescue NotImplementedError
|
@@ -748,7 +750,7 @@ class Resolv
|
|
748
750
|
next if @socks_hash[bind_host]
|
749
751
|
begin
|
750
752
|
sock = UDPSocket.new(af)
|
751
|
-
rescue Errno::EAFNOSUPPORT
|
753
|
+
rescue Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT
|
752
754
|
next # The kernel doesn't support the address family.
|
753
755
|
end
|
754
756
|
@socks << sock
|
@@ -965,7 +967,7 @@ class Resolv
|
|
965
967
|
next unless keyword
|
966
968
|
case keyword
|
967
969
|
when 'nameserver'
|
968
|
-
nameserver
|
970
|
+
nameserver.concat(args)
|
969
971
|
when 'domain'
|
970
972
|
next if args.empty?
|
971
973
|
search = [args[0]]
|
@@ -1004,6 +1006,7 @@ class Resolv
|
|
1004
1006
|
@mutex.synchronize {
|
1005
1007
|
unless @initialized
|
1006
1008
|
@nameserver_port = []
|
1009
|
+
@use_ipv6 = nil
|
1007
1010
|
@search = nil
|
1008
1011
|
@ndots = 1
|
1009
1012
|
case @config_info
|
@@ -1028,8 +1031,12 @@ class Resolv
|
|
1028
1031
|
if config_hash.include? :nameserver_port
|
1029
1032
|
@nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
|
1030
1033
|
end
|
1034
|
+
if config_hash.include? :use_ipv6
|
1035
|
+
@use_ipv6 = config_hash[:use_ipv6]
|
1036
|
+
end
|
1031
1037
|
@search = config_hash[:search] if config_hash.include? :search
|
1032
1038
|
@ndots = config_hash[:ndots] if config_hash.include? :ndots
|
1039
|
+
@raise_timeout_errors = config_hash[:raise_timeout_errors]
|
1033
1040
|
|
1034
1041
|
if @nameserver_port.empty?
|
1035
1042
|
@nameserver_port << ['0.0.0.0', Port]
|
@@ -1083,6 +1090,10 @@ class Resolv
|
|
1083
1090
|
@nameserver_port
|
1084
1091
|
end
|
1085
1092
|
|
1093
|
+
def use_ipv6?
|
1094
|
+
@use_ipv6
|
1095
|
+
end
|
1096
|
+
|
1086
1097
|
def generate_candidates(name)
|
1087
1098
|
candidates = nil
|
1088
1099
|
name = Name.create(name)
|
@@ -1116,6 +1127,7 @@ class Resolv
|
|
1116
1127
|
def resolv(name)
|
1117
1128
|
candidates = generate_candidates(name)
|
1118
1129
|
timeouts = @timeouts || generate_timeouts
|
1130
|
+
timeout_error = false
|
1119
1131
|
begin
|
1120
1132
|
candidates.each {|candidate|
|
1121
1133
|
begin
|
@@ -1127,11 +1139,13 @@ class Resolv
|
|
1127
1139
|
end
|
1128
1140
|
}
|
1129
1141
|
}
|
1142
|
+
timeout_error = true
|
1130
1143
|
raise ResolvError.new("DNS resolv timeout: #{name}")
|
1131
1144
|
rescue NXDomain
|
1132
1145
|
end
|
1133
1146
|
}
|
1134
1147
|
rescue ResolvError
|
1148
|
+
raise if @raise_timeout_errors && timeout_error
|
1135
1149
|
end
|
1136
1150
|
end
|
1137
1151
|
|
@@ -1487,14 +1501,14 @@ class Resolv
|
|
1487
1501
|
}
|
1488
1502
|
end
|
1489
1503
|
|
1490
|
-
def put_name(d)
|
1491
|
-
put_labels(d.to_a)
|
1504
|
+
def put_name(d, compress: true)
|
1505
|
+
put_labels(d.to_a, compress: compress)
|
1492
1506
|
end
|
1493
1507
|
|
1494
|
-
def put_labels(d)
|
1508
|
+
def put_labels(d, compress: true)
|
1495
1509
|
d.each_index {|i|
|
1496
1510
|
domain = d[i..-1]
|
1497
|
-
if idx = @names[domain]
|
1511
|
+
if compress && idx = @names[domain]
|
1498
1512
|
self.put_pack("n", 0xc000 | idx)
|
1499
1513
|
return
|
1500
1514
|
else
|
@@ -1518,13 +1532,15 @@ class Resolv
|
|
1518
1532
|
id, flag, qdcount, ancount, nscount, arcount =
|
1519
1533
|
msg.get_unpack('nnnnnn')
|
1520
1534
|
o.id = id
|
1535
|
+
o.tc = (flag >> 9) & 1
|
1536
|
+
o.rcode = flag & 15
|
1537
|
+
return o unless o.tc.zero?
|
1538
|
+
|
1521
1539
|
o.qr = (flag >> 15) & 1
|
1522
1540
|
o.opcode = (flag >> 11) & 15
|
1523
1541
|
o.aa = (flag >> 10) & 1
|
1524
|
-
o.tc = (flag >> 9) & 1
|
1525
1542
|
o.rd = (flag >> 8) & 1
|
1526
1543
|
o.ra = (flag >> 7) & 1
|
1527
|
-
o.rcode = flag & 15
|
1528
1544
|
(1..qdcount).each {
|
1529
1545
|
name, typeclass = msg.get_question
|
1530
1546
|
o.add_question(name, typeclass)
|
@@ -1616,6 +1632,14 @@ class Resolv
|
|
1616
1632
|
strings
|
1617
1633
|
end
|
1618
1634
|
|
1635
|
+
def get_list
|
1636
|
+
[].tap do |values|
|
1637
|
+
while @index < @limit
|
1638
|
+
values << yield
|
1639
|
+
end
|
1640
|
+
end
|
1641
|
+
end
|
1642
|
+
|
1619
1643
|
def get_name
|
1620
1644
|
return Name.new(self.get_labels)
|
1621
1645
|
end
|
@@ -1676,6 +1700,378 @@ class Resolv
|
|
1676
1700
|
end
|
1677
1701
|
end
|
1678
1702
|
|
1703
|
+
##
|
1704
|
+
# SvcParams for service binding RRs. [RFC9460]
|
1705
|
+
|
1706
|
+
class SvcParams
|
1707
|
+
include Enumerable
|
1708
|
+
|
1709
|
+
##
|
1710
|
+
# Create a list of SvcParams with the given initial content.
|
1711
|
+
#
|
1712
|
+
# +params+ has to be an enumerable of +SvcParam+s.
|
1713
|
+
# If its content has +SvcParam+s with the duplicate key,
|
1714
|
+
# the one appears last takes precedence.
|
1715
|
+
|
1716
|
+
def initialize(params = [])
|
1717
|
+
@params = {}
|
1718
|
+
|
1719
|
+
params.each do |param|
|
1720
|
+
add param
|
1721
|
+
end
|
1722
|
+
end
|
1723
|
+
|
1724
|
+
##
|
1725
|
+
# Get SvcParam for the given +key+ in this list.
|
1726
|
+
|
1727
|
+
def [](key)
|
1728
|
+
@params[canonical_key(key)]
|
1729
|
+
end
|
1730
|
+
|
1731
|
+
##
|
1732
|
+
# Get the number of SvcParams in this list.
|
1733
|
+
|
1734
|
+
def count
|
1735
|
+
@params.count
|
1736
|
+
end
|
1737
|
+
|
1738
|
+
##
|
1739
|
+
# Get whether this list is empty.
|
1740
|
+
|
1741
|
+
def empty?
|
1742
|
+
@params.empty?
|
1743
|
+
end
|
1744
|
+
|
1745
|
+
##
|
1746
|
+
# Add the SvcParam +param+ to this list, overwriting the existing one with the same key.
|
1747
|
+
|
1748
|
+
def add(param)
|
1749
|
+
@params[param.class.key_number] = param
|
1750
|
+
end
|
1751
|
+
|
1752
|
+
##
|
1753
|
+
# Remove the +SvcParam+ with the given +key+ and return it.
|
1754
|
+
|
1755
|
+
def delete(key)
|
1756
|
+
@params.delete(canonical_key(key))
|
1757
|
+
end
|
1758
|
+
|
1759
|
+
##
|
1760
|
+
# Enumerate the +SvcParam+s in this list.
|
1761
|
+
|
1762
|
+
def each(&block)
|
1763
|
+
return enum_for(:each) unless block
|
1764
|
+
@params.each_value(&block)
|
1765
|
+
end
|
1766
|
+
|
1767
|
+
def encode(msg) # :nodoc:
|
1768
|
+
@params.keys.sort.each do |key|
|
1769
|
+
msg.put_pack('n', key)
|
1770
|
+
msg.put_length16 do
|
1771
|
+
@params.fetch(key).encode(msg)
|
1772
|
+
end
|
1773
|
+
end
|
1774
|
+
end
|
1775
|
+
|
1776
|
+
def self.decode(msg) # :nodoc:
|
1777
|
+
params = msg.get_list do
|
1778
|
+
key, = msg.get_unpack('n')
|
1779
|
+
msg.get_length16 do
|
1780
|
+
SvcParam::ClassHash[key].decode(msg)
|
1781
|
+
end
|
1782
|
+
end
|
1783
|
+
|
1784
|
+
return self.new(params)
|
1785
|
+
end
|
1786
|
+
|
1787
|
+
private
|
1788
|
+
|
1789
|
+
def canonical_key(key) # :nodoc:
|
1790
|
+
case key
|
1791
|
+
when Integer
|
1792
|
+
key
|
1793
|
+
when /\Akey(\d+)\z/
|
1794
|
+
Integer($1)
|
1795
|
+
when Symbol
|
1796
|
+
SvcParam::ClassHash[key].key_number
|
1797
|
+
else
|
1798
|
+
raise TypeError, 'key must be either String or Symbol'
|
1799
|
+
end
|
1800
|
+
end
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
|
1804
|
+
##
|
1805
|
+
# Base class for SvcParam. [RFC9460]
|
1806
|
+
|
1807
|
+
class SvcParam
|
1808
|
+
|
1809
|
+
##
|
1810
|
+
# Get the presentation name of the SvcParamKey.
|
1811
|
+
|
1812
|
+
def self.key_name
|
1813
|
+
const_get(:KeyName)
|
1814
|
+
end
|
1815
|
+
|
1816
|
+
##
|
1817
|
+
# Get the registered number of the SvcParamKey.
|
1818
|
+
|
1819
|
+
def self.key_number
|
1820
|
+
const_get(:KeyNumber)
|
1821
|
+
end
|
1822
|
+
|
1823
|
+
ClassHash = Hash.new do |h, key| # :nodoc:
|
1824
|
+
case key
|
1825
|
+
when Integer
|
1826
|
+
Generic.create(key)
|
1827
|
+
when /\Akey(?<key>\d+)\z/
|
1828
|
+
Generic.create(key.to_int)
|
1829
|
+
when Symbol
|
1830
|
+
raise KeyError, "unknown key #{key}"
|
1831
|
+
else
|
1832
|
+
raise TypeError, 'key must be either String or Symbol'
|
1833
|
+
end
|
1834
|
+
end
|
1835
|
+
|
1836
|
+
##
|
1837
|
+
# Generic SvcParam abstract class.
|
1838
|
+
|
1839
|
+
class Generic < SvcParam
|
1840
|
+
|
1841
|
+
##
|
1842
|
+
# SvcParamValue in wire-format byte string.
|
1843
|
+
|
1844
|
+
attr_reader :value
|
1845
|
+
|
1846
|
+
##
|
1847
|
+
# Create generic SvcParam
|
1848
|
+
|
1849
|
+
def initialize(value)
|
1850
|
+
@value = value
|
1851
|
+
end
|
1852
|
+
|
1853
|
+
def encode(msg) # :nodoc:
|
1854
|
+
msg.put_bytes(@value)
|
1855
|
+
end
|
1856
|
+
|
1857
|
+
def self.decode(msg) # :nodoc:
|
1858
|
+
return self.new(msg.get_bytes)
|
1859
|
+
end
|
1860
|
+
|
1861
|
+
def self.create(key_number)
|
1862
|
+
c = Class.new(Generic)
|
1863
|
+
key_name = :"key#{key_number}"
|
1864
|
+
c.const_set(:KeyName, key_name)
|
1865
|
+
c.const_set(:KeyNumber, key_number)
|
1866
|
+
self.const_set(:"Key#{key_number}", c)
|
1867
|
+
ClassHash[key_name] = ClassHash[key_number] = c
|
1868
|
+
return c
|
1869
|
+
end
|
1870
|
+
end
|
1871
|
+
|
1872
|
+
##
|
1873
|
+
# "mandatory" SvcParam -- Mandatory keys in service binding RR
|
1874
|
+
|
1875
|
+
class Mandatory < SvcParam
|
1876
|
+
KeyName = :mandatory
|
1877
|
+
KeyNumber = 0
|
1878
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1879
|
+
|
1880
|
+
##
|
1881
|
+
# Mandatory keys.
|
1882
|
+
|
1883
|
+
attr_reader :keys
|
1884
|
+
|
1885
|
+
##
|
1886
|
+
# Initialize "mandatory" ScvParam.
|
1887
|
+
|
1888
|
+
def initialize(keys)
|
1889
|
+
@keys = keys.map(&:to_int)
|
1890
|
+
end
|
1891
|
+
|
1892
|
+
def encode(msg) # :nodoc:
|
1893
|
+
@keys.sort.each do |key|
|
1894
|
+
msg.put_pack('n', key)
|
1895
|
+
end
|
1896
|
+
end
|
1897
|
+
|
1898
|
+
def self.decode(msg) # :nodoc:
|
1899
|
+
keys = msg.get_list { msg.get_unpack('n')[0] }
|
1900
|
+
return self.new(keys)
|
1901
|
+
end
|
1902
|
+
end
|
1903
|
+
|
1904
|
+
##
|
1905
|
+
# "alpn" SvcParam -- Additional supported protocols
|
1906
|
+
|
1907
|
+
class ALPN < SvcParam
|
1908
|
+
KeyName = :alpn
|
1909
|
+
KeyNumber = 1
|
1910
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1911
|
+
|
1912
|
+
##
|
1913
|
+
# Supported protocol IDs.
|
1914
|
+
|
1915
|
+
attr_reader :protocol_ids
|
1916
|
+
|
1917
|
+
##
|
1918
|
+
# Initialize "alpn" ScvParam.
|
1919
|
+
|
1920
|
+
def initialize(protocol_ids)
|
1921
|
+
@protocol_ids = protocol_ids.map(&:to_str)
|
1922
|
+
end
|
1923
|
+
|
1924
|
+
def encode(msg) # :nodoc:
|
1925
|
+
msg.put_string_list(@protocol_ids)
|
1926
|
+
end
|
1927
|
+
|
1928
|
+
def self.decode(msg) # :nodoc:
|
1929
|
+
return self.new(msg.get_string_list)
|
1930
|
+
end
|
1931
|
+
end
|
1932
|
+
|
1933
|
+
##
|
1934
|
+
# "no-default-alpn" SvcParam -- No support for default protocol
|
1935
|
+
|
1936
|
+
class NoDefaultALPN < SvcParam
|
1937
|
+
KeyName = :'no-default-alpn'
|
1938
|
+
KeyNumber = 2
|
1939
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1940
|
+
|
1941
|
+
def encode(msg) # :nodoc:
|
1942
|
+
# no payload
|
1943
|
+
end
|
1944
|
+
|
1945
|
+
def self.decode(msg) # :nodoc:
|
1946
|
+
return self.new
|
1947
|
+
end
|
1948
|
+
end
|
1949
|
+
|
1950
|
+
##
|
1951
|
+
# "port" SvcParam -- Port for alternative endpoint
|
1952
|
+
|
1953
|
+
class Port < SvcParam
|
1954
|
+
KeyName = :port
|
1955
|
+
KeyNumber = 3
|
1956
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1957
|
+
|
1958
|
+
##
|
1959
|
+
# Port number.
|
1960
|
+
|
1961
|
+
attr_reader :port
|
1962
|
+
|
1963
|
+
##
|
1964
|
+
# Initialize "port" ScvParam.
|
1965
|
+
|
1966
|
+
def initialize(port)
|
1967
|
+
@port = port.to_int
|
1968
|
+
end
|
1969
|
+
|
1970
|
+
def encode(msg) # :nodoc:
|
1971
|
+
msg.put_pack('n', @port)
|
1972
|
+
end
|
1973
|
+
|
1974
|
+
def self.decode(msg) # :nodoc:
|
1975
|
+
port, = msg.get_unpack('n')
|
1976
|
+
return self.new(port)
|
1977
|
+
end
|
1978
|
+
end
|
1979
|
+
|
1980
|
+
##
|
1981
|
+
# "ipv4hint" SvcParam -- IPv4 address hints
|
1982
|
+
|
1983
|
+
class IPv4Hint < SvcParam
|
1984
|
+
KeyName = :ipv4hint
|
1985
|
+
KeyNumber = 4
|
1986
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1987
|
+
|
1988
|
+
##
|
1989
|
+
# Set of IPv4 addresses.
|
1990
|
+
|
1991
|
+
attr_reader :addresses
|
1992
|
+
|
1993
|
+
##
|
1994
|
+
# Initialize "ipv4hint" ScvParam.
|
1995
|
+
|
1996
|
+
def initialize(addresses)
|
1997
|
+
@addresses = addresses.map {|address| IPv4.create(address) }
|
1998
|
+
end
|
1999
|
+
|
2000
|
+
def encode(msg) # :nodoc:
|
2001
|
+
@addresses.each do |address|
|
2002
|
+
msg.put_bytes(address.address)
|
2003
|
+
end
|
2004
|
+
end
|
2005
|
+
|
2006
|
+
def self.decode(msg) # :nodoc:
|
2007
|
+
addresses = msg.get_list { IPv4.new(msg.get_bytes(4)) }
|
2008
|
+
return self.new(addresses)
|
2009
|
+
end
|
2010
|
+
end
|
2011
|
+
|
2012
|
+
##
|
2013
|
+
# "ipv6hint" SvcParam -- IPv6 address hints
|
2014
|
+
|
2015
|
+
class IPv6Hint < SvcParam
|
2016
|
+
KeyName = :ipv6hint
|
2017
|
+
KeyNumber = 6
|
2018
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
2019
|
+
|
2020
|
+
##
|
2021
|
+
# Set of IPv6 addresses.
|
2022
|
+
|
2023
|
+
attr_reader :addresses
|
2024
|
+
|
2025
|
+
##
|
2026
|
+
# Initialize "ipv6hint" ScvParam.
|
2027
|
+
|
2028
|
+
def initialize(addresses)
|
2029
|
+
@addresses = addresses.map {|address| IPv6.create(address) }
|
2030
|
+
end
|
2031
|
+
|
2032
|
+
def encode(msg) # :nodoc:
|
2033
|
+
@addresses.each do |address|
|
2034
|
+
msg.put_bytes(address.address)
|
2035
|
+
end
|
2036
|
+
end
|
2037
|
+
|
2038
|
+
def self.decode(msg) # :nodoc:
|
2039
|
+
addresses = msg.get_list { IPv6.new(msg.get_bytes(16)) }
|
2040
|
+
return self.new(addresses)
|
2041
|
+
end
|
2042
|
+
end
|
2043
|
+
|
2044
|
+
##
|
2045
|
+
# "dohpath" SvcParam -- DNS over HTTPS path template [RFC9461]
|
2046
|
+
|
2047
|
+
class DoHPath < SvcParam
|
2048
|
+
KeyName = :dohpath
|
2049
|
+
KeyNumber = 7
|
2050
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
2051
|
+
|
2052
|
+
##
|
2053
|
+
# URI template for DoH queries.
|
2054
|
+
|
2055
|
+
attr_reader :template
|
2056
|
+
|
2057
|
+
##
|
2058
|
+
# Initialize "dohpath" ScvParam.
|
2059
|
+
|
2060
|
+
def initialize(template)
|
2061
|
+
@template = template.encode('utf-8')
|
2062
|
+
end
|
2063
|
+
|
2064
|
+
def encode(msg) # :nodoc:
|
2065
|
+
msg.put_bytes(@template)
|
2066
|
+
end
|
2067
|
+
|
2068
|
+
def self.decode(msg) # :nodoc:
|
2069
|
+
template = msg.get_bytes.force_encoding('utf-8')
|
2070
|
+
return self.new(template)
|
2071
|
+
end
|
2072
|
+
end
|
2073
|
+
end
|
2074
|
+
|
1679
2075
|
##
|
1680
2076
|
# A DNS query abstract class.
|
1681
2077
|
|
@@ -2141,8 +2537,70 @@ class Resolv
|
|
2141
2537
|
TypeValue = 255 # :nodoc:
|
2142
2538
|
end
|
2143
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
|
+
|
2144
2602
|
ClassInsensitiveTypes = [ # :nodoc:
|
2145
|
-
NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY
|
2603
|
+
NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY, CAA
|
2146
2604
|
]
|
2147
2605
|
|
2148
2606
|
##
|
@@ -2328,7 +2786,7 @@ class Resolv
|
|
2328
2786
|
msg.put_pack("n", @priority)
|
2329
2787
|
msg.put_pack("n", @weight)
|
2330
2788
|
msg.put_pack("n", @port)
|
2331
|
-
msg.put_name(@target)
|
2789
|
+
msg.put_name(@target, compress: false)
|
2332
2790
|
end
|
2333
2791
|
|
2334
2792
|
def self.decode_rdata(msg) # :nodoc:
|
@@ -2339,6 +2797,84 @@ class Resolv
|
|
2339
2797
|
return self.new(priority, weight, port, target)
|
2340
2798
|
end
|
2341
2799
|
end
|
2800
|
+
|
2801
|
+
##
|
2802
|
+
# Common implementation for SVCB-compatible resource records.
|
2803
|
+
|
2804
|
+
class ServiceBinding
|
2805
|
+
|
2806
|
+
##
|
2807
|
+
# Create a service binding resource record.
|
2808
|
+
|
2809
|
+
def initialize(priority, target, params = [])
|
2810
|
+
@priority = priority.to_int
|
2811
|
+
@target = Name.create(target)
|
2812
|
+
@params = SvcParams.new(params)
|
2813
|
+
end
|
2814
|
+
|
2815
|
+
##
|
2816
|
+
# The priority of this target host.
|
2817
|
+
#
|
2818
|
+
# The range is 0-65535.
|
2819
|
+
# If set to 0, this RR is in AliasMode. Otherwise, it is in ServiceMode.
|
2820
|
+
|
2821
|
+
attr_reader :priority
|
2822
|
+
|
2823
|
+
##
|
2824
|
+
# The domain name of the target host.
|
2825
|
+
|
2826
|
+
attr_reader :target
|
2827
|
+
|
2828
|
+
##
|
2829
|
+
# The service parameters for the target host.
|
2830
|
+
|
2831
|
+
attr_reader :params
|
2832
|
+
|
2833
|
+
##
|
2834
|
+
# Whether this RR is in AliasMode.
|
2835
|
+
|
2836
|
+
def alias_mode?
|
2837
|
+
self.priority == 0
|
2838
|
+
end
|
2839
|
+
|
2840
|
+
##
|
2841
|
+
# Whether this RR is in ServiceMode.
|
2842
|
+
|
2843
|
+
def service_mode?
|
2844
|
+
!alias_mode?
|
2845
|
+
end
|
2846
|
+
|
2847
|
+
def encode_rdata(msg) # :nodoc:
|
2848
|
+
msg.put_pack("n", @priority)
|
2849
|
+
msg.put_name(@target, compress: false)
|
2850
|
+
@params.encode(msg)
|
2851
|
+
end
|
2852
|
+
|
2853
|
+
def self.decode_rdata(msg) # :nodoc:
|
2854
|
+
priority, = msg.get_unpack("n")
|
2855
|
+
target = msg.get_name
|
2856
|
+
params = SvcParams.decode(msg)
|
2857
|
+
return self.new(priority, target, params)
|
2858
|
+
end
|
2859
|
+
end
|
2860
|
+
|
2861
|
+
##
|
2862
|
+
# SVCB resource record [RFC9460]
|
2863
|
+
|
2864
|
+
class SVCB < ServiceBinding
|
2865
|
+
TypeValue = 64
|
2866
|
+
ClassValue = IN::ClassValue
|
2867
|
+
ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
|
2868
|
+
end
|
2869
|
+
|
2870
|
+
##
|
2871
|
+
# HTTPS resource record [RFC9460]
|
2872
|
+
|
2873
|
+
class HTTPS < ServiceBinding
|
2874
|
+
TypeValue = 65
|
2875
|
+
ClassValue = IN::ClassValue
|
2876
|
+
ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
|
2877
|
+
end
|
2342
2878
|
end
|
2343
2879
|
end
|
2344
2880
|
end
|
@@ -2558,11 +3094,7 @@ class Resolv
|
|
2558
3094
|
attr_reader :address
|
2559
3095
|
|
2560
3096
|
def to_s # :nodoc:
|
2561
|
-
|
2562
|
-
unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
|
2563
|
-
address.sub!(/(^|:)0(:|$)/, '::')
|
2564
|
-
end
|
2565
|
-
return address
|
3097
|
+
sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn")).sub(/(^|:)0(:0)+(:|$)/, '::')
|
2566
3098
|
end
|
2567
3099
|
|
2568
3100
|
def inspect # :nodoc:
|
data/resolv.gemspec
CHANGED
@@ -1,6 +1,13 @@
|
|
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
|
+
|
1
8
|
Gem::Specification.new do |spec|
|
2
|
-
spec.name =
|
3
|
-
spec.version =
|
9
|
+
spec.name = name
|
10
|
+
spec.version = version
|
4
11
|
spec.authors = ["Tanaka Akira"]
|
5
12
|
spec.email = ["akr@fsij.org"]
|
6
13
|
|
metadata
CHANGED
@@ -1,14 +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
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2024-03-19 00:00:00.000000000 Z
|
12
11
|
dependencies: []
|
13
12
|
description: Thread-aware DNS resolver library in Ruby.
|
14
13
|
email:
|
@@ -35,7 +34,6 @@ licenses:
|
|
35
34
|
metadata:
|
36
35
|
homepage_uri: https://github.com/ruby/resolv
|
37
36
|
source_code_uri: https://github.com/ruby/resolv
|
38
|
-
post_install_message:
|
39
37
|
rdoc_options: []
|
40
38
|
require_paths:
|
41
39
|
- lib
|
@@ -50,8 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
48
|
- !ruby/object:Gem::Version
|
51
49
|
version: '0'
|
52
50
|
requirements: []
|
53
|
-
rubygems_version: 3.
|
54
|
-
signing_key:
|
51
|
+
rubygems_version: 3.6.0.dev
|
55
52
|
specification_version: 4
|
56
53
|
summary: Thread-aware DNS resolver library in Ruby.
|
57
54
|
test_files: []
|