]> jfr.im git - irc/quakenet/qwebirc.git/commitdiff
Support asynchronous DNS resolution in webirc/None WEBIRC modes.
authorChris Porter <redacted>
Sat, 11 Apr 2009 23:07:26 +0000 (00:07 +0100)
committerChris Porter <redacted>
Sat, 11 Apr 2009 23:07:26 +0000 (00:07 +0100)
config.py.example
qwebirc/dns.py [new file with mode: 0644]
qwebirc/engines/ajaxengine.py
qwebirc/ircclient.py

index 42dbe68bc675d6500d629b0fbe9cc0fd4296831f..2d2b33611a61945422dd020e66ded9daa2c563a8 100644 (file)
@@ -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 (file)
index 0000000..9021c1d
--- /dev/null
@@ -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()
index 6d4310e5e4b2ffabea72d6deea01490dd1cff6bb..6b0bf45b02fb8c3efa0bc146bb771f0d66db0e94 100644 (file)
@@ -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
index 8ef8211102827174fbd860755fa1d8ad5eddae76..43f5665bc29650c30d14267fa47bd2939124332a 100644 (file)
@@ -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)