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
Code: Select all
zone "bit." IN {
type forward;
forward only;
forwarders { 10.0.1.35; };
};
Code: Select all
launch=pipe
pipe-command=/path/to/resolve.py
- 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.
- 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.
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