Skip to content

Instantly share code, notes, and snippets.

@kotnik
Created June 6, 2013 14:51
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save kotnik/5722085 to your computer and use it in GitHub Desktop.
Save kotnik/5722085 to your computer and use it in GitHub Desktop.
Example of how to create a DNS server in Python, based on Twisted libraries.
from collections import Mapping
from twisted.names import dns, server, client, cache
from twisted.application import service, internet
class MapResolver(client.Resolver):
def __init__(self, mapping, servers):
client.Resolver.__init__(self, servers=servers)
self.mapping = mapping
self.ttl = 10
def lookupAddress(self, name, timeout = None):
if name in self.mapping:
# We know the answer.
value = self.mapping[name]
return [
(
dns.RRHeader(
name, dns.A, dns.IN, self.ttl,
dns.Record_A(value, self.ttl)
),
),
(),
()
]
else:
# Ask our backend server.
return self._lookup(name, dns.IN, dns.A, timeout)
class CustomMapping(Mapping):
def __init__(self, servers):
self._servers = servers
def __getitem__(self, key):
return self._servers[key]
def __iter__(self):
return self._servers.iterkeys()
def __len__(self):
return len(self._servers)
# Our custom resolver.
custom_mapping = CustomMapping({"example.com": "33.33.33.33"})
# Upstream DNS server.
upstream_dns = "8.8.8.8"
# Setup Twisted application.
application = service.Application('dnsserver', 1, 1)
simpledns = MapResolver(custom_mapping, servers=[(upstream_dns, 53)])
# Create protocols.
f = server.DNSServerFactory(caches=[cache.CacheResolver()], clients=[simpledns])
p = dns.DNSDatagramProtocol(f)
f.noisy = p.noisy = False
# Register both TCP and UDP on port 53.
ret = service.MultiService()
PORT = 53
# Attach services to the parent.
for (klass, arg) in [(internet.TCPServer, f), (internet.UDPServer, p)]:
s = klass(PORT, arg)
s.setServiceParent(ret)
# Run as a twistd application.
ret.setServiceParent(service.IServiceCollection(application))
if __name__ == '__main__':
import sys
print "Usage: twistd -ny %s" % sys.argv[0]
@ozk-07
Copy link

ozk-07 commented Apr 18, 2019

Help us please.. When I type example.com in "custom_mapping = CustomMapping ({"example.com": "33.33.33.33"})" the address does not appear as 33.33.33.33. How can I do it?

@curtisforrester
Copy link

Needs a slight modification if running under Python 3.7. The name parameter to lookupAddress will be bytes; the key in CustomMapping is string, so the lookup will fail. One hack is to convert the name to string:

if isinstance(name, bytes):
    name = name.decode()

if name in self.mapping:
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment