Skip to content

Commit b25c63c

Browse files
authored
Merge pull request #54 from ruby/win32-resolv
Import win32/resolv.rb that is required on Windows
2 parents 5171095 + 48e427b commit b25c63c

File tree

4 files changed

+210
-0
lines changed

4 files changed

+210
-0
lines changed

.git-blame-ignore-revs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# This is a file used by GitHub to ignore the following commits on `git blame`.
2+
#
3+
# You can also do the same thing in your local repository with:
4+
# $ git config --local blame.ignoreRevsFile .git-blame-ignore-revs
5+
6+
# Expand tabs
7+
9ae210665a8524554e7c868d3ec67af54b0958bb

ext/win32/resolv/extconf.rb

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
if have_library('iphlpapi', 'GetNetworkParams')
2+
create_makefile('win32/resolv')
3+
end

ext/win32/resolv/lib/win32/resolv.rb

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# frozen_string_literal: false
2+
=begin
3+
= Win32 DNS and DHCP I/F
4+
5+
=end
6+
7+
require 'win32/registry'
8+
9+
module Win32
10+
module Resolv
11+
API = Registry::API
12+
Error = Registry::Error
13+
14+
def self.get_hosts_path
15+
path = get_hosts_dir
16+
path = File.expand_path('hosts', path)
17+
File.exist?(path) ? path : nil
18+
end
19+
20+
def self.get_resolv_info
21+
search, nameserver = get_info
22+
if search.empty?
23+
search = nil
24+
else
25+
search.delete("")
26+
search.uniq!
27+
end
28+
if nameserver.empty?
29+
nameserver = nil
30+
else
31+
nameserver.delete("")
32+
nameserver.delete("0.0.0.0")
33+
nameserver.uniq!
34+
end
35+
[ search, nameserver ]
36+
end
37+
end
38+
end
39+
40+
begin
41+
require 'win32/resolv.so'
42+
rescue LoadError
43+
end
44+
45+
module Win32
46+
#====================================================================
47+
# Windows NT
48+
#====================================================================
49+
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
58+
end
59+
str
60+
end
61+
end
62+
end
63+
using SZ
64+
65+
TCPIP_NT = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters'
66+
67+
class << self
68+
private
69+
def get_hosts_dir
70+
Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT) do |reg|
71+
reg.read_s_expand('DataBasePath')
72+
end
73+
end
74+
75+
def get_info
76+
search = nil
77+
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
84+
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
96+
end
97+
rescue Registry::Error
98+
end
99+
end
100+
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
125+
end
126+
end
127+
end
128+
end
129+
search << devo if add_search and devo
130+
end
131+
[ search.uniq, nameserver.uniq ]
132+
end
133+
end
134+
end
135+
end

ext/win32/resolv/resolv.c

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include <ruby.h>
2+
#include <ruby/encoding.h>
3+
#include <windows.h>
4+
#ifndef NTDDI_VERSION
5+
#define NTDDI_VERSION 0x06000000
6+
#endif
7+
#include <iphlpapi.h>
8+
9+
static VALUE
10+
w32error_make_error(DWORD e)
11+
{
12+
VALUE code = ULONG2NUM(e);
13+
return rb_class_new_instance(1, &code, rb_path2class("Win32::Resolv::Error"));
14+
}
15+
16+
static void
17+
w32error_raise(DWORD e)
18+
{
19+
rb_exc_raise(w32error_make_error(e));
20+
}
21+
22+
static VALUE
23+
get_dns_server_list(VALUE self)
24+
{
25+
FIXED_INFO *fixedinfo = NULL;
26+
ULONG buflen = 0;
27+
DWORD ret;
28+
VALUE buf, nameservers = Qnil;
29+
30+
ret = GetNetworkParams(NULL, &buflen);
31+
if (ret != NO_ERROR && ret != ERROR_BUFFER_OVERFLOW) {
32+
w32error_raise(ret);
33+
}
34+
fixedinfo = ALLOCV(buf, buflen);
35+
ret = GetNetworkParams(fixedinfo, &buflen);
36+
if (ret == NO_ERROR) {
37+
const IP_ADDR_STRING *ipaddr = &fixedinfo->DnsServerList;
38+
nameservers = rb_ary_new();
39+
do {
40+
const char *s = ipaddr->IpAddress.String;
41+
if (!*s) continue;
42+
if (strcmp(s, "0.0.0.0") == 0) continue;
43+
rb_ary_push(nameservers, rb_str_new_cstr(s));
44+
} while ((ipaddr = ipaddr->Next) != NULL);
45+
}
46+
ALLOCV_END(buf);
47+
if (ret != NO_ERROR) w32error_raise(ret);
48+
49+
return nameservers;
50+
}
51+
52+
void
53+
InitVM_resolv(void)
54+
{
55+
VALUE mWin32 = rb_define_module("Win32");
56+
VALUE resolv = rb_define_module_under(mWin32, "Resolv");
57+
VALUE singl = rb_singleton_class(resolv);
58+
rb_define_private_method(singl, "get_dns_server_list", get_dns_server_list, 0);
59+
}
60+
61+
void
62+
Init_resolv(void)
63+
{
64+
InitVM(resolv);
65+
}

0 commit comments

Comments
 (0)