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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be8cc01e584a5861d458d566337d00aeafab62860c2170612c1df385df352f0d
4
- data.tar.gz: 4810a106bcf7e982c68c9e8a6a1ff19a5614deacbdabd6859b0d2078fba48c0d
3
+ metadata.gz: 56680c64e918a60193f43e3ca4a7093db20bbe66f516da79a159d9a3c05860d8
4
+ data.tar.gz: f017a2c89fbcdf946b69ce57d41a67537b73f54ec6e99d18cc62865fd6ec1633
5
5
  SHA512:
6
- metadata.gz: 5a8d2b5467bc3af582454742074a91f2d43dbeac233cf33c299541e8c208ff0ef31abe694e7d8b70d6aaf14793df90c7e6fbf976ddc3a989d627f12d59d7c1a7
7
- data.tar.gz: 2898499c18aae2c0f5700084e82cff594c60920e6d5a3782470e18a3001d101d602810b5aa423067be46099d05f144bf508c0d18ce5c7ef566c3f038906e3823
6
+ metadata.gz: d57f866a30bc2b8da6dbcdb8c65d0a5db4630af4ec0244aa490e37370ba7b27c3031e153e76055e7f4f63114bd477944326b05dbb7319f97bf59478f8518d76a
7
+ data.tar.gz: f07e85287b3bb9973c90900c1fbdc272e193d91493e63b407e696cc9f52de29fc0716f2ec11aba56d37d89a12b6d3fec55d21bd8ce756f02d56577940c454b06
@@ -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: [ '3.0', 2.7, 2.6, 2.5, head ]
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@v3
24
+ - uses: actions/checkout@v4
15
25
  - name: Set up Ruby
16
26
  uses: ruby/setup-ruby@v1
17
27
  with:
data/.gitignore CHANGED
@@ -6,3 +6,5 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+
10
+ Gemfile.lock
data/Gemfile CHANGED
@@ -1,4 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
+ gemspec
4
+
3
5
  gem "rake"
4
6
  gem "test-unit"
7
+ gem "test-unit-ruby-core"
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=[Hosts.new, DNS.new])
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, hostname, *aliases = line.split(/\s+/)
197
+ addr, *hostnames = line.split(/\s+/)
196
198
  next unless addr
197
- @addr2name[addr] = [] unless @addr2name.include? addr
198
- @addr2name[addr] << hostname
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 += args
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
- address = sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn"))
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 = "resolv"
3
- spec.version = "0.2.2"
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.2.2
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: 2022-12-05 00:00:00.000000000 Z
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.4.0.dev
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: []