|
@@ -31,61 +31,59 @@ class Node(object):
|
|
|
# Users are expected to call these:
|
|
|
def __init__(self, parent=None, **kwargs):
|
|
|
self._parent = parent
|
|
|
- self._fields = self._createEnviron(parent, kwargs)
|
|
|
+ self.env = self._createEnviron(parent, kwargs)
|
|
|
|
|
|
def getN(self, N):
|
|
|
- return [ Node(self) for i in xrange(N) ]
|
|
|
+ return [ Node(self) for _ in xrange(N) ]
|
|
|
|
|
|
def specialize(self, **kwargs):
|
|
|
return Node(parent=self, **kwargs)
|
|
|
|
|
|
+ def expand(self, pat, includePath=(".",)):
|
|
|
+ return chutney.Templating.Template(pat, includePath).format(self.env)
|
|
|
+
|
|
|
+
|
|
|
#######
|
|
|
# Users are NOT expected to call these:
|
|
|
-
|
|
|
def _getTorrcFname(self):
|
|
|
- t = chutney.Templating.Template("${torrc_fname}")
|
|
|
- return t.format(self._fields)
|
|
|
+ return self.expand("${torrc_fname}")
|
|
|
|
|
|
def _createTorrcFile(self, checkOnly=False):
|
|
|
- template = self._getTorrcTemplate()
|
|
|
- env = self._fields
|
|
|
fn_out = self._getTorrcFname()
|
|
|
- output = template.format(env)
|
|
|
+ torrc_template = self._getTorrcTemplate()
|
|
|
+ output = torrc_template.format(self.env)
|
|
|
if checkOnly:
|
|
|
return
|
|
|
with open(fn_out, 'w') as f:
|
|
|
f.write(output)
|
|
|
|
|
|
def _getTorrcTemplate(self):
|
|
|
- env = self._fields
|
|
|
- template_path = env['torrc_template_path']
|
|
|
-
|
|
|
- t = "$${include:$torrc}"
|
|
|
- return chutney.Templating.Template(t, includePath=template_path)
|
|
|
+ template_path = self.env['torrc_template_path']
|
|
|
+ return chutney.Templating.Template("$${include:$torrc}",
|
|
|
+ includePath=template_path)
|
|
|
|
|
|
def _getFreeVars(self):
|
|
|
template = self._getTorrcTemplate()
|
|
|
- env = self._fields
|
|
|
- return template.freevars(env)
|
|
|
+ return template.freevars(self.env)
|
|
|
|
|
|
def _createEnviron(self, parent, argdict):
|
|
|
if parent:
|
|
|
- parentfields = parent._fields
|
|
|
+ parentenv = parent.env
|
|
|
else:
|
|
|
- parentfields = self._getDefaultFields()
|
|
|
- return TorEnviron(parentfields, **argdict)
|
|
|
+ parentenv = self._getDefaultEnviron()
|
|
|
+ return TorEnviron(parentenv, **argdict)
|
|
|
|
|
|
- def _getDefaultFields(self):
|
|
|
- return _BASE_FIELDS
|
|
|
+ def _getDefaultEnviron(self):
|
|
|
+ return _BASE_ENVIRON
|
|
|
|
|
|
def _checkConfig(self, net):
|
|
|
self._createTorrcFile(checkOnly=True)
|
|
|
|
|
|
def _preConfig(self, net):
|
|
|
self._makeDataDir()
|
|
|
- if self._fields['authority']:
|
|
|
+ if self.env['authority']:
|
|
|
self._genAuthorityKey()
|
|
|
- if self._fields['relay']:
|
|
|
+ if self.env['relay']:
|
|
|
self._genRouterKey()
|
|
|
|
|
|
def _config(self, net):
|
|
@@ -97,23 +95,21 @@ class Node(object):
|
|
|
pass
|
|
|
|
|
|
def _setnodenum(self, num):
|
|
|
- self._fields['nodenum'] = num
|
|
|
+ self.env['nodenum'] = num
|
|
|
|
|
|
def _makeDataDir(self):
|
|
|
- env = self._fields
|
|
|
- datadir = env['dir']
|
|
|
+ datadir = self.env['dir']
|
|
|
mkdir_p(os.path.join(datadir, 'keys'))
|
|
|
|
|
|
def _genAuthorityKey(self):
|
|
|
- env = self._fields
|
|
|
- datadir = env['dir']
|
|
|
- tor_gencert = env['tor_gencert']
|
|
|
- lifetime = env['auth_cert_lifetime']
|
|
|
+ datadir = self.env['dir']
|
|
|
+ tor_gencert = self.env['tor_gencert']
|
|
|
+ lifetime = self.env['auth_cert_lifetime']
|
|
|
idfile = os.path.join(datadir,'keys',"authority_identity_key")
|
|
|
skfile = os.path.join(datadir,'keys',"authority_signing_key")
|
|
|
certfile = os.path.join(datadir,'keys',"authority_certificate")
|
|
|
- addr = "%s:%s" % (env['ip'], env['dirport'])
|
|
|
- passphrase = env['auth_passphrase']
|
|
|
+ addr = self.expand("${ip}:${dirport}")
|
|
|
+ passphrase = self.env['auth_passphrase']
|
|
|
if all(os.path.exists(f) for f in [idfile, skfile, certfile]):
|
|
|
return
|
|
|
cmdline = [
|
|
@@ -125,15 +121,15 @@ class Node(object):
|
|
|
'-c', certfile,
|
|
|
'-m', str(lifetime),
|
|
|
'-a', addr]
|
|
|
- print "Creating identity key %s for %s with %s"%(idfile,env['nick']," ".join(cmdline))
|
|
|
+ print "Creating identity key %s for %s with %s"%(
|
|
|
+ idfile,self.env['nick']," ".join(cmdline))
|
|
|
p = subprocess.Popen(cmdline, stdin=subprocess.PIPE)
|
|
|
p.communicate(passphrase+"\n")
|
|
|
assert p.returncode == 0 #XXXX BAD!
|
|
|
|
|
|
def _genRouterKey(self):
|
|
|
- env = self._fields
|
|
|
- datadir = env['dir']
|
|
|
- tor = env['tor']
|
|
|
+ datadir = self.env['dir']
|
|
|
+ tor = self.env['tor']
|
|
|
idfile = os.path.join(datadir,'keys',"identity_key")
|
|
|
cmdline = [
|
|
|
tor,
|
|
@@ -147,14 +143,13 @@ class Node(object):
|
|
|
stdout, stderr = p.communicate()
|
|
|
fingerprint = "".join(stdout.split()[1:])
|
|
|
assert re.match(r'^[A-F0-9]{40}$', fingerprint)
|
|
|
- env['fingerprint'] = fingerprint
|
|
|
+ self.env['fingerprint'] = fingerprint
|
|
|
|
|
|
def _getDirServerLine(self):
|
|
|
- env = self._fields
|
|
|
- if not env['authority']:
|
|
|
+ if not self.env['authority']:
|
|
|
return ""
|
|
|
|
|
|
- datadir = env['dir']
|
|
|
+ datadir = self.env['dir']
|
|
|
certfile = os.path.join(datadir,'keys',"authority_certificate")
|
|
|
v3id = None
|
|
|
with open(certfile, 'r') as f:
|
|
@@ -166,16 +161,16 @@ class Node(object):
|
|
|
assert v3id is not None
|
|
|
|
|
|
return "DirServer %s v3ident=%s orport=%s %s %s:%s %s\n" %(
|
|
|
- env['nick'], v3id, env['orport'], env['dirserver_flags'],
|
|
|
- env['ip'], env['dirport'], env['fingerprint'])
|
|
|
+ self.env['nick'], v3id, self.env['orport'],
|
|
|
+ self.env['dirserver_flags'], self.env['ip'], self.env['dirport'],
|
|
|
+ self.env['fingerprint'])
|
|
|
|
|
|
|
|
|
##### Controlling a node. This should probably get split into its
|
|
|
# own class. XXXX
|
|
|
|
|
|
def getPid(self):
|
|
|
- env = self._fields
|
|
|
- pidfile = os.path.join(env['dir'], 'pid')
|
|
|
+ pidfile = os.path.join(self.env['dir'], 'pid')
|
|
|
if not os.path.exists(pidfile):
|
|
|
return None
|
|
|
|
|
@@ -183,7 +178,6 @@ class Node(object):
|
|
|
return int(f.read())
|
|
|
|
|
|
def isRunning(self, pid=None):
|
|
|
- env = self._fields
|
|
|
if pid is None:
|
|
|
pid = self.getPid()
|
|
|
if pid is None:
|
|
@@ -196,19 +190,18 @@ class Node(object):
|
|
|
return False
|
|
|
raise
|
|
|
|
|
|
- # okay, so the process exists. Say "True" for now.
|
|
|
+ # okay, so the process exists. Say "True" for now.
|
|
|
# XXXX check if this is really tor!
|
|
|
return True
|
|
|
|
|
|
def check(self, listRunning=True, listNonRunning=False):
|
|
|
- env = self._fields
|
|
|
pid = self.getPid()
|
|
|
running = self.isRunning(pid)
|
|
|
- name = env['nick']
|
|
|
- dir = env['dir']
|
|
|
+ nick = self.env['nick']
|
|
|
+ dir = self.env['dir']
|
|
|
if running:
|
|
|
if listRunning:
|
|
|
- print "%s is running with PID %s"%(name,pid)
|
|
|
+ print "%s is running with PID %s"%(nick,pid)
|
|
|
return True
|
|
|
elif os.path.exists(os.path.join(dir, "core.%s"%pid)):
|
|
|
if listNonRunning:
|
|
@@ -223,7 +216,7 @@ class Node(object):
|
|
|
def hup(self):
|
|
|
pid = self.getPid()
|
|
|
running = self.isRunning()
|
|
|
- nick = self._fields['nick']
|
|
|
+ nick = self.env['nick']
|
|
|
if self.isRunning():
|
|
|
print "Sending sighup to %s"%nick
|
|
|
os.kill(pid, signal.SIGHUP)
|
|
@@ -234,11 +227,11 @@ class Node(object):
|
|
|
|
|
|
def start(self):
|
|
|
if self.isRunning():
|
|
|
- print "%s is already running"%self._fields['nick']
|
|
|
+ print "%s is already running"%self.env['nick']
|
|
|
return
|
|
|
torrc = self._getTorrcFname()
|
|
|
cmdline = [
|
|
|
- self._fields['tor'],
|
|
|
+ self.env['tor'],
|
|
|
"--quiet",
|
|
|
"-f", torrc,
|
|
|
]
|
|
@@ -246,17 +239,16 @@ class Node(object):
|
|
|
# XXXX this requires that RunAsDaemon is set.
|
|
|
p.wait()
|
|
|
if p.returncode != 0:
|
|
|
- print "Couldn't launch %s (%s): %s"%(self._fields['nick'],
|
|
|
+ print "Couldn't launch %s (%s): %s"%(self.env['nick'],
|
|
|
" ".join(cmdline),
|
|
|
p.returncode)
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
def stop(self, sig=signal.SIGINT):
|
|
|
- env = self._fields
|
|
|
pid = self.getPid()
|
|
|
if not self.isRunning(pid):
|
|
|
- print "%s is not running"%env['nick']
|
|
|
+ print "%s is not running"%self.env['nick']
|
|
|
return
|
|
|
os.kill(pid, sig)
|
|
|
|
|
@@ -284,34 +276,34 @@ class TorEnviron(chutney.Templating.Environ):
|
|
|
def __init__(self,parent=None,**kwargs):
|
|
|
chutney.Templating.Environ.__init__(self, parent=parent, **kwargs)
|
|
|
|
|
|
- def _get_orport(self, me):
|
|
|
- return me['orport_base']+me['nodenum']
|
|
|
+ def _get_orport(self, my):
|
|
|
+ return my['orport_base']+my['nodenum']
|
|
|
|
|
|
- def _get_controlport(self, me):
|
|
|
- return me['controlport_base']+me['nodenum']
|
|
|
+ def _get_controlport(self, my):
|
|
|
+ return my['controlport_base']+my['nodenum']
|
|
|
|
|
|
- def _get_socksport(self, me):
|
|
|
- return me['socksport_base']+me['nodenum']
|
|
|
+ def _get_socksport(self, my):
|
|
|
+ return my['socksport_base']+my['nodenum']
|
|
|
|
|
|
- def _get_dirport(self, me):
|
|
|
- return me['dirport_base']+me['nodenum']
|
|
|
+ def _get_dirport(self, my):
|
|
|
+ return my['dirport_base']+my['nodenum']
|
|
|
|
|
|
- def _get_dir(self, me):
|
|
|
- return os.path.abspath(os.path.join(me['net_base_dir'],
|
|
|
+ def _get_dir(self, my):
|
|
|
+ return os.path.abspath(os.path.join(my['net_base_dir'],
|
|
|
"nodes",
|
|
|
- "%03d%s"%(me['nodenum'], me['tag'])))
|
|
|
+ "%03d%s"%(my['nodenum'], my['tag'])))
|
|
|
|
|
|
- def _get_nick(self, me):
|
|
|
- return "test%03d%s"%(me['nodenum'], me['tag'])
|
|
|
+ def _get_nick(self, my):
|
|
|
+ return "test%03d%s"%(my['nodenum'], my['tag'])
|
|
|
|
|
|
- def _get_tor_gencert(self, me):
|
|
|
- return me['tor']+"-gencert"
|
|
|
+ def _get_tor_gencert(self, my):
|
|
|
+ return my['tor']+"-gencert"
|
|
|
|
|
|
- def _get_auth_passphrase(self, me):
|
|
|
+ def _get_auth_passphrase(self, my):
|
|
|
return self['nick'] # OMG TEH SECURE!
|
|
|
|
|
|
- def _get_torrc_template_path(self, me):
|
|
|
- return [ os.path.join(me['privnet_dir'], 'torrc_templates') ]
|
|
|
+ def _get_torrc_template_path(self, my):
|
|
|
+ return [ os.path.join(my['privnet_dir'], 'torrc_templates') ]
|
|
|
|
|
|
|
|
|
class Network(object):
|
|
@@ -392,12 +384,12 @@ def ConfigureNodes(nodelist):
|
|
|
network._addNode(n)
|
|
|
|
|
|
def runConfigFile(verb, f):
|
|
|
- global _BASE_FIELDS
|
|
|
+ global _BASE_ENVIRON
|
|
|
global _THE_NETWORK
|
|
|
- _BASE_FIELDS = TorEnviron(chutney.Templating.Environ(**DEFAULTS))
|
|
|
- _THE_NETWORK = Network(_BASE_FIELDS)
|
|
|
+ _BASE_ENVIRON = TorEnviron(chutney.Templating.Environ(**DEFAULTS))
|
|
|
+ _THE_NETWORK = Network(_BASE_ENVIRON)
|
|
|
|
|
|
- _GLOBALS = dict(_BASE_FIELDS= _BASE_FIELDS,
|
|
|
+ _GLOBALS = dict(_BASE_ENVIRON= _BASE_ENVIRON,
|
|
|
Node=Node,
|
|
|
ConfigureNodes=ConfigureNodes,
|
|
|
_THE_NETWORK=_THE_NETWORK)
|