Skip to content

Commit 5cd408a

Browse files
authored
Bump up resolv-0.6.2 for Ruby 3.4 (ruby#13818)
1 parent 66437a4 commit 5cd408a

File tree

4 files changed

+129
-83
lines changed

4 files changed

+129
-83
lines changed

ext/win32/lib/win32/resolv.rb

Lines changed: 70 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@
44
55
=end
66

7-
require 'win32/registry'
8-
97
module Win32
108
module Resolv
11-
API = Registry::API
12-
Error = Registry::Error
13-
149
def self.get_hosts_path
1510
path = get_hosts_dir
1611
path = File.expand_path('hosts', path)
@@ -47,89 +42,103 @@ module Win32
4742
# Windows NT
4843
#====================================================================
4944
module Resolv
50-
module SZ
51-
refine Registry do
52-
# ad hoc workaround for broken registry
53-
def read_s(key)
54-
type, str = read(key)
55-
unless type == Registry::REG_SZ
56-
warn "Broken registry, #{name}\\#{key} was #{Registry.type2name(type)}, ignored"
57-
return String.new
45+
begin
46+
require 'win32/registry'
47+
module SZ
48+
refine Registry do
49+
# ad hoc workaround for broken registry
50+
def read_s(key)
51+
type, str = read(key)
52+
unless type == Registry::REG_SZ
53+
warn "Broken registry, #{name}\\#{key} was #{Registry.type2name(type)}, ignored"
54+
return String.new
55+
end
56+
str
5857
end
59-
str
6058
end
6159
end
60+
using SZ
61+
rescue LoadError
62+
require "open3"
6263
end
63-
using SZ
6464

6565
TCPIP_NT = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters'
6666

6767
class << self
6868
private
6969
def get_hosts_dir
70-
Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
71-
reg.read_s_expand('DataBasePath')
72-
end
70+
get_item_property(TCPIP_NT, 'DataBasePath', expand: true)
7371
end
7472

7573
def get_info
7674
search = nil
7775
nameserver = get_dns_server_list
78-
Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
79-
begin
80-
slist = reg.read_s('SearchList')
81-
search = slist.split(/,\s*/) unless slist.empty?
82-
rescue Registry::Error
83-
end
8476

85-
if add_search = search.nil?
86-
search = []
87-
begin
88-
nvdom = reg.read_s('NV Domain')
89-
unless nvdom.empty?
90-
@search = [ nvdom ]
91-
if reg.read_i('UseDomainNameDevolution') != 0
92-
if /^\w+\./ =~ nvdom
93-
devo = $'
94-
end
95-
end
77+
slist = get_item_property(TCPIP_NT, 'SearchList')
78+
search = slist.split(/,\s*/) unless slist.empty?
79+
80+
if add_search = search.nil?
81+
search = []
82+
nvdom = get_item_property(TCPIP_NT, 'NV Domain')
83+
84+
unless nvdom.empty?
85+
@search = [ nvdom ]
86+
udmnd = get_item_property(TCPIP_NT, 'UseDomainNameDevolution').to_i
87+
if udmnd != 0
88+
if /^\w+\./ =~ nvdom
89+
devo = $'
9690
end
97-
rescue Registry::Error
9891
end
9992
end
93+
end
10094

101-
reg.open('Interfaces') do |h|
102-
h.each_key do |iface, |
103-
h.open(iface) do |regif|
104-
next unless ns = %w[NameServer DhcpNameServer].find do |key|
105-
begin
106-
ns = regif.read_s(key)
107-
rescue Registry::Error
108-
else
109-
break ns.split(/[,\s]\s*/) unless ns.empty?
110-
end
111-
end
112-
next if (nameserver & ns).empty?
113-
114-
if add_search
115-
begin
116-
[ 'Domain', 'DhcpDomain' ].each do |key|
117-
dom = regif.read_s(key)
118-
unless dom.empty?
119-
search.concat(dom.split(/,\s*/))
120-
break
121-
end
122-
end
123-
rescue Registry::Error
124-
end
95+
ifs = if defined?(Win32::Registry)
96+
Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT + '\Interfaces') do |reg|
97+
reg.keys
98+
rescue Registry::Error
99+
[]
125100
end
101+
else
102+
cmd = "Get-ChildItem 'HKLM:\\#{TCPIP_NT}\\Interfaces' | ForEach-Object { $_.PSChildName }"
103+
output, _ = Open3.capture2('powershell', '-Command', cmd)
104+
output.split(/\n+/)
105+
end
106+
107+
ifs.each do |iface|
108+
next unless ns = %w[NameServer DhcpNameServer].find do |key|
109+
ns = get_item_property(TCPIP_NT + '\Interfaces' + "\\#{iface}", key)
110+
break ns.split(/[,\s]\s*/) unless ns.empty?
111+
end
112+
113+
next if (nameserver & ns).empty?
114+
115+
if add_search
116+
[ 'Domain', 'DhcpDomain' ].each do |key|
117+
dom = get_item_property(TCPIP_NT + '\Interfaces' + "\\#{iface}", key)
118+
unless dom.empty?
119+
search.concat(dom.split(/,\s*/))
120+
break
126121
end
127122
end
128123
end
129-
search << devo if add_search and devo
130124
end
125+
search << devo if add_search and devo
131126
[ search.uniq, nameserver.uniq ]
132127
end
128+
129+
def get_item_property(path, name, expand: false)
130+
if defined?(Win32::Registry)
131+
Registry::HKEY_LOCAL_MACHINE.open(path) do |reg|
132+
expand ? reg.read_s_expand(name) : reg.read_s(name)
133+
rescue Registry::Error
134+
""
135+
end
136+
else
137+
cmd = "Get-ItemProperty -Path 'HKLM:\\#{path}' -Name '#{name}' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty '#{name}'"
138+
output, _ = Open3.capture2('powershell', '-Command', cmd)
139+
output.strip
140+
end
141+
end
133142
end
134143
end
135144
end

