Permalink
Browse files

First commit

  • Loading branch information...
0 parents commit e1549a72d2a3d3d8bdd87bdcbb8ba7447e4a2127 @sonicrules1234 committed Nov 17, 2011
Showing with 464 additions and 0 deletions.
  1. 0 README
  2. +5 −0 config.json.dist
  3. +45 −0 listdns.py
  4. +143 −0 namecoindns.py
  5. +248 −0 namecoindnsserver.py
  6. +23 −0 utils.py
0 README
No changes.
5 config.json.dist
@@ -0,0 +1,5 @@
+{
+ "username": "<USERNAME>",
+ "password": "<PASSWORD>",
+ "port": 8336
+}
45 listdns.py
@@ -0,0 +1,45 @@
+from jsonrpc import ServiceProxy
+import json, base64, types, traceback, DNS
+
+def lookup(sp, qdict) :
+ domain = qdict["domain"]
+ if domain.count(".") >= 2 :
+ host = ".".join(domain.split(".")[-2:-1])
+ subdomain = ".".join(domain.split(".")[:-2])
+ else :
+ host = domain.split(".")[0]
+ subdomain = ""
+ #rawlist = json.dumps(rawjson)
+ item = sp.name_scan("d/"+host, 1)[0]
+ if str(item[u"name"]) == "d/" + host :
+ try :
+ value = json.loads(item[u"value"])
+ if value.has_key(u"map") :
+ if type(value[u"map"]) is types.DictType :
+ hasdefault = False
+ for key in value[u"map"].keys()[:] :
+ if key == u"" :
+ hasdefault = True
+ if str(key) == subdomain :
+ if type(value[u"map"][key]) == types.DictType :
+ return dnslookup(value, key, qdict)
+ return str(value[u"map"][u""])
+ #else :
+ #if type(value[u"map"][key]) == types.DictType :
+ #return dnslookup(domain, qt)
+ #return 1, str(value[u"map"][key])
+ if hasdefault :
+ if type(value[u"map"][u""]) == types.DictType :
+ return dnslookup(value, u"", qdict)
+ return str(value[u"map"][u""])
+ except :
+ traceback.print_exc()
+def dnslookup(value, key, qdict) :
+ if value[u"map"][key].has_key(u"ns") :
+ x = DNS.Request(server="8.8.8.8")
+ if type(value[u"map"][key][u"ns"]) == types.UnicodeType :
+ y = x.req(str(value[u"map"][key][u"ns"])).answers[0]["data"]
+ else :
+ y = x.req(str(value[u"map"][key][u"ns"][0])).answers[0]["data"]
+ ns = DNS.Request(server=y)
+ return ns.req(name=qdict["domain"], qtype=qdict["qtype"]).answers[0]
143 namecoindns.py
@@ -0,0 +1,143 @@
+#name_scan "d/yourdomain" 1
+import struct, DNS, listdns, base64, types, json
+from jsonrpc import ServiceProxy
+from utils import *
+
+class Source(object):
+ def __init__(self):
+ #self._answers = {}
+ #self._filename = filename
+ #self._parse_file()
+ self.reqobj = DNS.Request(server="8.8.8.8")
+ jsonfile = open("config.json", "r")
+ data = json.loads(jsonfile.read())
+ jsonfile.close()
+ username = str(data[u"username"])
+ port = data[u"port"]
+ password = str(data[u"password"])
+ self.sp = ServiceProxy("http://%(user)s:%(passwd)s@127.0.0.1:%(port)d" % dict(user=username, passwd=password, port=port))
+
+# def _parse_file(self):
+# f = open(self._filename, "r")
+# for line in f.readlines():
+# line = line.strip()
+# if line and line[0] != '#':
+# question, type, value = line.split()
+# question = question.lower()
+# type = type.upper()
+# if question == '@':
+# question = ''
+# if type == 'A':
+# answer = struct.pack("!I", ipstr2int(value))
+# qtype = 1
+# if type == 'NS':
+# answer = labels2str(value.split("."))
+# qtype = 2
+# elif type == 'CNAME':
+# answer = labels2str(value.split("."))
+# qtype = 5
+# elif type == 'TXT':
+# answer = label2str(value)
+# qtype = 16
+# elif type == 'MX':
+# preference, domain = value.split(":")
+# answer = struct.pack("!H", int(preference))
+# answer += labels2str(domain.split("."))
+# qtype = 15
+# self._answers.setdefault(question, {}).setdefault(qtype, []).append(answer)
+# f.close()
+
+ def isIP(self, host) :
+ parts = host.split(".")
+ if len(parts) != 4:
+ return False
+ try :
+ valid = False
+ for part in parts :
+ intpart = int(part)
+ if intpart <= 255 and intpart >= 0 :
+ valid = True
+ else : return False
+ if valid :
+ return True
+ return False
+ except : return False
+ def get_response(self, query, domain, qtype, qclass, src_addr):
+ print query
+ print domain
+ print qtype
+ print qclass
+ print src_addr
+ if qtype == 1:
+ #answer = struct.pack("!I", ipstr2int(value))
+ reqtype = "A"
+ if qtype == 2:
+ #answer = labels2str(value.split("."))
+ reqtype = "NS"
+ elif qtype == 5:
+ #answer = labels2str(value.split("."))
+ reqtype = "CNAME"
+ elif qtype == 16:
+ #answer = label2str(value)
+ reqtype = "TXT"
+ elif qtype == 15:
+ #preference, domain = value.split(":")
+ #nswer = struct.pack("!H", int(preference))
+ #answer += labels2str(domain.split("."))
+ reqtype = "MX"
+ else : reqtype = None
+ if domain.endswith(".bit") :
+ response = listdns.lookup(self.sp, {"query":query, "domain":domain, "qtype":qtype, "qclass":qclass, "src_addr":src_addr})
+ results = []
+ if type(response) == types.DictType :
+ tempresults = {"qtype":response["type"], "qclass":response["class"], "ttl":response["ttl"]}
+ if response["type"] == 1 :
+ #if answers == [] :
+ # return self.get_response(query, domain, 5, qclass, src_addr)
+ tempresults["rdata"] = struct.pack("!I", ipstr2int(response["data"]))
+ elif response["type"] == 2 or response["type"] == 5:
+ tempresults["rdata"] = labels2str(response["data"].split("."))
+ elif response["type"] == 16 :
+ tempresults["rdata"] = label2str(response["data"])
+ elif response["type"] == 15 :
+ tempresult = struct.pack("!H", response["data"][0])
+ tempresult += labels2str(response["data"][1].split("."))
+ tempresults["rdata"] = tempresult
+ #else : return 3, []
+ results.append(tempresults)
+ return 0, results
+ if type(response) == types.StringType :
+ if self.isIP(response) :
+ return 0, [{"qtype":1, "qclass":qclass, "ttl":300, "rdata":struct.pack("!I", ipstr2int(response))}]
+ return 3, []
+ #if query not in self._answers:
+ #return 3, []
+ #if qtype in self._answers[query]:
+ #if domain == "sonicrules.bit":
+ # results = [{'qtype': 1, 'qclass':qclass, 'ttl': 300, 'rdata': struct.pack("!I", ipstr2int(self.reqobj.req("sonicrules.org", qtype=1).answers[0]["data"]))}]
+ # return 0, results
+ #elif qtype == 1:
+ # if they asked for an A record and we didn't find one, check for a CNAME
+ #return self.get_response(query, domain, 5, qclass, src_addr)
+ else:
+ answers = self.reqobj.req(name=domain, qtype=qtype).answers
+ #print answers
+ results = []
+ for response in answers :
+ tempresults = {"qtype":response["type"], "qclass":response["class"], "ttl":response["ttl"]}
+ if response["type"] == 1 :
+ if answers == [] :
+ return self.get_response(query, domain, 5, qclass, src_addr)
+ tempresults["rdata"] = struct.pack("!I", ipstr2int(response["data"]))
+ elif response["type"] == 2 or response["type"] == 5:
+ tempresults["rdata"] = labels2str(response["data"].split("."))
+ elif response["type"] == 16 :
+ tempresults["rdata"] = label2str(response["data"])
+ elif response["type"] == 15 :
+ tempresult = struct.pack("!H", response["data"][0])
+ tempresult += labels2str(response["data"][1].split("."))
+ tempresults["rdata"] = tempresult
+ #else : return 3, []
+ results.append(tempresults)
+ return 0, results
+ return 3, []
248 namecoindnsserver.py
@@ -0,0 +1,248 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Tom Pinckney
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+# Modified by sonicrules1234 (Westly Ward) in order to have it work as a dns server for all domains rather than just one
+# File originally named pymds
+import sys
+import socket
+import struct
+import ConfigParser
+import signal
+import getopt
+import traceback
+
+from utils import *
+
+class DnsError(Exception):
+ pass
+
+def serve():
+ udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ udps.bind((listen_host, listen_port))
+ #ns_resource_records, ar_resource_records = compute_name_server_resources(_name_servers)
+ ns_resource_records = ar_resource_records = []
+ while True:
+ try:
+ req_pkt, src_addr = udps.recvfrom(512) # max UDP DNS pkt size
+ except socket.error:
+ continue
+ qid = None
+ try:
+ exception_rcode = None
+ try:
+ qid, question, qtype, qclass = parse_request(req_pkt)
+ except:
+ exception_rcode = 1
+ raise Exception("could not parse query")
+ question = map(lambda x: x.lower(), question)
+ found = False
+ source_module = __import__("namecoindns", {}, {}, [''])
+ source_instance = source_module.Source()
+ for config in [True]:
+ #if question[1:] == config['domain']:
+ #query = question[0]
+ #elif question == config['domain']:
+ #query = ''
+ #else:
+ # continue
+ #print question
+ #if len(question) == 2 :
+ query = ""
+ #query = question.split(".")
+ rcode, an_resource_records = source_instance.get_response(query, ".".join(question), qtype, qclass, src_addr)
+ #if rcode == 0 and 'filters' in config:
+ # for f in config['filters']:
+ # an_resource_records = f.filter(query, config['domain'], qtype, qclass, src_addr, an_resource_records)
+ resp_pkt = format_response(qid, question, qtype, qclass, rcode, an_resource_records, ns_resource_records, ar_resource_records)
+ found = True
+ break
+ if not found:
+ exception_rcode = 3
+ raise Exception("query is not for our domain: %s" % ".".join(question))
+ except:
+ traceback.print_exc()
+ if qid:
+ if exception_rcode is None:
+ exception_rcode = 2
+ resp_pkt = format_response(qid, question, qtype, qclass, exception_rcode, [], [], [])
+ else:
+ continue
+ udps.sendto(resp_pkt, src_addr)
+
+def compute_name_server_resources(name_servers):
+ ns = []
+ ar = []
+ for name_server, ip, ttl in name_servers:
+ ns.append({'qtype':2, 'qclass':1, 'ttl':ttl, 'rdata':labels2str(name_server)})
+ ar.append({'qtype':1, 'qclass':1, 'ttl':ttl, 'rdata':struct.pack("!I", ip)})
+ return ns, ar
+
+def parse_request(packet):
+ hdr_len = 12
+ header = packet[:hdr_len]
+ qid, flags, qdcount, _, _, _ = struct.unpack('!HHHHHH', header)
+ qr = (flags >> 15) & 0x1
+ opcode = (flags >> 11) & 0xf
+ rd = (flags >> 8) & 0x1
+ #print "qid", qid, "qdcount", qdcount, "qr", qr, "opcode", opcode, "rd", rd
+ if qr != 0 or opcode != 0 or qdcount == 0:
+ raise DnsError("Invalid query")
+ body = packet[hdr_len:]
+ labels = []
+ offset = 0
+ while True:
+ label_len, = struct.unpack('!B', body[offset:offset+1])
+ offset += 1
+ if label_len & 0xc0:
+ raise DnsError("Invalid label length %d" % label_len)
+ if label_len == 0:
+ break
+ label = body[offset:offset+label_len]
+ offset += label_len
+ labels.append(label)
+ qtype, qclass= struct.unpack("!HH", body[offset:offset+4])
+ if qclass != 1:
+ raise DnsError("Invalid class: " + qclass)
+ return (qid, labels, qtype, qclass)
+
+def format_response(qid, question, qtype, qclass, rcode, an_resource_records, ns_resource_records, ar_resource_records):
+ resources = []
+ resources.extend(an_resource_records)
+ num_an_resources = len(an_resource_records)
+ num_ns_resources = num_ar_resources = 0
+ if rcode == 0:
+ resources.extend(ns_resource_records)
+ resources.extend(ar_resource_records)
+ num_ns_resources = len(ns_resource_records)
+ num_ar_resources = len(ar_resource_records)
+ pkt = format_header(qid, rcode, num_an_resources, num_ns_resources, num_ar_resources)
+ pkt += format_question(question, qtype, qclass)
+ for resource in resources:
+ pkt += format_resource(resource, question)
+ return pkt
+
+def format_header(qid, rcode, ancount, nscount, arcount):
+ flags = 0
+ flags |= (1 << 15)
+ flags |= (1 << 10)
+ flags |= (rcode & 0xf)
+ hdr = struct.pack("!HHHHHH", qid, flags, 1, ancount, nscount, arcount)
+ return hdr
+
+def format_question(question, qtype, qclass):
+ q = labels2str(question)
+ q += struct.pack("!HH", qtype, qclass)
+ return q
+
+def format_resource(resource, question):
+ r = ''
+ r += labels2str(question)
+ r += struct.pack("!HHIH", resource['qtype'], resource['qclass'], resource['ttl'], len(resource['rdata']))
+ r += resource['rdata']
+ return r
+
+#def read_config():
+# for config_file in config_files:
+# config_files[config_file] = config = {}
+# config_parser = ConfigParser.SafeConfigParser()
+# try:
+# config_parser.read(config_file)
+# config_values = config_parser.items("default")
+# except:
+# die("Error reading config file %s\n" % config_file)
+#
+# for var, value in config_values:
+# if var == "domain":
+# config['domain'] = value.split(".")
+# elif var == "name servers":
+# config['name_servers'] = []
+# split_name_servers = value.split(":")
+# num_split_name_servers = len(split_name_servers)
+# for i in range(0,num_split_name_servers,3):
+# server = split_name_servers[i]
+# ip = split_name_servers[i+1]
+# ttl = int(split_name_servers[i+2])
+# config['name_servers'].append((server.split("."), ipstr2int(ip), ttl))
+# elif var == 'source':
+# module_and_args = value.split(":")
+# module = module_and_args[0]
+# args = module_and_args[1:]
+# source_module = __import__(module, {}, {}, [''])
+# source_instance = source_module.Source(*args)
+# config['source'] = source_instance
+# elif var == 'filters':
+# config['filters'] = []
+# for module_and_args_str in value.split():
+# module_and_args = module_and_args_str.split(":")
+# module = module_and_args[0]
+# args = module_and_args[1:]
+# filter_module = __import__(module, {}, {}, [''])
+# filter_instance = filter_module.Filter(*args)
+# config['filters'].append(filter_instance)
+# else:
+# die("unrecognized paramter in conf file %s: %s\n" % (config_file, var))
+#
+# if 'domain' not in config or 'source' not in config:
+# die("must specify domain name and source in conf file %s\n", config_file)
+# sys.stderr.write("read configuration from %s\n" % config_file)
+
+#def reread(signum, frame):
+# read_config()
+
+def die(msg):
+ sys.stderr.write(msg)
+ sys.exit(-1)
+
+def usage(cmd):
+ die("Usage: %s\n" % (cmd))
+
+#config_files = {}
+listen_port = 53
+listen_host = ''
+
+#try:
+# options, filenames = getopt.getopt(sys.argv[1:], "p:h:")
+#except getopt.GetoptError:
+# usage(sys.argv[0])
+
+#for option, value in options:
+# if option == "-p":
+# listen_port = int(value)
+# elif option == "-h":
+# listen_host = value
+#if not filenames:
+# filenames = ['pymds.conf']
+#for f in filenames:
+# if f in config_files:
+# raise Exception("repeated configuration")
+# config_files[f] = {}
+
+sys.stdout.write("Starting %s\n" % (sys.argv[0]))
+#read_config()
+#signal.signal(signal.SIGHUP, reread)
+#for config in config_files.values():
+# sys.stdout.write("%s: serving for domain %s\n" % (sys.argv[0], ".".join(config['domain'])))
+sys.stdout.flush()
+sys.stderr.flush()
+serve()
23 utils.py
@@ -0,0 +1,23 @@
+#This was not written by sonicrules1234, look in namecoindnsserver.py at the top for the actual author
+import struct
+
+def label2str(label):
+ s = struct.pack("!B", len(label))
+ s += label
+ return s
+
+def labels2str(labels):
+ s = ''
+ for label in labels:
+ s += label2str(label)
+ s += struct.pack("!B", 0)
+ return s
+
+def ipstr2int(ipstr):
+ ip = 0
+ i = 24
+ for octet in ipstr.split("."):
+ ip |= (int(octet) << i)
+ i -= 8
+ return ip
+

0 comments on commit e1549a7

Please sign in to comment.