Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
gleicon committed Mar 7, 2012
0 parents commit 2c2d399
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 0 deletions.
20 changes: 20 additions & 0 deletions README.md
@@ -0,0 +1,20 @@
Python, DNS and Redis

Simple servers to deliver customized DNS data. These servers rely on Redis as storage backend.

Both of them rely on google's dns as fallback

gevent version
==============
gevent_dns.py

to create a new domain:
set IP:name ip_addr
set TXT:name txtfield

twisted version
===============
tx_dns.py

create a new domain SET:
domain.tld ip_addr
61 changes: 61 additions & 0 deletions gevent_dns.py
@@ -0,0 +1,61 @@
# dns server using dnslib and gevent
# based on https://bitbucket.org/paulc/dnslib/src/80d85555aae4/src/server/gevent_server.py
# set the key as
# set IP:name ip_addr
# set TXT:name txtfield
# fallback on gevent's dns resolver
# gleicon 2011


import gevent
from gevent import socket
import gevent.dns;
from gevent import monkey;
monkey.patch_socket()

import urllib2,sys
import redis
import random
from dnslib import *


AF_INET = 2
SOCK_DGRAM = 2

s = socket.socket(AF_INET,SOCK_DGRAM)
s.bind(('',53))

def dns_handler(s, peer, data, r):
request = DNSRecord.parse(data)
id = request.header.id
qname = request.q.qname
qtype = request.q.qtype
IP = r.get("IP:%s" % qname)
TXT = r.get("TXT:%s" % qname)
if not IP:
try:
IP = socket.gethostbyname(str(qname))
except Exception, e:
print 'Host not found'
IP = '0.0.0.0'
print "Request (%s): %r (%s) - Response: %s" % (str(peer), qname.label, QTYPE[qtype], IP)
reply = DNSRecord(DNSHeader(id=id,qr=1,aa=1,ra=1),q=request.q)
if qtype == QTYPE.A:
reply.add_answer(RR(qname,qtype,rdata=A(IP)))
elif qtype == QTYPE['*']:
reply.add_answer(RR(qname,QTYPE.A,rdata=A(IP)))
reply.add_answer(RR(qname,QTYPE.MX,rdata=MX(IP)))
reply.add_answer(RR(qname,QTYPE.TXT,rdata=TXT(TXT)))
else:
reply.add_answer(RR(qname,QTYPE.CNAME,rdata=CNAME(TXT)))
s.sendto(reply.pack(),peer)


def main():
r = redis.Redis()
while True:
data,peer = s.recvfrom(8192)
gevent.spawn(dns_handler, s, peer, data, r)

if __name__ == '__main__':
main()
48 changes: 48 additions & 0 deletions tx_dns.py
@@ -0,0 +1,48 @@
# Python/Twisted/Redis backed DNS server - resolves from NAME to IP addrs
# fallback to google or any other DNS server to resolv domains not present on Redis
# to set a new domain on redis, just issue a SET domain.tld ip_addr
# run with twistd -ny txredns.tac
# gleicon 2011

from twisted.names import dns, server, client, cache
from twisted.application import service, internet
from twisted.internet import defer
from twisted.python import log
import txredisapi

class RedisResolverBackend(client.Resolver):
def __init__(self, redis, servers=None):
self.redis = redis
client.Resolver.__init__(self, servers=servers)
self.ttl = 5

@defer.inlineCallbacks
def _get_ip_addr(self, hostname, timeout):
ip = yield self.redis.get(hostname)
r = None
if ip:
defer.returnValue([(dns.RRHeader(hostname, dns.A, dns.IN, self.ttl, dns.Record_A(ip, self.ttl)),), (), ()])
else:
i = yield self._lookup(hostname, dns.IN, dns.A, timeout)
defer.returnValue(i)

def lookupAddress(self, name, timeout = None):
return self._get_ip_addr(name, timeout)

def create_application():
rd = txredisapi.lazyRedisConnectionPool()
redisBackend = RedisResolverBackend(rd, servers=[('8.8.8.8', 53)])

application = service.Application("txdnsredis")
srv_collection = service.IServiceCollection(application)

dnsFactory = server.DNSServerFactory(caches=[cache.CacheResolver()], clients=[redisBackend])

internet.TCPServer(53, dnsFactory).setServiceParent(srv_collection)
internet.UDPServer(53, dns.DNSDatagramProtocol(dnsFactory)).setServiceParent(srv_collection)
return application

# .tac app
application = create_application()


0 comments on commit 2c2d399

Please sign in to comment.