ext/win32/resolv/resolv.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ w32error_make_error(DWORD e)
1313
return rb_class_new_instance(1, &code, rb_path2class("Win32::Resolv::Error"));
1414
}
1515

16+
NORETURN(static void w32error_raise(DWORD e));
17+
1618
static void
1719
w32error_raise(DWORD e)
1820
{

lib/resolv.rb

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
class Resolv
3535

36-
VERSION = "0.6.0"
36+
VERSION = "0.6.2"
3737

3838
##
3939
# Looks up the first IP address for +name+.
@@ -173,13 +173,16 @@ class ResolvError < StandardError; end
173173

174174
class ResolvTimeout < Timeout::Error; end
175175

176+
WINDOWS = /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
177+
private_constant :WINDOWS
178+
176179
##
177180
# Resolv::Hosts is a hostname resolver that uses the system hosts file.
178181

179182
class Hosts
180-
if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM and
183+
if WINDOWS
181184
begin
182-
require 'win32/resolv'
185+
require 'win32/resolv' unless defined?(Win32::Resolv)
183186
DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL
184187
rescue LoadError
185188
end
@@ -659,8 +662,20 @@ def self.free_request_id(host, port, id) # :nodoc:
659662
}
660663
end
661664

662-
def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
663-
begin
665+
case RUBY_PLATFORM
666+
when *[
667+
# https://www.rfc-editor.org/rfc/rfc6056.txt
668+
# Appendix A. Survey of the Algorithms in Use by Some Popular Implementations
669+
/freebsd/, /linux/, /netbsd/, /openbsd/, /solaris/,
670+
/darwin/, # the same as FreeBSD
671+
] then
672+
def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
673+
udpsock.bind(bind_host, 0)
674+
end
675+
else
676+
# Sequential port assignment
677+
def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
678+
# Ephemeral port number range recommended by RFC 6056
664679
port = random(1024..65535)
665680
udpsock.bind(bind_host, port)
666681
rescue Errno::EADDRINUSE, # POSIX
@@ -983,13 +998,13 @@ def Config.parse_resolv_conf(filename)
983998
next unless keyword
984999
case keyword
9851000
when 'nameserver'
986-
nameserver.concat(args)
1001+
nameserver.concat(args.each(&:freeze))
9871002
when 'domain'
9881003
next if args.empty?
989-
search = [args[0]]
1004+
search = [args[0].freeze]
9901005
when 'search'
9911006
next if args.empty?
992-
search = args
1007+
search = args.each(&:freeze)
9931008
when 'options'
9941009
args.each {|arg|
9951010
case arg
@@ -1000,22 +1015,22 @@ def Config.parse_resolv_conf(filename)
10001015
end
10011016
}
10021017
}
1003-
return { :nameserver => nameserver, :search => search, :ndots => ndots }
1018+
return { :nameserver => nameserver.freeze, :search => search.freeze, :ndots => ndots.freeze }.freeze
10041019
end
10051020

