From: Chris Porter Date: Sat, 11 Apr 2009 23:07:26 +0000 (+0100) Subject: Support asynchronous DNS resolution in webirc/None WEBIRC modes. X-Git-Url: https://jfr.im/git/irc/quakenet/qwebirc.git/commitdiff_plain/28c4ad012c879f98f8fdc9aaf5bd50b71fdb7175 Support asynchronous DNS resolution in webirc/None WEBIRC modes. --- diff --git a/config.py.example b/config.py.example index 42dbe68..2d2b336 100644 --- a/config.py.example +++ b/config.py.example @@ -21,13 +21,15 @@ HTTP_AJAX_REQUEST_TIMEOUT = 30 NETWORK_NAME = "FooNet" APP_TITLE = "FooNet Web IRC" -# Possible types include "cgiirc", "hmac" and None -WEBIRC_MODE = "cgiirc" +DNS_TIMEOUT = 5 -# CGIIRC values -CGIIRC_PASSWORD = "fish" +# Possible types include "webirc" (CGIIRC style webirc config block), +# "hmac" (quakenet specific) and None (passes ip and host in realname) +WEBIRC_MODE = "webirc" -# HMAC values +# webirc mode values +WEBIRC_PASSWORD = "fish" +# hmac mode values HMACKEY = "mrmoo" HMACTEMPORAL = 30 diff --git a/qwebirc/dns.py b/qwebirc/dns.py new file mode 100644 index 0000000..9021c1d --- /dev/null +++ b/qwebirc/dns.py @@ -0,0 +1,56 @@ +from twisted.names import client +from twisted.internet import reactor, defer + +class LookupException(Exception): pass +class VerificationException(Exception): pass +TimeoutException = defer.TimeoutError + +def lookupPTR(ip, *args, **kwargs): + def callback(result): + answer, auth, add = result + + if len(answer) == 0: + raise LookupException, "No ANSWERS in PTR response for %s." % repr(ip) + return str(answer[0].payload.name) + + ptr = ".".join(ip.split(".")[::-1]) + ".in-addr.arpa." + return client.lookupPointer(ptr, **kwargs).addCallback(callback) + +def lookupAs(hostname, *args, **kwargs): + def callback(result): + answer, auth, add = result + if len(answer) == 0: + raise LookupException, "No ANSWERS in A response for %s." % repr(hostname) + return [x.payload.dottedQuad() for x in answer] + + return client.lookupAddress(hostname, *args, **kwargs).addCallback(callback) + +def lookupAndVerifyPTR(ip, *args, **kwargs): + d = defer.Deferred() + + def gotPTRResult(ptr): + def gotAResult(a_records): + if ip in a_records: + d.callback(ptr) + else: + raise VerificationException("IP mismatch: %s != %s%s" % (repr(ip), repr(ptr), repr(a_records))) + lookupAs(ptr, *args, **kwargs).addCallback(gotAResult).addErrback(d.errback) + + lookupPTR(ip, *args, **kwargs).addCallback(gotPTRResult).addErrback(d.errback) + return d + +if __name__ == "__main__": + import sys + + def callback(x): + print x + reactor.stop() + + def errback(x): + x.printTraceback() + reactor.stop() + + d = lookupAndVerifyPTR(sys.argv[1], timeout=[.001]) + d.addCallbacks(callback, errback) + + reactor.run() diff --git a/qwebirc/engines/ajaxengine.py b/qwebirc/engines/ajaxengine.py index 6d4310e..6b0bf45 100644 --- a/qwebirc/engines/ajaxengine.py +++ b/qwebirc/engines/ajaxengine.py @@ -6,7 +6,7 @@ import simplejson, md5, sys, os, time, config, weakref, traceback, socket import qwebirc.ircclient as ircclient from adminengine import AdminEngineAction from qwebirc.util import HitCounter - +import qwebirc.dns as qdns Sessions = {} def get_session_id(): @@ -137,6 +137,10 @@ class IRCSession: reactor.callLater(5, cleanupSession, self.id) +# DANGER! Breach of encapsulation! +def connect_notice(line): + return "c", "NOTICE", "", ("AUTH", "*** (qwebirc) %s" % line) + class Channel: def __init__(self, request): self.request = request @@ -173,9 +177,6 @@ class AJAXEngine(resource.Resource): raise PassthruException, http_error.NoResource().render(request) - #def render_GET(self, request): - #return self.render_POST(request) - def newConnection(self, request): ticket = login_optional(request) @@ -208,9 +209,24 @@ class AJAXEngine(resource.Resource): ident = socket.inet_aton(ip).encode("hex") self.__connect_hit() - client = ircclient.createIRC(session, nick=nick, ident=ident, ip=ip, realname=realname, perform=perform, hostname=ip) - session.client = client - + + def proceed(hostname): + client = ircclient.createIRC(session, nick=nick, ident=ident, ip=ip, realname=realname, perform=perform, hostname=hostname) + session.client = client + + if config.WEBIRC_MODE != "hmac": + notice = lambda x: session.event(connect_notice(x)) + notice("Looking up your hostname...") + def callback(hostname): + notice("Found your hostname.") + proceed(hostname) + def errback(failure): + notice("Couldn't look up your hostname!") + proceed(ip) + qdns.lookupAndVerifyPTR(ip, timeout=[config.DNS_TIMEOUT]).addCallbacks(callback, errback) + else: + proceed(None) # hmac doesn't care + Sessions[id] = session return id diff --git a/qwebirc/ircclient.py b/qwebirc/ircclient.py index 8ef8211..43f5665 100644 --- a/qwebirc/ircclient.py +++ b/qwebirc/ircclient.py @@ -79,8 +79,8 @@ class QWebIRCClient(basic.LineReceiver): if config.WEBIRC_MODE == "hmac": hmac = hmacfn(ident, ip) self.write("USER %s bleh bleh %s %s :%s" % (ident, ip, hmac, realname)) - elif config.WEBIRC_MODE == "cgiirc": - self.write("WEBIRC %s cgiirc %s %s" % (config.WEBIRC_PASSWORD, ip, hostname)) + elif config.WEBIRC_MODE == "webirc": + self.write("WEBIRC %s qwebirc %s %s" % (config.WEBIRC_PASSWORD, ip, hostname)) self.write("USER %s bleh %s :%s" % (ident, ip, realname)) else: if ip == hostname: @@ -88,7 +88,7 @@ class QWebIRCClient(basic.LineReceiver): else: dispip = "%s/%s" % (hostname, ip) - self.write("USER %s bleh bleh :%s -- %s" % (ident, dispip, realname)) + self.write("USER %s bleh bleh :%s - %s" % (ident, dispip, realname)) self.write("NICK %s" % nick)