Skip to content

Instantly share code, notes, and snippets.

@icy
Last active March 22, 2020 15:39
Show Gist options
  • Save icy/aede7b6bf5ac153073828734497808b4 to your computer and use it in GitHub Desktop.
Save icy/aede7b6bf5ac153073828734497808b4 to your computer and use it in GitHub Desktop.
my-dns-resolver.rb
#!/usr/bin/env ruby
# Purpose : Extremely stupid dns resolver for laptop
# Author : Ky-Anh Huynh
# License : MIT
# Requirements
#
# * dnscrypt-proxy, or another upstream listen on 127.0.0.1:52
# * NetworkManager
# * Enable this dns resolver and make /etc/resolv.conf immutable
# ( rm /etc/resolv.conf; echo nameserver 127.0.0.1 > /etc/resolv.conf; chattr +i /etc/resolv.conf ;)
#
# Dealing with captive portal (Remember to remove them after you're connected :D)
#
# $ sudo touch /root/enable_isp
#
require 'rubydns'
LISTEN_PORT = (ENV["MDNS_PORT"].to_s.empty? ? 53 : ENV["MDNS_PORT"].to_i)
# Where we are listening on
INTERFACES = [
[:udp, "0.0.0.0", LISTEN_PORT],
[:tcp, "0.0.0.0", LISTEN_PORT],
]
# Alias
IN = Resolv::DNS::Resource::IN
# The main upstream
UPSTREAM = RubyDNS::Resolver.new(
[
[:udp, "127.0.0.1", 52],
[:tcp, "127.0.0.1", 52],
])
# To use the ISP/router resolvers, just touch a file
# $ sudo touch /root/enable_isp
#
# FIXME: We don't have cache here, so it's a bit slow ;)
def next_upstream
isp_resolv_conf = "/run/NetworkManager/resolv.conf"
resolvers = []
if File.exist?("/root/enable_isp") and File.exist?(isp_resolv_conf)
STDERR.puts "using isp dns resolvers..."
lines = File.open(isp_resolv_conf, "r").readlines
lines.each do |line|
if gs = line.match(/^nameserver (.+)/)
STDERR.puts "found isp dns resolver: #{gs[1]}"
resolvers << gs[1]
end
end
end
if resolvers.size > 0
STDERR.puts "using upstream: #{resolvers}"
ret = RubyDNS::Resolver.new(resolvers.map{|ip| [:udp, ip, 53]})
else
STDERR.puts "using default upstream on your localhost"
ret = UPSTREAM
end
return ret
end
RubyDNS::run_server(INTERFACES) do
# This is just an example for fun
match("incoming.telemetry.mozilla.org") do |t|
t.respond!("127.0.0.1")
end
# Your own domains
match(%r{kyanh.net}, IN::A) do |t|
my_ip = "192.168.192.168"
my_ip = "127.0.0.1"
STDERR.puts "client #{t.options[:remote_address].ip_address} asked #{t.question} got #{my_ip}"
t.respond!(my_ip)
end
otherwise do |t|
t.passthrough!(next_upstream)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment