[Half-working] .bit resolver in Power DNS

Forum rules
Warning !
Avoid using binary softwares from untrusted users.
Prefer compiling it yourself and verify sources.
Post Reply
fwaggle
Posts: 1
Joined: Fri Oct 21, 2011 5:25 am
os: bsd

[Half-working] .bit resolver in Power DNS

Post by fwaggle »

I've started working on a resolver for .bit that's real-time and doesn't involve sweeping all the zones over into BIND zones. I have a BIND server on my border router, which forwards, all requests to the .bit zone to a PowerDNS server, which also runs the namecoin daemon.

I apologize that it's not complete, but I'm having a really rough time with it. It's probably terrible Python, I'm very new to Python and not particularly good at thinking in OOP. Feel free to make fun of my bad Python, or point out smarter ways to do one thing or another.

I had some fun writing it, and I can browse .bit domains from any browser on my network seamlessly, as long as the .bit domain has the actual DNS records in the blockchain and doesn't do DNS forwarding or translation or anything.

To install the appropriate software on Debian (assumes working namecoind):

Code: Select all

# apt-get install pdns-server  pdns-backend-pipe
Your resolver needs to be set up to forward to PowerDNS (I'm using BIND for my main resolver):

Code: Select all

zone "bit." IN {
        type forward;
        forward only;
        forwarders { 10.0.1.35; };
};
Then in the pdns.conf:

Code: Select all

launch=pipe
pipe-command=/path/to/resolve.py
What it does:
  • Resolves plain IPs, including subdomains stored in maps in the blockchain.
  • Makes a half-arsed effort at a sane SOA record
  • It should forward to a ToR service via CNAME, however testing this is difficult as at the moment I can't find any domains that have ToR record. I have registered a new domain that I'll put a tor record on, but it needs to wait for 12 blocks.
What it doesn't do:
  • Aliases don't work yet
  • wildcards do not work yet.
  • Translated domains do not work yet.
  • DNS forwarding doesn't work yet. I'm not even sure I can make it work in the way I'm trying (I don't grok PowerDNS all that well, so what I'm trying may be impossible, but it's probably more likely I'm just trying it wrong), but figuring it out is made really difficult that I believe many domains have really broken DNS. Almost everything registered by register.dot-bit.org is broken (ns[01].web-sweet-web.net do not appear to be authoritative for any .bit domains), including d/explorer and others. I found the domain d/vj that appears to have working nameservers, and while it's late and I'm sleepy, I don't think it's "value" record is up to specs.
Finally, the code for the pipebackend resolver (work in progress):

Code: Select all

#! /usr/bin/python -u

import sys
import json
import socket
from jsonrpc import ServiceProxy

# check for hello
line = sys.stdin.readline().rstrip()
if (line != "HELO\t1"):
	print "LOG	Bad HELO"
	print "FAIL\n"
	sys.exit(-1)

namecoin = ServiceProxy("http://fwaggle:test@127.0.0.1:8332");

print "OK	Namecoin resolver starting up."

# main loop

while 1:
	# fetch input
	try:
		line = sys.stdin.readline().rstrip()
	except KeyboardInterrupt:
		break
	
	if not line:
		break
	
	req = line.split("\t")
	if req[0] == "AXFR":
		print "LOG	AXFR Requested - not implemented"
		print "FAIL"
		continue
	if len(req) < 6:
		print "LOG	Bad request"
		print "FAIL"
		continue # next request
	
	type = req[0]
	qname = req[1]
	qclass = req[2]
	qtype = req[3]
	id = req[4]
	ip = req[5]
	
	# split apart hostname
	name = qname.split(".")
	
	# only interested in .bit TLD
	if name[len(name) -1] != "bit":
		print "END"
		continue
	
	# get domain and subdomains
	sub = name[0:len(name) -2]
	sub.reverse()
	name = "d/" + name[len(name) -2]
	
	print "LOG	Lookup: %s (%s)" % (name, qtype)
	
	# perform lookup via namecoin
	lookup = namecoin.name_scan(name, 1)
	
	# domain does not exist?
	if lookup[0]['name'] != name:
		print "END"
		continue
	
	# decode JSON in value field
	try:
		dvalue = json.loads(lookup[0]['value'])
		print "LOG	%s" % dvalue
	except:
		print "LOG	JSON decode failed."
		print "FAIL"
		continue

	hostmaster = None

	# check for SOA related stuff
	if 'email' in dvalue:
		hostmaster = dvalue['email'].replace('@','.')
	else:
		hostmaster = 'root.10.0.1.35'
		
	# check for DNS forwarding
	if 'dns' in dvalue:
		if isinstance(dvalue['dns'], basestring):
			if qtype == "NS" or qtype == "ANY":
				ns = socket.gethostbyname(dvalue['dns'])
				print "DATA	%s	%s	NS	600	-1	%s" % (qname, qclass, ns)
		else:
			soa = 0
			for x in dvalue['dns']:
				ns = socket.gethostbyname(x)
				if soa == 0:
					soa = 1
					if qtype == "SOA" or qtype == "ANY":
						print "DATA	%s	%s	SOA	600	-1	%s. %s 1 600 3600 604800 600" % (qname, qclass, x, hostmaster)
				if qtype == "NS" or qtype == "ANY":
					print "DATA	%s	%s	NS	600	-1	%s" % (qname, qclass, x)
		print "END"
	
	# zone is in blockchain
	elif 'map' in dvalue or 'ip' in dvalue:
		result = None

		# checking for root domain:
		if len(sub) < 1:
			if 'ip' in dvalue:
				result = dvalue['ip']
			elif 'tor' in dvalue:
				if qtype == "CNAME" or qtype == "ANY":
					print "DATA	%s	%s	CNAME	600	-1	%s." % (qname, qclass, dvalue['tor'])
				print "END"
				continue
			else:
				try:
					result = dvalue['map']['']
				except:
					pass

		# checking for subdomain
		else:
			# if we have no "map" value, no subdomains
			if 'map' not in dvalue:
				print "END"
				continue
			
			map = dvalue['map']
			
			for s in sub:
				# hostname does not exist:
				if s not in map:
					print "END"
					continue
				
				try:
					map = map[s]
					if 'map' in map:
						map = map['map']
				except:
					map = None
					break

			if map == None:
				print "END"
				continue
			
			if 'alias' in map:
				print "LOG	alias: %s (not implemented)" % map['alias']
				print "END"
				continue
			
			if 'tor' in dvalue:
				if qtype == "CNAME" or qtype == "ANY":
					print "DATA	%s	%s	CNAME	600	-1	%s." % (qname, qclass, dvalue['tor'])
				print "END"
				continue
				
			if 'ip' not in map:
				print "END"
				continue
			result = map['ip']

		if result != None:
			if isinstance(result, basestring):
				if qtype == "A" or qtype == "ANY":
					print "DATA	%s	%s	A	600	-1	%s" % (qname, qclass, result)
			else:
				for x in result:
					if qtype == "A" or qtype == "ANY":
						print "DATA	%s	%s	A	600	-1	%s" % (qname, qclass, x)
	else:
		for x in dvalue:
			print x
	print "END"
	continue

khal
Site Admin
Posts: 708
Joined: Mon May 09, 2011 5:09 pm
os: linux

Re: [Half-working] .bit resolver in Power DNS

Post by khal »

fwaggle wrote: [*]It should forward to a ToR service via CNAME, however testing this is difficult as at the moment I can't find any domains that have ToR record. I have registered a new domain that I'll put a tor record on, but it needs to wait for 12 blocks.
I don't think that the "alias" record should be used to forward to a tor service (an onion address)... The "tor" record should by used for this, which requires a tor server + a proxy, things not covered by your software (the way nmcsocks is working). Or maybe i misunderstood what you want to redirect ?
fwaggle wrote: [*]DNS forwarding doesn't work yet. I'm not even sure I can make it work in the way I'm trying (I don't grok PowerDNS all that well, so what I'm trying may be impossible, but it's probably more likely I'm just trying it wrong), but figuring it out is made really difficult that I believe many domains have really broken DNS. Almost everything registered by register.dot-bit.org is broken (ns[01].web-sweet-web.net do not appear to be authoritative for any .bit domains), including d/explorer and others. I found the domain d/vj that appears to have working nameservers, and while it's late and I'm sleepy, I don't think it's "value" record is up to specs.[/list]
ns[01].web-sweet-web.net should be authoritative for a lot of .bit domains, including explorer.bit and dns.bit. Maybe you made your tests during the server upgrade (that had changed zone configuration until i resolved the bug) or maybe something is wrong on my side ? :p (remember that both "dns" and "ns" keywords are valid in the json value)


This thread may have some interest for you too :
https://dot-bit.org/forum/viewtopic.php?p=2295#p2295
and this comment: https://dot-bit.org/forum/viewtopic.php?p=2295#p2295

ps : python-json-rpc is not available on debian, so you must install it manually.
NamecoinID: id/khal
GPG : 9CC5B92E965D69A9
NMC: N1KHAL5C1CRzy58NdJwp1tbLze3XrkFxx9
BTC: 1KHAL8bUjnkMRMg9yd2dNrYnJgZGH8Nj6T

Register Namecoin domains with BTC
My bitcoin Identity - Send messages to bitcoin users
Charity Ad - Make a good deed without paying a cent

Post Reply