[Twisted-Python] Handeling unresolved DNS queries?

Hi Guys, Im playing with a dns-cache script, that overrides DNS requests for certain IP addresses. I would like to add functionality, so unresolved requests are sent to a spicific IP. How do I go about doing that? Is there a negative answer in the (udp) DNS protocol or am I forced to use a timeout. Kind regards Tax import sys, os from socket import * from twisted.internet.protocol import Factory, Protocol from twisted.internet import reactor from twisted.names import dns, client, server import time LOGFILE = 'dnsfilter.log' def allowip(ip): return True class Log: """file like for writes with auto flush after each write to ensure that everything is logged, even during an unexpected exit.""" def __init__(self, f): self.f = f def write(self, s): self.f.write(s) self.f.flush() if __name__ == "__main__": dns_servers = [] f = open('/etc/resolv.conf', "r") while 1: line = f.readline() if not line: break if line[0]!='#': s, ns = line.strip().split(' ') if s == 'nameserver': dns_servers.append((ns,53)) #redirect outputs to a logfile sys.stdout = sys.stderr = Log(open(LOGFILE, 'a+')) print 'dnsfilter starting' print dns_servers #address that traffic is redirected to redirect = '10.0.64.1' greenlist= ['63.4.241.16', \ '216.13.188.67'] class DNSDatagramProtocolTest(dns.DNSDatagramProtocol): def writeMessage(self, message, address): log = '%s DNS request from: %s\n' % (time.strftime("%m/%d/%y - %H:%M:%S", time.localtime()) ,address[0]) for i in range(len(message.answers)): x = message.answers[i] print x.type if x.type==1 and x.payload: if not allowip(address[0]): to_adr = inet_ntoa(x.payload.address) if to_adr in greenlist: log += ' allowed to %s\n'%(to_adr) else: log += ' not allowed so %s becomes %s\n'%(to_adr, redirect) x.payload.address = inet_aton(redirect) else: log += ' to %s\n'%(inet_ntoa(x.payload.address)) print log self.transport.write(message.toStr(), address) resolver = client.Resolver(servers=dns_servers) f = server.DNSServerFactory(clients=[resolver]) p = DNSDatagramProtocolTest(f) reactor.listenUDP(53, p) reactor.run()

On 20 Oct, 07:50 pm, jesper@taxboel.dk wrote:
Hi Guys,
Im playing with a dns-cache script, that overrides DNS requests for certain IP addresses.
I would like to add functionality, so unresolved requests are sent to a spicific IP. How do I go about doing that?
Is there a negative answer in the (udp) DNS protocol or am I forced to use a timeout.
You've overridden writeMessage to inspect messages for answers and rewrite them if necessary. You can recognize error responses by looking at the rCode attribute of the message object itself. This will take on a value like dns.OK, dns.EFORMAT, dns.ESERVER, dns.ENAME, dns.ENOTIMP, or dns.EREFUSED. You can handle these errors by making a request of another domain, although since writeMessage is a very low-level API in the process and not really intended to be overridden, I'm not sure how you'll insert the responses you get from these new requests into the original request/response process. Jean-Paul

Hi Jean-Paul, Thanx for your nice reply. My problem seems to be that I dont get any calls to writemessage when the domain is a bogus one? /tax 2009/10/22 <exarkun@twistedmatrix.com>
On 20 Oct, 07:50 pm, jesper@taxboel.dk wrote:
Hi Guys,
Im playing with a dns-cache script, that overrides DNS requests for certain IP addresses.
I would like to add functionality, so unresolved requests are sent to a spicific IP. How do I go about doing that?
Is there a negative answer in the (udp) DNS protocol or am I forced to use a timeout.
You've overridden writeMessage to inspect messages for answers and rewrite them if necessary. You can recognize error responses by looking at the rCode attribute of the message object itself. This will take on a value like dns.OK, dns.EFORMAT, dns.ESERVER, dns.ENAME, dns.ENOTIMP, or dns.EREFUSED. You can handle these errors by making a request of another domain, although since writeMessage is a very low-level API in the process and not really intended to be overridden, I'm not sure how you'll insert the responses you get from these new requests into the original request/response process.
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

