[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[minion-cvs] Mixminion just delivered its first test message. Still...



Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.seul.org:/tmp/cvs-serv13014/lib/mixminion

Modified Files:
	BuildMessage.py Common.py Config.py HashLog.py MMTPServer.py 
	Main.py Modules.py PacketHandler.py ServerMain.py test.py 
	testSupport.py 
Added Files:
	ClientMain.py 
Log Message:
Mixminion just delivered its first test message.  Still requires babysitting
that only I can do, though. :P  BTW, happy birthday to me!

BuildMessage.py: Add warning in comment

Common.py: Withstand logging in nonexistant dir

Config.py: 
	- Path len is an int
	- Add more validation

HashLog.py:
	- Withstand logging in nonexistant dir.

MMTPServer.py:
	- Quiet debugging a bit
	- Debug server class

Main.py:
	- Add client CLI

ClientMain.py:
	- Stub client CLI.  Doesn't do anything worthwhile yet

Modules.py:
	- Fix dumb typo

ServerMain.py:
	- Much debugging

test.py:
	- Suspend log more consistently

testSupport.py:
	- Debug testing module
	



--- NEW FILE: ClientMain.py ---
# Copyright 2002 Nick Mathewson.  See LICENSE for licensing information.
# $Id: ClientMain.py,v 1.1 2002/08/31 04:12:36 nickm Exp $

"""mixminion.ClientMain

   Code for Mixminion command-line client.

   XXXX THIS ISN'T IMPLEMENTED YET!  This file is just a placeholder that
   XXXX routes a testing message through a few servers so I can make sure that
   XXXX at least one configuration works.
   """

import os
import getopt
import sys
import time
import bisect

import mixminion.Crypto
from mixminion.Common import getLog, floorDiv
import mixminion.Config
import mixminion.BuildMessage
import mixminion.MMTPClient
import mixminion.Modules

def sendTestMessage(servers1, servers2):
    assert len(servers1)
    assert len(servers2)
    payload = """ 
           Insert
	   Example
	   Message
	   Here.
	   """
    rt, ri = 0xFFFE, "deliver"
    m = mixminion.BuildMessage.buildForwardMessage(payload,
						   rt, ri,
						   servers1, servers2)
    firstHop = servers1[0]
    b = mixminion.MMTPClient.BlockingClientConnection(firstHop.getAddr(),
						      firstHop.getPort(),
						      firstHop.getKeyID())
    b.connect()
    b.sendPacket(m)
    b.shutdown()


def readConfigFile(configFile):
    try:
	return mixminion.Config.ClientConfig(fname=configFile)
    except (IOError, OSError), e:
	print >>sys.stderr, "Error reading configuration file %r:"%configFile
	print >>sys.stderr, "   ", str(e)
	sys.exit(1)
    except mixminion.Config.ConfigError, e:
	print >>sys.stderr, "Error in configuration file %r"%configFile
	print >>sys.stderr, str(e)
	sys.exit(1)

# XXXX This isn't anything LIKE the final client interface: for now, I'm
# XXXX just testing the server.
def runClient(cmd, args):
    options, args = getopt.getopt(args, "hf:", ["help", "config="])
    configFile = '~/.mixminion/mixminion.conf'
    usage = 0
    for opt,val in options:
	if opt in ('-h', '--help'):
	    usage=1
	elif opt in ('-f', '--config'):
	    configFile = val
    if usage:
	print >>sys.stderr, "Usage: %s [-h] [-f configfile] server1 server2..."%cmd
	sys.exit(1)
    config = readConfigFile(os.path.expanduser(configFile))

    getLog().setMinSeverity("INFO")
    mixminion.Crypto.init_crypto(config)
    if len(args) < 2:
	print >> sys.stderr, "I need at least 2 servers"
    servers = [ mixminion.ServerInfo.ServerInfo(fn) for fn in args ]
    idx = floorDiv(len(servers),2)

    sendTestMessage(servers[:idx], servers[idx:])



Index: BuildMessage.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/BuildMessage.py,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- BuildMessage.py	6 Aug 2002 16:09:21 -0000	1.11
+++ BuildMessage.py	31 Aug 2002 04:12:36 -0000	1.12
@@ -21,6 +21,9 @@
             exitInfo: The routing info for the final node
             path1: Sequence of ServerInfo objects for the first leg of the path
             path2: Sequence of ServerInfo objects for the 2nd leg of the path
+
+        Note: If either path is empty, the message is vulnerable to tagging 
+         attacks! (FFFF we should check this.)
     """
     return _buildMessage(payload, exitType, exitInfo, path1, path2)
 

Index: Common.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Common.py,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- Common.py	29 Aug 2002 03:30:21 -0000	1.19
+++ Common.py	31 Aug 2002 04:12:36 -0000	1.20
@@ -208,6 +208,9 @@
         if self.file is not None:
             self.file.close()
 	try: 
+	    parent = os.path.split(self.fname)[0]
+	    if not os.path.exists(parent):
+		createPrivateDir(parent)
 	    self.file = open(self.fname, 'a')
 	except OSError, e:
 	    self.file = None

Index: Config.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Config.py,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- Config.py	29 Aug 2002 03:30:21 -0000	1.13
+++ Config.py	31 Aug 2002 04:12:36 -0000	1.14
@@ -51,7 +51,6 @@
 import os
 import re
 import binascii
-import time
 import socket # for inet_aton and error
 from cStringIO import StringIO
 
@@ -624,15 +623,13 @@
         'User' : { 'UserDir' : ('ALLOW', None, "~/.mixminion" ) },
         'Security' : { 'PathLength' : ('ALLOW', _parseInt, "8"),
                        'SURBAddress' : ('ALLOW', None, None),
-                       'SURBPathLength' : ('ALLOW', None, "8") },
+                       'SURBPathLength' : ('ALLOW', _parseInt, "8") },
         }
     def __init__(self, fname=None, string=None):
         _ConfigFile.__init__(self, fname, string)
 
     def validate(self, sections, entries, lines, contents):
-        #XXXX Write this
-        pass
-
+	_validateHostSection(sections.get('Host', {}))
 
 SERVER_SYNTAX =  {
         'Host' : ClientConfig._syntax['Host'],
@@ -695,7 +692,34 @@
         _ConfigFile.__init__(self, fname, string)
 
     def validate(self, sections, entries, lines, contents):
-        #XXXX write this.
+	log = getLog()
+	_validateHostSection(sections.get('Host', {}))
+	# Server section
+	server = sections['Server']
+	bits = server['IdentityKeyBits']
+	if not (2048 <= bits <= 4096):
+	    raise ConfigError("IdentityKeyBits must be between 2048 and 4096")
+	if server['EncryptIdentityKey']:
+	    log.warn("Identity key encryption not yet implemented")
+	if server['EncryptPrivateKey']:
+	    log.warn("Encrypted private keys not yet implemented")
+	if server['PublicKeyLifetime'][2] < 24*60*60:
+	    raise ConfigError("PublicKeyLifetime must be at least 1 day.")
+	if server['PublicKeySloppiness'][2] > 20*60:
+	    raise ConfigError("PublicKeySloppiness must be <= 20 minutes.")
+	if [e for e in entries['Server'] if e[0]=='Mode']:
+	    log.warn("Mode specification is not yet supported.")
+
+	if not sections['Incoming/MMTP'].get('Enabled'):
+	    log.warn("Disabling incoming MMTP is not yet supported.")
+	if [e for e in entries['Incoming/MMTP'] if e[0] in ('Allow', 'Deny')]:
+	    log.warn("Allow/deny are not yet supported")
+
+	if not sections['Outgoing/MMTP'].get('Enabled'):
+	    log.warn("Disabling incoming MMTP is not yet supported.")
+	if [e for e in entries['Outgoing/MMTP'] if e[0] in ('Allow', 'Deny')]:
+	    log.warn("Allow/deny are not yet supported")
+
         self.moduleManager.validate(sections, entries, lines, contents)
 
     def __loadModules(self, section, sectionEntries):
@@ -712,3 +736,8 @@
     def getModuleManager(self):
 	"Return the module manager initialized by this server."
 	return self.moduleManager
+
+def _validateHostSection(sec):
+    #XXXX
+    pass
+

Index: HashLog.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/HashLog.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- HashLog.py	9 Jul 2002 04:07:14 -0000	1.9
+++ HashLog.py	31 Aug 2002 04:12:36 -0000	1.10
@@ -5,8 +5,9 @@
 
    Persistant memory for the hashed secrets we've seen."""
 
+import os
 import anydbm, dumbdbm
-from mixminion.Common import MixFatalError, getLog
+from mixminion.Common import MixFatalError, getLog, createPrivateDir
 
 __all__ = [ 'HashLog' ]
 
@@ -37,6 +38,9 @@
     def __init__(self, filename, keyid):
         """Create a new HashLog to store data in 'filename' for the key
            'keyid'."""
+        parent = os.path.split(filename)[0]
+	createPrivateDir(parent)
+	print filename
         self.log = anydbm.open(filename, 'c')
         if isinstance(self.log, dumbdbm._Database):
             getLog().warn("Warning: logging packet digests to a flat file.")

Index: MMTPServer.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/MMTPServer.py,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- MMTPServer.py	29 Aug 2002 03:30:21 -0000	1.15
+++ MMTPServer.py	31 Aug 2002 04:12:36 -0000	1.16
@@ -63,8 +63,8 @@
            If we receive an unblocked signal, return immediately.
            """
 
-        trace("%s readers, %s writers" % (len(self.readers),
-                                          len(self.writers)))
+##        trace("%s readers, %s writers" % (len(self.readers),
+##                                          len(self.writers)))
         
         readfds = self.readers.keys()
         writefds = self.writers.keys()
@@ -570,7 +570,8 @@
         msg = self.messageList[0]
         self.expectedDigest = sha1(msg+"RECEIVED")
         msg = SEND_CONTROL+msg+sha1(msg+"SEND")
-
+	assert len(msg) == SEND_RECORD_LEN
+	
         self.beginWrite(msg)
         self.finished = self.__sentMessage
 
@@ -641,14 +642,21 @@
         sock.setblocking(0)
         con = MMTPServerConnection(sock, tls, self.onMessageReceived)
         con.register(self)
+	return con
     
     def stopListening(self):
 	self.listener.shutdown()
 
     def sendMessages(self, ip, port, keyID, messages, handles):
 	"""Send a set of messages to a given server."""
-        con = MMTPClientConnection(ip, port, keyID, messages, handles,
-                                   self.onMessageSent)
+	#XXXX for debugging
+	for m,h in zip(messages, handles):
+	    assert len(m) == MESSAGE_LEN
+	    assert len(h) < 32
+	    
+        con = MMTPClientConnection(self.context,
+				   ip, port, keyID, messages, handles,
+                                   self.onMessageSent, self.onMessageUndeliverable)
         con.register(self)
 
     def onMessageReceived(self, msg):

Index: Main.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Main.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Main.py	29 Aug 2002 03:30:21 -0000	1.3
+++ Main.py	31 Aug 2002 04:12:36 -0000	1.4
@@ -75,6 +75,7 @@
 _COMMANDS = {
     "unittests" : ( 'mixminion.test', 'testAll' ),
     "benchmarks" : ( 'mixminion.benchmark', 'timeAll' ),
+    "client" : ( 'mixminion.ClientMain', 'runClient' ),
     "server" : ( 'mixminion.ServerMain', 'runServer' ),
     "server-keygen" : ( 'mixminion.ServerMain', 'runKeygen')
 }

Index: Modules.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Modules.py,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- Modules.py	29 Aug 2002 03:30:21 -0000	1.10
+++ Modules.py	31 Aug 2002 04:12:36 -0000	1.11
@@ -108,7 +108,7 @@
 
     def queueMessage(self, (exitType, exitInfo), message):
 	try:
-	    res = self.module.processMessage(exitType, exitInfo, message)
+	    res = self.module.processMessage(message, exitType, exitInfo)
 	    if res == DELIVER_OK:
 		return
 	    elif res == DELIVER_FAIL_RETRY:

Index: PacketHandler.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/PacketHandler.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- PacketHandler.py	19 Aug 2002 20:27:02 -0000	1.6
+++ PacketHandler.py	31 Aug 2002 04:12:36 -0000	1.7
@@ -38,6 +38,7 @@
             self.privatekey = privatekey
             self.hashlog = hashlog
         except:
+	    # XXXX Don't do except:; name an exception.
             self.privatekey = (privatekey, )
             self.hashlog = (hashlog, )
 

Index: ServerMain.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ServerMain.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- ServerMain.py	29 Aug 2002 03:30:21 -0000	1.7
+++ ServerMain.py	31 Aug 2002 04:12:36 -0000	1.8
@@ -175,7 +175,7 @@
 
 	    nextStart = startAt + self.config['Server']['PublicKeyLifetime'][2]
 
-	    getLog().info("Generating key %s to run from %s through %s", 
+	    getLog().info("Generating key %s to run from %s through %s (GMT)", 
 			  keyname, _date(startAt), _date(nextStart-3600))
  	    generateServerDescriptorAndKeys(config=self.config,
 					    identityKey=self.getIdentityKey(),
@@ -210,7 +210,6 @@
 	    self.nextKeyRotation = 0
 	    return None
 
-
 	w = when
 	if when is None: 
 	    when = time.time()
@@ -260,8 +259,11 @@
     def getPacketHandler(self):
 	"""Create and return a PacketHandler from the currently live key."""
         keys = self.getServerKeyset()
-        return mixminion.PacketHandler.PacketHandler(keys.getPacketKey(),
-                                                     keys.getHashLogFileName())
+	packetKey = keys.getPacketKey()
+	hashlog = mixminion.HashLog.HashLog(keys.getHashLogFileName(),
+						 keys.getMMTPKeyID())
+        return mixminion.PacketHandler.PacketHandler(packetKey,
+						     hashlog)
 
 class IncomingQueue(mixminion.Queue.DeliveryQueue):
     """A DeliveryQueue to accept messages from incoming MMTP connections,
@@ -280,14 +282,14 @@
 
     def queueMessage(self, msg):
 	"""Add a message for delivery"""
-	mixminion.DeliveryQueue.queueMessage(None, msg)
+	mixminion.Queue.DeliveryQueue.queueMessage(self, None, msg)
     
     def deliverMessages(self, msgList):
 	"Implementation of abstract method from DeliveryQueue."
 	ph = self.packetHandler
 	for handle, _, message, n_retries in msgList:
 	    try:
-		res = ph.packetHandler(message)
+		res = ph.processMessage(message)
 		if res is None:
 		    # Drop padding before it gets to the mix.
 		    getLog().info("Padding message dropped")
@@ -315,7 +317,7 @@
 
     def queueObject(self, obj):
 	"""Insert an object into the queue."""
-	self.queue.queueObject(ob)
+	self.queue.queueObject(obj)
 
     def connectQueues(self, outgoing, manager):
 	"""Sets the queue for outgoing mixminion packets, and the
@@ -327,15 +329,17 @@
 	"""Get a batch of messages, and queue them for delivery as 
 	   appropriate."""
 	handles = self.queue.getBatch()
+	getLog().trace("Mixing %s messages", len(handles))
 	for h in handles:
 	    tp, info = self.queue.getObject(h)
 	    if tp == 'EXIT':
 		rt, ri, app_key, payload = info
-		self.moduleManager.queueMessage((rt, ri), payload)
+		self.moduleManager.queueMessage(payload, rt, ri)
 	    else:
 		assert tp == 'QUEUE'
 		ipv4, msg = info
 		self.outgoingQueue.queueMessage(ipv4, msg)
+	    self.queue.removeMessage(h)
 
 class OutgoingQueue(mixminion.Queue.DeliveryQueue):
     """DeliveryQueue to send messages via outgoing MMTP connections."""
@@ -357,9 +361,9 @@
 	for handle, addr, message, n_retries in msgList:
 	    msgs.setdefault(addr, []).append( (handle, message) )
 	for addr, messages in msgs.items():
-	    messages, handles = zip(*messages)
+	    handles, messages = zip(*messages)
 	    self.server.sendMessages(addr.ip, addr.port, addr.keyinfo,
-				     messages, handles)
+				     list(messages), list(handles))
 
 class _MMTPServer(mixminion.MMTPServer.MMTPServer):
     """Implementation of mixminion.MMTPServer that knows about
@@ -462,7 +466,7 @@
     options, args = getopt.getopt(args, "hf:", ["help", "config="])
     if args:
 	usageAndExit(cmd)
-    configFile = "/etc/miniond.conf"
+    configFile = "/etc/mixminiond.conf"
     for o,v in options:
 	if o in ('-h', '--help'):
 	    usageAndExit()
@@ -507,6 +511,7 @@
 	getLog().fatal_exc(sys.exc_info(),"Exception while running server")
     getLog().info("Server shutting down")
     
+    
     sys.exit(0)
 
 #----------------------------------------------------------------------
@@ -539,5 +544,4 @@
     for i in xrange(keys):
 	keyring.createKeys(1)
 	print >> sys.stderr, ".... (%s/%s done)" % (i+1,keys)
-    
     

Index: test.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/test.py,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- test.py	29 Aug 2002 03:30:21 -0000	1.25
+++ test.py	31 Aug 2002 04:12:36 -0000	1.26
@@ -2135,7 +2135,11 @@
     def testServerInfoGen(self):
 	identity = _getIdentityKey()
         d = mix_mktemp()
-        conf = mixminion.Config.ServerConfig(string=SERVER_CONFIG)
+	try:
+	    suspendLog()
+	    conf = mixminion.Config.ServerConfig(string=SERVER_CONFIG)
+	finally:
+	    resumeLog()
         if not os.path.exists(d):
             os.mkdir(d, 0700)
 
@@ -2195,7 +2199,11 @@
                                                   identityPK))
 
         # Now with a shorter configuration