10061021
def Config.default_config_hash(filename="/etc/resolv.conf")
10071022
if File.exist? filename
1008-
config_hash = Config.parse_resolv_conf(filename)
1023+
Config.parse_resolv_conf(filename)
1024+
elsif WINDOWS
1025+
require 'win32/resolv' unless defined?(Win32::Resolv)
1026+
search, nameserver = Win32::Resolv.get_resolv_info
1027+
config_hash = {}
1028+
config_hash[:nameserver] = nameserver if nameserver
1029+
config_hash[:search] = [search].flatten if search
1030+
config_hash
10091031
else
1010-
if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
1011-
require 'win32/resolv'
1012-
search, nameserver = Win32::Resolv.get_resolv_info
1013-
config_hash = {}
1014-
config_hash[:nameserver] = nameserver if nameserver
1015-
config_hash[:search] = [search].flatten if search
1016-
end
1032+
{}
10171033
end
1018-
config_hash || {}
10191034
end
10201035

10211036
def lazy_initialize
@@ -1664,6 +1679,7 @@ def get_labels
16641679
prev_index = @index
16651680
save_index = nil
16661681
d = []
1682+
size = -1
16671683
while true
16681684
raise DecodeError.new("limit exceeded") if @limit <= @index
16691685
case @data.getbyte(@index)
@@ -1684,7 +1700,10 @@ def get_labels
16841700
end
16851701
@index = idx
16861702
else
1687-
d << self.get_label
1703+
l = self.get_label
1704+
d << l
1705+
size += 1 + l.string.bytesize
1706+
raise DecodeError.new("name label data exceed 255 octets") if size > 255
16881707
end
16891708
end
16901709
end
@@ -2110,7 +2129,14 @@ class Resource < Query
21102129

21112130
attr_reader :ttl
21122131

2113-
ClassHash = {} # :nodoc:
2132+
ClassHash = Module.new do
2133+
module_function
2134+
2135+
def []=(type_class_value, klass)
2136+
type_value, class_value = type_class_value
2137+
Resource.const_set(:"Type#{type_value}_Class#{class_value}", klass)
2138+
end
2139+
end
21142140

21152141
def encode_rdata(msg) # :nodoc:
21162142
raise NotImplementedError.new
@@ -2148,7 +2174,9 @@ def hash # :nodoc:
21482174
end
21492175

21502176
def self.get_class(type_value, class_value) # :nodoc:
2151-
return ClassHash[[type_value, class_value]] ||
2177+
cache = :"Type#{type_value}_Class#{class_value}"
2178+
2179+
return (const_defined?(cache) && const_get(cache)) ||
21522180
Generic.create(type_value, class_value)
21532181
end
21542182

@@ -2577,7 +2605,7 @@ def initialize(flags, tag, value)
25772605
end
25782606

25792607
##
2580-
# Flags for this proprty:
2608+
# Flags for this property:
25812609
# - Bit 0 : 0 = not critical, 1 = critical
25822610

25832611
attr_reader :flags

test/resolv/test_dns.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,13 @@ def test_too_big_label_address
627627
assert_operator(2**14, :<, m.to_s.length)
628628
end
629629

630+
def test_too_long_address
631+
too_long_address_message = [0, 0, 1, 0, 0, 0].pack("n*") + "\x01x" * 129 + [0, 0, 0].pack("cnn")
632+
assert_raise_with_message(Resolv::DNS::DecodeError, /name label data exceed 255 octets/) do
633+
Resolv::DNS::Message.decode too_long_address_message
634+
end
635+
end
636+
630637
def assert_no_fd_leak
631638
socket = assert_throw(self) do |tag|
632639
Resolv::DNS.stub(:bind_random_port, ->(s, *) {throw(tag, s)}) do

0 commit comments

Comments
 (0)