On 02:46 pm, jesper@taxboel.dk wrote:
Hi Jean-Paul,
Thanx for your nice reply. My problem seems to be that I dont get any calls to writemessage when the domain is a bogus one?
It's not immediately obvious why this would be. writeMessage is called to write responses back to your clients. If the requests your server issues get answers, then writeMessage will be called with those answers. If it's not being called, perhaps the problem is that your server's requests are being answered by the servers it is asking. Jean-Paul

Hi Jean-Paul, I guess my focus is right when it comes to redirecting clients. Im hooking into DNSDatagramProtocol.writeMessage(self, message, address): And I guess thats OK? But when it comes to bogus domains, I guess i could use: DNSServerFactory.gotResolverError(self, failure, protocol, message, address): My problem is now how I construct a redirect package and channel it back to the client. Do you think that is a sensible approach? -and do you hava a pointer on how to find the associated client. kind regards /tax 2009/10/22 <exarkun@twistedmatrix.com>
On 02:46 pm, jesper@taxboel.dk wrote:
Hi Jean-Paul,
Thanx for your nice reply. My problem seems to be that I dont get any calls to writemessage when the domain is a bogus one?
It's not immediately obvious why this would be. writeMessage is called to write responses back to your clients. If the requests your server issues get answers, then writeMessage will be called with those answers. If it's not being called, perhaps the problem is that your server's requests are being answered by the servers it is asking.
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

On 07:00 pm, jesper@taxboel.dk wrote:
Hi Jean-Paul,
I guess my focus is right when it comes to redirecting clients.
Im hooking into
DNSDatagramProtocol.writeMessage(self, message, address):
And I guess thats OK?
Depends what "OK" is supposed to mean.
But when it comes to bogus domains, I guess i could use:
DNSServerFactory.gotResolverError(self, failure, protocol, message, address):
I don't know why you should have to do that.
My problem is now how I construct a redirect package and channel it back to the client.
Do you think that is a sensible approach? -and do you hava a pointer on how to find the associated client.
It would probably be a lot easier and more robust to implement a completely new custom resolver that *wraps* an existing resolver, rather than trying to extend an existing resolver via a subclass. This removes many irrelevant implementation details from consideration (such as writeMessage and gotResolverError) and gives you an obvious place to put your redirect logic - in an errback on the Deferred returned by one of the wrapped resolver's lookup/query methods. Jean-Paul

I'm still new to the whole twisted way of doing things, but it sounds very sensible. :) Could you suggest a class to start studying from ? /tax 2009/10/22 <exarkun@twistedmatrix.com>
On 07:00 pm, jesper@taxboel.dk wrote:
Hi Jean-Paul,
I guess my focus is right when it comes to redirecting clients.
Im hooking into
DNSDatagramProtocol.writeMessage(self, message, address):
And I guess thats OK?
Depends what "OK" is supposed to mean.
But when it comes to bogus domains, I guess i could use:
DNSServerFactory.gotResolverError(self, failure, protocol, message, address):
I don't know why you should have to do that.
My problem is now how I construct a redirect package and channel it back to the client.
Do you think that is a sensible approach? -and do you hava a pointer on how to find the associated client.
It would probably be a lot easier and more robust to implement a completely new custom resolver that *wraps* an existing resolver, rather than trying to extend an existing resolver via a subclass. This removes many irrelevant implementation details from consideration (such as writeMessage and gotResolverError) and gives you an obvious place to put your redirect logic - in an errback on the Deferred returned by one of the wrapped resolver's lookup/query methods.
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

