Created
June 6, 2013 14:51
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Needs a slight modification if running under Python 3.7. The
name
parameter tolookupAddress
will be bytes; the key in CustomMapping is string, so the lookup will fail. One hack is to convert thename
to string: