sonots/resolver_replace を使ってみたら再帰して too many open files になったので別の方法を探る事に。といっても、Ruby に付いてくる resolv-replace
を使うだけで良かった。
DNS サーバ
ioquatix/rubydns を使って、 *.dev
なドメインを 127.0.0.1
として解決し、それ以外は上流に任せるという DNS サーバを書く。以下は rubydns の README ほぼそのまま。
#!/usr/bin/env ruby
require 'rubydns'
# Use upstream DNS for name resolution.
upstream = RubyDNS::Resolver.new([[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]])
# Start the RubyDNS server
RubyDNS.run_server(listen: [[:udp, '0.0.0.0', 5300], [:tcp, '0.0.0.0', 5300]]) do
match(/\.dev/, Resolv::DNS::Resource::IN::A) do |transaction|
transaction.respond!('127.0.0.1')
end
# Default DNS handler
otherwise do |transaction|
transaction.passthrough!(upstream)
end
end
WEB サーバ
DNS resolver が変更できているか確認するために、ローカルホストで適当なウェブサーバを動かす。
require 'sinatra'
get '/' do
'OK'
end
検証
以下の様なスクリプトで、プログラム中でのみ DNS resolver を変更できるかを確認。
require 'resolv'
require 'resolv-replace'
require 'open-uri'
resolver = Resolv::DNS.new(nameserver_port: [['127.0.0.1', 5300]])
Resolv::DefaultResolver.replace_resolvers([Resolv::Hosts.new, resolver])
puts open('http://hoge.dev:4567').read
-
Resolv::DNS
で任意の DNS サーバのインスタンスを作り、Resolv::DefaultResolver.replace_resolvers
でResolv::DefaultResolver
の中身を入れ替える -
resolv-replace.rb
をロードしていれば、モンキーパッチによってソケットの#getaddress
がResolv::DefaultResolver
を使って名前解決する様になる- なお、
#gethostbyname
などは対象外なので、ホストで設定されている DNS resolver を使い続ける
- なお、
-
Resolv::DefaultResolver
はソケットの#getaddress
のレシーバ