On 08:55 pm, jesper@taxboel.dk wrote:
I'm still new to the whole twisted way of doing things, but it sounds very sensible. :)
Could you suggest a class to start studying from ?
twisted/names/common.py is probably a good place to start. It has what comes closest to the definition of a Twisted Names "resolver". Jean-Paul

Im looking at the common.py and I feel a bit confused about how to wrap a resolver. Would'nt a subclass achieve the same thing. I would only need to implement the changed functions in the subclass. I guess my problem is that I dont exactly know how to write a wrapper in python. Kind regards Tax 2009/10/23 <exarkun@twistedmatrix.com>
On 08:55 pm, jesper@taxboel.dk wrote:
I'm still new to the whole twisted way of doing things, but it sounds very sensible. :)
Could you suggest a class to start studying from ?
twisted/names/common.py is probably a good place to start. It has what comes closest to the definition of a Twisted Names "resolver".
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

On 24 Oct, 08:04 pm, jesper@taxboel.dk wrote:
Im looking at the common.py and I feel a bit confused about how to wrap a resolver.
Would'nt a subclass achieve the same thing. I would only need to implement the changed functions in the subclass.
I guess my problem is that I dont exactly know how to write a wrapper in python.
There's nothing special to it. Just do the obvious thing: class SomeWrapper: def __init__(self, wrapee): self.wrapee = wrapee def someMethod(self, args): do something with self.wrapee.someMethod and args common.py will show you all the methods that a resolver is expected to have. Subclassing ResolverBase might help, though it's unfortunate that it works by demultiplexing everything to "_lookup", a private method that Twisted's compatibility policy doesn't guarantee will continue to operate as it presently does. Wrapping (ie "containment" or "has-a") is just an alternative implementation strategy to subclassing (ie "inheritance" or "is-a"). Generally it's a better approach for various reasons, none of which are really specific to Twisted. Jean-Paul

First of all. Thanx for the help!!! The internet is just fantastic!! I like the wrapper approach. I had not thought of that approach myself. Sounds very reasonable. -So I started wrapping Resolver, but got stuck pretty fast. I get a problem saying that 'NoneType' object has no attribute 'addCallback' "addCallback" seems to be implemented in defer.py, but im unsure on how to handle that in the wrapper? Kind regards /Tax P.S: As a side question: In my old hack approach, which I have had almost working, I have had problems constructing valid DNS answers. Wold you happen to know what requirements there is to the returning package, to be accepted. I made some attempts by using pickle to capture live packages, but have a hard time tweaking other values than the address. Ideally I would like to pass on a very short TTL, so the client would not be bothered by fake DNS when I turn the system off. As you might have guessed, Im building a gateway system for a small set of apartments. Requirements are: invalid domains should go to a shop valid domains should be redirected to the shop if the client have not paid, except if the query is for paypal. 2009/10/25 <exarkun@twistedmatrix.com>
On 24 Oct, 08:04 pm, jesper@taxboel.dk wrote:
Im looking at the common.py and I feel a bit confused about how to wrap a resolver.
Would'nt a subclass achieve the same thing. I would only need to implement the changed functions in the subclass.
I guess my problem is that I dont exactly know how to write a wrapper in python.
There's nothing special to it. Just do the obvious thing:
class SomeWrapper: def __init__(self, wrapee): self.wrapee = wrapee
def someMethod(self, args): do something with self.wrapee.someMethod and args
common.py will show you all the methods that a resolver is expected to have. Subclassing ResolverBase might help, though it's unfortunate that it works by demultiplexing everything to "_lookup", a private method that Twisted's compatibility policy doesn't guarantee will continue to operate as it presently does.
Wrapping (ie "containment" or "has-a") is just an alternative implementation strategy to subclassing (ie "inheritance" or "is-a"). Generally it's a better approach for various reasons, none of which are really specific to Twisted.
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
participants (2)
-
exarkun@twistedmatrix.com
-
Jesper Taxbøl