resolv 0.2.1 → 0.3.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 +11 -5
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/lib/resolv.rb +496 -19
- data/resolv.gemspec +9 -2
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d76dc1156c60da694ce1f0a96165e6d5a7e29d662ad7140b443e9aa735082f31
|
4
|
+
data.tar.gz: 7b532fc449aff2e5a63cb6a31892a45da5b41b6090d454f94d3c3e5165c94271
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 685ce620cc9c83f1d5827de0a374d71f98fbff7629256d2ab7ed65d66eee062a5bc081a869caba31aeb67b4c292ca6dfc53fa4d71180ce15dd82f39d6fb5992b
|
7
|
+
data.tar.gz: 9897929fbfc67bc3a8133d3d9b2f99e7c9350802cf86d4cc0d8f061f397393f91308d6d1d6d35e46d497a3beb7fcf6424dc47ae92d5f7f39e572ac04b2677409
|
data/.github/workflows/test.yml
CHANGED
@@ -3,20 +3,26 @@ 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:
|
17
|
+
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
11
18
|
os: [ ubuntu-latest, macos-latest ]
|
12
19
|
runs-on: ${{ matrix.os }}
|
13
20
|
steps:
|
14
|
-
- uses: actions/checkout@
|
21
|
+
- uses: actions/checkout@v4
|
15
22
|
- name: Set up Ruby
|
16
23
|
uses: ruby/setup-ruby@v1
|
17
24
|
with:
|
18
25
|
ruby-version: ${{ matrix.ruby }}
|
19
|
-
|
20
|
-
run: bundle install
|
26
|
+
bundler-cache: true
|
21
27
|
- name: Run test
|
22
|
-
run: rake test
|
28
|
+
run: bundle exec rake test
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/lib/resolv.rb
CHANGED
@@ -37,6 +37,8 @@ end
|
|
37
37
|
|
38
38
|
class Resolv
|
39
39
|
|
40
|
+
VERSION = "0.3.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
|
##
|
@@ -196,7 +198,7 @@ class Resolv
|
|
196
198
|
next unless addr
|
197
199
|
@addr2name[addr] = [] unless @addr2name.include? addr
|
198
200
|
@addr2name[addr] << hostname
|
199
|
-
@addr2name[addr]
|
201
|
+
@addr2name[addr].concat(aliases)
|
200
202
|
@name2addr[hostname] = [] unless @name2addr.include? hostname
|
201
203
|
@name2addr[hostname] << addr
|
202
204
|
aliases.each {|n|
|
@@ -310,6 +312,8 @@ class Resolv
|
|
310
312
|
# String:: Path to a file using /etc/resolv.conf's format.
|
311
313
|
# Hash:: Must contain :nameserver, :search and :ndots keys.
|
312
314
|
# :nameserver_port can be used to specify port number of nameserver address.
|
315
|
+
# :raise_timeout_errors can be used to raise timeout errors
|
316
|
+
# as exceptions instead of treating the same as an NXDOMAIN response.
|
313
317
|
#
|
314
318
|
# The value of :nameserver should be an address string or
|
315
319
|
# an array of address strings.
|
@@ -406,6 +410,11 @@ class Resolv
|
|
406
410
|
end
|
407
411
|
|
408
412
|
def use_ipv6? # :nodoc:
|
413
|
+
use_ipv6 = @config.use_ipv6?
|
414
|
+
unless use_ipv6.nil?
|
415
|
+
return use_ipv6
|
416
|
+
end
|
417
|
+
|
409
418
|
begin
|
410
419
|
list = Socket.ip_address_list
|
411
420
|
rescue NotImplementedError
|
@@ -748,7 +757,7 @@ class Resolv
|
|
748
757
|
next if @socks_hash[bind_host]
|
749
758
|
begin
|
750
759
|
sock = UDPSocket.new(af)
|
751
|
-
rescue Errno::EAFNOSUPPORT
|
760
|
+
rescue Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT
|
752
761
|
next # The kernel doesn't support the address family.
|
753
762
|
end
|
754
763
|
@socks << sock
|
@@ -965,7 +974,7 @@ class Resolv
|
|
965
974
|
next unless keyword
|
966
975
|
case keyword
|
967
976
|
when 'nameserver'
|
968
|
-
nameserver
|
977
|
+
nameserver.concat(args)
|
969
978
|
when 'domain'
|
970
979
|
next if args.empty?
|
971
980
|
search = [args[0]]
|
@@ -1004,6 +1013,7 @@ class Resolv
|
|
1004
1013
|
@mutex.synchronize {
|
1005
1014
|
unless @initialized
|
1006
1015
|
@nameserver_port = []
|
1016
|
+
@use_ipv6 = nil
|
1007
1017
|
@search = nil
|
1008
1018
|
@ndots = 1
|
1009
1019
|
case @config_info
|
@@ -1028,8 +1038,12 @@ class Resolv
|
|
1028
1038
|
if config_hash.include? :nameserver_port
|
1029
1039
|
@nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
|
1030
1040
|
end
|
1041
|
+
if config_hash.include? :use_ipv6
|
1042
|
+
@use_ipv6 = config_hash[:use_ipv6]
|
1043
|
+
end
|
1031
1044
|
@search = config_hash[:search] if config_hash.include? :search
|
1032
1045
|
@ndots = config_hash[:ndots] if config_hash.include? :ndots
|
1046
|
+
@raise_timeout_errors = config_hash[:raise_timeout_errors]
|
1033
1047
|
|
1034
1048
|
if @nameserver_port.empty?
|
1035
1049
|
@nameserver_port << ['0.0.0.0', Port]
|
@@ -1083,6 +1097,10 @@ class Resolv
|
|
1083
1097
|
@nameserver_port
|
1084
1098
|
end
|
1085
1099
|
|
1100
|
+
def use_ipv6?
|
1101
|
+
@use_ipv6
|
1102
|
+
end
|
1103
|
+
|
1086
1104
|
def generate_candidates(name)
|
1087
1105
|
candidates = nil
|
1088
1106
|
name = Name.create(name)
|
@@ -1116,6 +1134,7 @@ class Resolv
|
|
1116
1134
|
def resolv(name)
|
1117
1135
|
candidates = generate_candidates(name)
|
1118
1136
|
timeouts = @timeouts || generate_timeouts
|
1137
|
+
timeout_error = false
|
1119
1138
|
begin
|
1120
1139
|
candidates.each {|candidate|
|
1121
1140
|
begin
|
@@ -1127,11 +1146,13 @@ class Resolv
|
|
1127
1146
|
end
|
1128
1147
|
}
|
1129
1148
|
}
|
1149
|
+
timeout_error = true
|
1130
1150
|
raise ResolvError.new("DNS resolv timeout: #{name}")
|
1131
1151
|
rescue NXDomain
|
1132
1152
|
end
|
1133
1153
|
}
|
1134
1154
|
rescue ResolvError
|
1155
|
+
raise if @raise_timeout_errors && timeout_error
|
1135
1156
|
end
|
1136
1157
|
end
|
1137
1158
|
|
@@ -1487,14 +1508,14 @@ class Resolv
|
|
1487
1508
|
}
|
1488
1509
|
end
|
1489
1510
|
|
1490
|
-
def put_name(d)
|
1491
|
-
put_labels(d.to_a)
|
1511
|
+
def put_name(d, compress: true)
|
1512
|
+
put_labels(d.to_a, compress: compress)
|
1492
1513
|
end
|
1493
1514
|
|
1494
|
-
def put_labels(d)
|
1515
|
+
def put_labels(d, compress: true)
|
1495
1516
|
d.each_index {|i|
|
1496
1517
|
domain = d[i..-1]
|
1497
|
-
if idx = @names[domain]
|
1518
|
+
if compress && idx = @names[domain]
|
1498
1519
|
self.put_pack("n", 0xc000 | idx)
|
1499
1520
|
return
|
1500
1521
|
else
|
@@ -1518,13 +1539,15 @@ class Resolv
|
|
1518
1539
|
id, flag, qdcount, ancount, nscount, arcount =
|
1519
1540
|
msg.get_unpack('nnnnnn')
|
1520
1541
|
o.id = id
|
1542
|
+
o.tc = (flag >> 9) & 1
|
1543
|
+
o.rcode = flag & 15
|
1544
|
+
return o unless o.tc.zero?
|
1545
|
+
|
1521
1546
|
o.qr = (flag >> 15) & 1
|
1522
1547
|
o.opcode = (flag >> 11) & 15
|
1523
1548
|
o.aa = (flag >> 10) & 1
|
1524
|
-
o.tc = (flag >> 9) & 1
|
1525
1549
|
o.rd = (flag >> 8) & 1
|
1526
1550
|
o.ra = (flag >> 7) & 1
|
1527
|
-
o.rcode = flag & 15
|
1528
1551
|
(1..qdcount).each {
|
1529
1552
|
name, typeclass = msg.get_question
|
1530
1553
|
o.add_question(name, typeclass)
|
@@ -1616,6 +1639,14 @@ class Resolv
|
|
1616
1639
|
strings
|
1617
1640
|
end
|
1618
1641
|
|
1642
|
+
def get_list
|
1643
|
+
[].tap do |values|
|
1644
|
+
while @index < @limit
|
1645
|
+
values << yield
|
1646
|
+
end
|
1647
|
+
end
|
1648
|
+
end
|
1649
|
+
|
1619
1650
|
def get_name
|
1620
1651
|
return Name.new(self.get_labels)
|
1621
1652
|
end
|
@@ -1676,6 +1707,378 @@ class Resolv
|
|
1676
1707
|
end
|
1677
1708
|
end
|
1678
1709
|
|
1710
|
+
##
|
1711
|
+
# SvcParams for service binding RRs. [RFC9460]
|
1712
|
+
|
1713
|
+
class SvcParams
|
1714
|
+
include Enumerable
|
1715
|
+
|
1716
|
+
##
|
1717
|
+
# Create a list of SvcParams with the given initial content.
|
1718
|
+
#
|
1719
|
+
# +params+ has to be an enumerable of +SvcParam+s.
|
1720
|
+
# If its content has +SvcParam+s with the duplicate key,
|
1721
|
+
# the one appears last takes precedence.
|
1722
|
+
|
1723
|
+
def initialize(params = [])
|
1724
|
+
@params = {}
|
1725
|
+
|
1726
|
+
params.each do |param|
|
1727
|
+
add param
|
1728
|
+
end
|
1729
|
+
end
|
1730
|
+
|
1731
|
+
##
|
1732
|
+
# Get SvcParam for the given +key+ in this list.
|
1733
|
+
|
1734
|
+
def [](key)
|
1735
|
+
@params[canonical_key(key)]
|
1736
|
+
end
|
1737
|
+
|
1738
|
+
##
|
1739
|
+
# Get the number of SvcParams in this list.
|
1740
|
+
|
1741
|
+
def count
|
1742
|
+
@params.count
|
1743
|
+
end
|
1744
|
+
|
1745
|
+
##
|
1746
|
+
# Get whether this list is empty.
|
1747
|
+
|
1748
|
+
def empty?
|
1749
|
+
@params.empty?
|
1750
|
+
end
|
1751
|
+
|
1752
|
+
##
|
1753
|
+
# Add the SvcParam +param+ to this list, overwriting the existing one with the same key.
|
1754
|
+
|
1755
|
+
def add(param)
|
1756
|
+
@params[param.class.key_number] = param
|
1757
|
+
end
|
1758
|
+
|
1759
|
+
##
|
1760
|
+
# Remove the +SvcParam+ with the given +key+ and return it.
|
1761
|
+
|
1762
|
+
def delete(key)
|
1763
|
+
@params.delete(canonical_key(key))
|
1764
|
+
end
|
1765
|
+
|
1766
|
+
##
|
1767
|
+
# Enumerate the +SvcParam+s in this list.
|
1768
|
+
|
1769
|
+
def each(&block)
|
1770
|
+
return enum_for(:each) unless block
|
1771
|
+
@params.each_value(&block)
|
1772
|
+
end
|
1773
|
+
|
1774
|
+
def encode(msg) # :nodoc:
|
1775
|
+
@params.keys.sort.each do |key|
|
1776
|
+
msg.put_pack('n', key)
|
1777
|
+
msg.put_length16 do
|
1778
|
+
@params.fetch(key).encode(msg)
|
1779
|
+
end
|
1780
|
+
end
|
1781
|
+
end
|
1782
|
+
|
1783
|
+
def self.decode(msg) # :nodoc:
|
1784
|
+
params = msg.get_list do
|
1785
|
+
key, = msg.get_unpack('n')
|
1786
|
+
msg.get_length16 do
|
1787
|
+
SvcParam::ClassHash[key].decode(msg)
|
1788
|
+
end
|
1789
|
+
end
|
1790
|
+
|
1791
|
+
return self.new(params)
|
1792
|
+
end
|
1793
|
+
|
1794
|
+
private
|
1795
|
+
|
1796
|
+
def canonical_key(key) # :nodoc:
|
1797
|
+
case key
|
1798
|
+
when Integer
|
1799
|
+
key
|
1800
|
+
when /\Akey(\d+)\z/
|
1801
|
+
Integer($1)
|
1802
|
+
when Symbol
|
1803
|
+
SvcParam::ClassHash[key].key_number
|
1804
|
+
else
|
1805
|
+
raise TypeError, 'key must be either String or Symbol'
|
1806
|
+
end
|
1807
|
+
end
|
1808
|
+
end
|
1809
|
+
|
1810
|
+
|
1811
|
+
##
|
1812
|
+
# Base class for SvcParam. [RFC9460]
|
1813
|
+
|
1814
|
+
class SvcParam
|
1815
|
+
|
1816
|
+
##
|
1817
|
+
# Get the presentation name of the SvcParamKey.
|
1818
|
+
|
1819
|
+
def self.key_name
|
1820
|
+
const_get(:KeyName)
|
1821
|
+
end
|
1822
|
+
|
1823
|
+
##
|
1824
|
+
# Get the registered number of the SvcParamKey.
|
1825
|
+
|
1826
|
+
def self.key_number
|
1827
|
+
const_get(:KeyNumber)
|
1828
|
+
end
|
1829
|
+
|
1830
|
+
ClassHash = Hash.new do |h, key| # :nodoc:
|
1831
|
+
case key
|
1832
|
+
when Integer
|
1833
|
+
Generic.create(key)
|
1834
|
+
when /\Akey(?<key>\d+)\z/
|
1835
|
+
Generic.create(key.to_int)
|
1836
|
+
when Symbol
|
1837
|
+
raise KeyError, "unknown key #{key}"
|
1838
|
+
else
|
1839
|
+
raise TypeError, 'key must be either String or Symbol'
|
1840
|
+
end
|
1841
|
+
end
|
1842
|
+
|
1843
|
+
##
|
1844
|
+
# Generic SvcParam abstract class.
|
1845
|
+
|
1846
|
+
class Generic < SvcParam
|
1847
|
+
|
1848
|
+
##
|
1849
|
+
# SvcParamValue in wire-format byte string.
|
1850
|
+
|
1851
|
+
attr_reader :value
|
1852
|
+
|
1853
|
+
##
|
1854
|
+
# Create generic SvcParam
|
1855
|
+
|
1856
|
+
def initialize(value)
|
1857
|
+
@value = value
|
1858
|
+
end
|
1859
|
+
|
1860
|
+
def encode(msg) # :nodoc:
|
1861
|
+
msg.put_bytes(@value)
|
1862
|
+
end
|
1863
|
+
|
1864
|
+
def self.decode(msg) # :nodoc:
|
1865
|
+
return self.new(msg.get_bytes)
|
1866
|
+
end
|
1867
|
+
|
1868
|
+
def self.create(key_number)
|
1869
|
+
c = Class.new(Generic)
|
1870
|
+
key_name = :"key#{key_number}"
|
1871
|
+
c.const_set(:KeyName, key_name)
|
1872
|
+
c.const_set(:KeyNumber, key_number)
|
1873
|
+
self.const_set(:"Key#{key_number}", c)
|
1874
|
+
ClassHash[key_name] = ClassHash[key_number] = c
|
1875
|
+
return c
|
1876
|
+
end
|
1877
|
+
end
|
1878
|
+
|
1879
|
+
##
|
1880
|
+
# "mandatory" SvcParam -- Mandatory keys in service binding RR
|
1881
|
+
|
1882
|
+
class Mandatory < SvcParam
|
1883
|
+
KeyName = :mandatory
|
1884
|
+
KeyNumber = 0
|
1885
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1886
|
+
|
1887
|
+
##
|
1888
|
+
# Mandatory keys.
|
1889
|
+
|
1890
|
+
attr_reader :keys
|
1891
|
+
|
1892
|
+
##
|
1893
|
+
# Initialize "mandatory" ScvParam.
|
1894
|
+
|
1895
|
+
def initialize(keys)
|
1896
|
+
@keys = keys.map(&:to_int)
|
1897
|
+
end
|
1898
|
+
|
1899
|
+
def encode(msg) # :nodoc:
|
1900
|
+
@keys.sort.each do |key|
|
1901
|
+
msg.put_pack('n', key)
|
1902
|
+
end
|
1903
|
+
end
|
1904
|
+
|
1905
|
+
def self.decode(msg) # :nodoc:
|
1906
|
+
keys = msg.get_list { msg.get_unpack('n')[0] }
|
1907
|
+
return self.new(keys)
|
1908
|
+
end
|
1909
|
+
end
|
1910
|
+
|
1911
|
+
##
|
1912
|
+
# "alpn" SvcParam -- Additional supported protocols
|
1913
|
+
|
1914
|
+
class ALPN < SvcParam
|
1915
|
+
KeyName = :alpn
|
1916
|
+
KeyNumber = 1
|
1917
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1918
|
+
|
1919
|
+
##
|
1920
|
+
# Supported protocol IDs.
|
1921
|
+
|
1922
|
+
attr_reader :protocol_ids
|
1923
|
+
|
1924
|
+
##
|
1925
|
+
# Initialize "alpn" ScvParam.
|
1926
|
+
|
1927
|
+
def initialize(protocol_ids)
|
1928
|
+
@protocol_ids = protocol_ids.map(&:to_str)
|
1929
|
+
end
|
1930
|
+
|
1931
|
+
def encode(msg) # :nodoc:
|
1932
|
+
msg.put_string_list(@protocol_ids)
|
1933
|
+
end
|
1934
|
+
|
1935
|
+
def self.decode(msg) # :nodoc:
|
1936
|
+
return self.new(msg.get_string_list)
|
1937
|
+
end
|
1938
|
+
end
|
1939
|
+
|
1940
|
+
##
|
1941
|
+
# "no-default-alpn" SvcParam -- No support for default protocol
|
1942
|
+
|
1943
|
+
class NoDefaultALPN < SvcParam
|
1944
|
+
KeyName = :'no-default-alpn'
|
1945
|
+
KeyNumber = 2
|
1946
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1947
|
+
|
1948
|
+
def encode(msg) # :nodoc:
|
1949
|
+
# no payload
|
1950
|
+
end
|
1951
|
+
|
1952
|
+
def self.decode(msg) # :nodoc:
|
1953
|
+
return self.new
|
1954
|
+
end
|
1955
|
+
end
|
1956
|
+
|
1957
|
+
##
|
1958
|
+
# "port" SvcParam -- Port for alternative endpoint
|
1959
|
+
|
1960
|
+
class Port < SvcParam
|
1961
|
+
KeyName = :port
|
1962
|
+
KeyNumber = 3
|
1963
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1964
|
+
|
1965
|
+
##
|
1966
|
+
# Port number.
|
1967
|
+
|
1968
|
+
attr_reader :port
|
1969
|
+
|
1970
|
+
##
|
1971
|
+
# Initialize "port" ScvParam.
|
1972
|
+
|
1973
|
+
def initialize(port)
|
1974
|
+
@port = port.to_int
|
1975
|
+
end
|
1976
|
+
|
1977
|
+
def encode(msg) # :nodoc:
|
1978
|
+
msg.put_pack('n', @port)
|
1979
|
+
end
|
1980
|
+
|
1981
|
+
def self.decode(msg) # :nodoc:
|
1982
|
+
port, = msg.get_unpack('n')
|
1983
|
+
return self.new(port)
|
1984
|
+
end
|
1985
|
+
end
|
1986
|
+
|
1987
|
+
##
|
1988
|
+
# "ipv4hint" SvcParam -- IPv4 address hints
|
1989
|
+
|
1990
|
+
class IPv4Hint < SvcParam
|
1991
|
+
KeyName = :ipv4hint
|
1992
|
+
KeyNumber = 4
|
1993
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
1994
|
+
|
1995
|
+
##
|
1996
|
+
# Set of IPv4 addresses.
|
1997
|
+
|
1998
|
+
attr_reader :addresses
|
1999
|
+
|
2000
|
+
##
|
2001
|
+
# Initialize "ipv4hint" ScvParam.
|
2002
|
+
|
2003
|
+
def initialize(addresses)
|
2004
|
+
@addresses = addresses.map {|address| IPv4.create(address) }
|
2005
|
+
end
|
2006
|
+
|
2007
|
+
def encode(msg) # :nodoc:
|
2008
|
+
@addresses.each do |address|
|
2009
|
+
msg.put_bytes(address.address)
|
2010
|
+
end
|
2011
|
+
end
|
2012
|
+
|
2013
|
+
def self.decode(msg) # :nodoc:
|
2014
|
+
addresses = msg.get_list { IPv4.new(msg.get_bytes(4)) }
|
2015
|
+
return self.new(addresses)
|
2016
|
+
end
|
2017
|
+
end
|
2018
|
+
|
2019
|
+
##
|
2020
|
+
# "ipv6hint" SvcParam -- IPv6 address hints
|
2021
|
+
|
2022
|
+
class IPv6Hint < SvcParam
|
2023
|
+
KeyName = :ipv6hint
|
2024
|
+
KeyNumber = 6
|
2025
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
2026
|
+
|
2027
|
+
##
|
2028
|
+
# Set of IPv6 addresses.
|
2029
|
+
|
2030
|
+
attr_reader :addresses
|
2031
|
+
|
2032
|
+
##
|
2033
|
+
# Initialize "ipv6hint" ScvParam.
|
2034
|
+
|
2035
|
+
def initialize(addresses)
|
2036
|
+
@addresses = addresses.map {|address| IPv6.create(address) }
|
2037
|
+
end
|
2038
|
+
|
2039
|
+
def encode(msg) # :nodoc:
|
2040
|
+
@addresses.each do |address|
|
2041
|
+
msg.put_bytes(address.address)
|
2042
|
+
end
|
2043
|
+
end
|
2044
|
+
|
2045
|
+
def self.decode(msg) # :nodoc:
|
2046
|
+
addresses = msg.get_list { IPv6.new(msg.get_bytes(16)) }
|
2047
|
+
return self.new(addresses)
|
2048
|
+
end
|
2049
|
+
end
|
2050
|
+
|
2051
|
+
##
|
2052
|
+
# "dohpath" SvcParam -- DNS over HTTPS path template [RFC9461]
|
2053
|
+
|
2054
|
+
class DoHPath < SvcParam
|
2055
|
+
KeyName = :dohpath
|
2056
|
+
KeyNumber = 7
|
2057
|
+
ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
|
2058
|
+
|
2059
|
+
##
|
2060
|
+
# URI template for DoH queries.
|
2061
|
+
|
2062
|
+
attr_reader :template
|
2063
|
+
|
2064
|
+
##
|
2065
|
+
# Initialize "dohpath" ScvParam.
|
2066
|
+
|
2067
|
+
def initialize(template)
|
2068
|
+
@template = template.encode('utf-8')
|
2069
|
+
end
|
2070
|
+
|
2071
|
+
def encode(msg) # :nodoc:
|
2072
|
+
msg.put_bytes(@template)
|
2073
|
+
end
|
2074
|
+
|
2075
|
+
def self.decode(msg) # :nodoc:
|
2076
|
+
template = msg.get_bytes.force_encoding('utf-8')
|
2077
|
+
return self.new(template)
|
2078
|
+
end
|
2079
|
+
end
|
2080
|
+
end
|
2081
|
+
|
1679
2082
|
##
|
1680
2083
|
# A DNS query abstract class.
|
1681
2084
|
|
@@ -2328,7 +2731,7 @@ class Resolv
|
|
2328
2731
|
msg.put_pack("n", @priority)
|
2329
2732
|
msg.put_pack("n", @weight)
|
2330
2733
|
msg.put_pack("n", @port)
|
2331
|
-
msg.put_name(@target)
|
2734
|
+
msg.put_name(@target, compress: false)
|
2332
2735
|
end
|
2333
2736
|
|
2334
2737
|
def self.decode_rdata(msg) # :nodoc:
|
@@ -2339,6 +2742,84 @@ class Resolv
|
|
2339
2742
|
return self.new(priority, weight, port, target)
|
2340
2743
|
end
|
2341
2744
|
end
|
2745
|
+
|
2746
|
+
##
|
2747
|
+
# Common implementation for SVCB-compatible resource records.
|
2748
|
+
|
2749
|
+
class ServiceBinding
|
2750
|
+
|
2751
|
+
##
|
2752
|
+
# Create a service binding resource record.
|
2753
|
+
|
2754
|
+
def initialize(priority, target, params = [])
|
2755
|
+
@priority = priority.to_int
|
2756
|
+
@target = Name.create(target)
|
2757
|
+
@params = SvcParams.new(params)
|
2758
|
+
end
|
2759
|
+
|
2760
|
+
##
|
2761
|
+
# The priority of this target host.
|
2762
|
+
#
|
2763
|
+
# The range is 0-65535.
|
2764
|
+
# If set to 0, this RR is in AliasMode. Otherwise, it is in ServiceMode.
|
2765
|
+
|
2766
|
+
attr_reader :priority
|
2767
|
+
|
2768
|
+
##
|
2769
|
+
# The domain name of the target host.
|
2770
|
+
|
2771
|
+
attr_reader :target
|
2772
|
+
|
2773
|
+
##
|
2774
|
+
# The service paramters for the target host.
|
2775
|
+
|
2776
|
+
attr_reader :params
|
2777
|
+
|
2778
|
+
##
|
2779
|
+
# Whether this RR is in AliasMode.
|
2780
|
+
|
2781
|
+
def alias_mode?
|
2782
|
+
self.priority == 0
|
2783
|
+
end
|
2784
|
+
|
2785
|
+
##
|
2786
|
+
# Whether this RR is in ServiceMode.
|
2787
|
+
|
2788
|
+
def service_mode?
|
2789
|
+
!alias_mode?
|
2790
|
+
end
|
2791
|
+
|
2792
|
+
def encode_rdata(msg) # :nodoc:
|
2793
|
+
msg.put_pack("n", @priority)
|
2794
|
+
msg.put_name(@target, compress: false)
|
2795
|
+
@params.encode(msg)
|
2796
|
+
end
|
2797
|
+
|
2798
|
+
def self.decode_rdata(msg) # :nodoc:
|
2799
|
+
priority, = msg.get_unpack("n")
|
2800
|
+
target = msg.get_name
|
2801
|
+
params = SvcParams.decode(msg)
|
2802
|
+
return self.new(priority, target, params)
|
2803
|
+
end
|
2804
|
+
end
|
2805
|
+
|
2806
|
+
##
|
2807
|
+
# SVCB resource record [RFC9460]
|
2808
|
+
|
2809
|
+
class SVCB < ServiceBinding
|
2810
|
+
TypeValue = 64
|
2811
|
+
ClassValue = IN::ClassValue
|
2812
|
+
ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
|
2813
|
+
end
|
2814
|
+
|
2815
|
+
##
|
2816
|
+
# HTTPS resource record [RFC9460]
|
2817
|
+
|
2818
|
+
class HTTPS < ServiceBinding
|
2819
|
+
TypeValue = 65
|
2820
|
+
ClassValue = IN::ClassValue
|
2821
|
+
ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
|
2822
|
+
end
|
2342
2823
|
end
|
2343
2824
|
end
|
2344
2825
|
end
|
@@ -2464,7 +2945,7 @@ class Resolv
|
|
2464
2945
|
Regex_8HexLinkLocal = /\A
|
2465
2946
|
[Ff][Ee]80
|
2466
2947
|
(?::[0-9A-Fa-f]{1,4}){7}
|
2467
|
-
%[0-9A-Za-z]+
|
2948
|
+
%[-0-9A-Za-z._~]+
|
2468
2949
|
\z/x
|
2469
2950
|
|
2470
2951
|
##
|
@@ -2478,7 +2959,7 @@ class Resolv
|
|
2478
2959
|
|
|
2479
2960
|
:((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
|
2480
2961
|
)?
|
2481
|
-
:[0-9A-Fa-f]{1,4}%[0-9A-Za-z.]+
|
2962
|
+
:[0-9A-Fa-f]{1,4}%[-0-9A-Za-z._~]+
|
2482
2963
|
\z/x
|
2483
2964
|
|
2484
2965
|
##
|
@@ -2558,11 +3039,7 @@ class Resolv
|
|
2558
3039
|
attr_reader :address
|
2559
3040
|
|
2560
3041
|
def to_s # :nodoc:
|
2561
|
-
|
2562
|
-
unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
|
2563
|
-
address.sub!(/(^|:)0(:|$)/, '::')
|
2564
|
-
end
|
2565
|
-
return address
|
3042
|
+
sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn")).sub(/(^|:)0(:0)+(:|$)/, '::')
|
2566
3043
|
end
|
2567
3044
|
|
2568
3045
|
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,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resolv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tanaka Akira
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-12-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Thread-aware DNS resolver library in Ruby.
|
14
14
|
email:
|
@@ -17,6 +17,7 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
+
- ".github/dependabot.yml"
|
20
21
|
- ".github/workflows/test.yml"
|
21
22
|
- ".gitignore"
|
22
23
|
- Gemfile
|
@@ -49,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
50
|
- !ruby/object:Gem::Version
|
50
51
|
version: '0'
|
51
52
|
requirements: []
|
52
|
-
rubygems_version: 3.
|
53
|
+
rubygems_version: 3.5.0.dev
|
53
54
|
signing_key:
|
54
55
|
specification_version: 4
|
55
56
|
summary: Thread-aware DNS resolver library in Ruby.
|