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 hidden or 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] |
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
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?