-        conf = mixminion.Config.ServerConfig(string=SERVER_CONFIG_SHORT)
+	try:
+	    suspendLog()
+	    conf = mixminion.Config.ServerConfig(string=SERVER_CONFIG_SHORT)
+	finally:
+	    resumeLog()
 	mixminion.ServerInfo.generateServerDescriptorAndKeys(conf,
 							     identity,
 							     d,
@@ -2285,7 +2293,11 @@
 Foo: 99
 """ % (home_dir, mod_dir)
 
-        conf = mixminion.Config.ServerConfig(string=cfg_test)	
+        try:
+	    suspendLog()
+	    conf = mixminion.Config.ServerConfig(string=cfg_test)	
+	finally:
+	    resumeLog()
 	manager = conf.getModuleManager()
 	exampleMod = None
 	for m in manager.modules:
@@ -2295,7 +2307,11 @@
 	manager.configure(conf)
 
 	self.assertEquals(99, exampleMod.foo)
-        conf = mixminion.Config.ServerConfig(string=cfg_test)	
+	try:
+	    suspendLog()
+	    conf = mixminion.Config.ServerConfig(string=cfg_test)	
+	finally:
+	    resumeLog()
 	manager = conf.getModuleManager()
 	exampleMod = None
 	for m in manager.modules:
@@ -2348,7 +2364,11 @@
 Module ExampleMod.TestModule
 """ % (home_dir, mod_dir)
 
-        conf = mixminion.Config.ServerConfig(string=cfg_test)	
+        try:
+	    suspendLog()
+	    conf = mixminion.Config.ServerConfig(string=cfg_test)
+	finally:
+	    resumeLog()
 	manager = conf.getModuleManager()
 	exampleMod = None
 	for m in manager.modules:
@@ -2390,7 +2410,11 @@
     if _FAKE_HOME is None:
 	_FAKE_HOME = mix_mktemp()	
     cfg = SERVERCFG % { 'home' : _FAKE_HOME }
-    conf = mixminion.Config.ServerConfig(string=cfg)
+    try:
+	suspendLog()
+	conf = mixminion.Config.ServerConfig(string=cfg)
+    finally:
+	resumeLog()
     return mixminion.ServerMain.ServerKeyring(conf)
 
 _IDENTITY_KEY = None

Index: testSupport.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/testSupport.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- testSupport.py	29 Aug 2002 03:30:21 -0000	1.3
+++ testSupport.py	31 Aug 2002 04:12:36 -0000	1.4
@@ -42,7 +42,7 @@
 	if not self.loc:
 	    return
 	self.useQueue = config['Testing/DirectoryDump']['UseQueue']
-	#manager.registerModule(self)
+	manager.enableModule(self)
 	
 	if not os.path.exists(self.loc):
 	    createPrivateDir(self.loc)
@@ -75,7 +75,7 @@
 	elif exitInfo == 'FAIL!':
 	    return DELIVER_FAIL_NORETRY
 
-	f = open(os.path.join(self.loc, self.next), 'w')
+	f = open(os.path.join(self.loc, str(self.next)), 'w')
 	self.next += 1
 	f.write(exitInfo)
 	f.write("\n")