mirror of git://git.psyced.org/git/pypsyc
187 lines
6.9 KiB
Python
187 lines
6.9 KiB
Python
"""network code for pyPSYC"""
|
|
|
|
from pypsyc import GLYPHS
|
|
|
|
from pypsyc.PSYC import PSYCProtocol
|
|
from pypsyc import parseUNL, UNL2Location
|
|
|
|
from twisted.names import client
|
|
from twisted.internet import reactor
|
|
from twisted.internet.protocol import ClientFactory, ServerFactory
|
|
|
|
|
|
class HostChecker:
|
|
"""checks validity of _source/_context in a packet
|
|
this could well implement policies like trusted from localhost"""
|
|
def __init__(self, center, target, myname):
|
|
self.target = target
|
|
self.myname = myname
|
|
self.center = center
|
|
def check(self, vars, mc, data, protocol, peer):
|
|
source = vars.get('_context') or vars.get('_source')
|
|
if (source and not
|
|
source.startswith('psyc://%s'%(peer.host))):
|
|
u = parseUNL(source)
|
|
d = client.lookupAddress(u['host'])
|
|
d.addCallback(self.resolved, peer.host, vars, mc, data, protocol)
|
|
elif source:
|
|
# numeric address
|
|
self.handle(vars, mc, data, protocol)
|
|
else:
|
|
protocol.msg({ '_source' : self.myname },
|
|
'_error_syntax_protocol_missing_source',
|
|
'Your implementation is broken')
|
|
def handle(self, vars, mc, data, protocol):
|
|
method = getattr(self, 'recv%s'%mc, None)
|
|
if method is not None:
|
|
method(vars, mc, data, protocol)
|
|
else:
|
|
u = parseUNL(vars['_source'])
|
|
self.center.register_remote(protocol, u['root'])
|
|
self.center.msg(vars, mc, data)
|
|
def resolved(self, record, shouldbe, vars, mc, data, protocol):
|
|
v = { '_source' : self.myname,
|
|
'_target' : vars['_source'] }
|
|
if not record[0]:
|
|
print 'name not resolvable'
|
|
protocol.msg(v, '_error_rejected_relay',
|
|
'[_source] is not resolvable. Goodbye')
|
|
protocol.transport.loseConnection()
|
|
elif record[0][0].type == 5:
|
|
payload = record[0][0].payload
|
|
d = client.lookupAddress(payload.name.name)
|
|
d.addCallback(self.resolved, shouldbe, vars, mc, data, protocol)
|
|
else:
|
|
payload = record[0][0].payload
|
|
if payload.dottedQuad() == shouldbe:
|
|
self.handle(vars, mc, data, protocol)
|
|
else:
|
|
print 'rejected relay'
|
|
protocol.msg(v, '_error_rejected_relay',
|
|
'[_source] does not resolve to your ip.')
|
|
protocol.transport.loseConnection()
|
|
|
|
|
|
class PSYCConnector:
|
|
hostname = ''
|
|
port = 4404
|
|
factory = None
|
|
factory_type = None
|
|
real_hostname = ''
|
|
def __init__(self, center, target, myname = None):
|
|
# TODO: dont try to resolve IP addresses ;)
|
|
# must subclass
|
|
if not self.factory_type: raise NotImplementedError
|
|
try:
|
|
self.factory = self.factory_type(center, target, myname)
|
|
except:
|
|
print self.factory_type
|
|
raise
|
|
u = parseUNL(target)
|
|
self.host = u['host']
|
|
d = client.lookupService('_psyc._tcp.' + self.host)
|
|
d.addCallback(self.srvResolved)
|
|
def get_queue(self):
|
|
return self.factory
|
|
def resolved(self, record):
|
|
if not record[0]:
|
|
print 'resolution failed...'
|
|
else:
|
|
payload = record[0][0].payload
|
|
if record[0][0].type == 5: # evil cname
|
|
d = client.lookupAddress(payload.name.name)
|
|
d.addCallback(self.resolved)
|
|
else:
|
|
reactor.connectTCP(payload.dottedQuad(), self.port, self.factory)
|
|
return True
|
|
def srvResolved(self, record):
|
|
if not record[0]:
|
|
d = client.lookupAddress(self.host)
|
|
d.addCallback(self.resolved)
|
|
else:
|
|
payload = record[0][0].payload
|
|
self.port = payload.port
|
|
d = client.lookupAddress(payload.target.name)
|
|
d.addCallback(self.resolved)
|
|
return True
|
|
|
|
|
|
class PSYCClientFactory(ClientFactory):
|
|
"""a factory for a client which does not have to check
|
|
for validity of host names"""
|
|
class PSYCClient(PSYCProtocol):
|
|
def connectionMade(self):
|
|
PSYCProtocol.connectionMade(self)
|
|
self.factory.connectionMade(self)
|
|
|
|
protocol = PSYCClient
|
|
center = None
|
|
location = None
|
|
def __init__(self, center, location, myname):
|
|
self.center = center
|
|
self.location = location
|
|
def connectionMade(self, proto):
|
|
self.center.register_remote(proto, self.location)
|
|
self.center.gotOnline()
|
|
def packetReceived(self, vars, mc, data, protocol, peer):
|
|
self.center.msg(vars, mc, data)
|
|
|
|
|
|
class PSYCClientConnector(PSYCConnector):
|
|
factory_type = PSYCClientFactory
|
|
|
|
|
|
class PSYCActiveFactory(ClientFactory, HostChecker):
|
|
"""a factory for a client which does hostname checks
|
|
maybe this will also become a Q
|
|
probably we want to override connectionMade?"""
|
|
protocol = PSYCProtocol
|
|
queue = []
|
|
connected = None
|
|
def packetReceived(self, vars, mc, data, protocol, peer):
|
|
self.check(vars, mc, data, protocol, peer)
|
|
def msg(self, vars, mc, data):
|
|
# watch out, if we dont use dict-vars we may need deepcopy
|
|
if self.connected is not None:
|
|
self.connected.msg(vars, mc, data)
|
|
else:
|
|
self.queue.append((vars, mc, data))
|
|
def run_queue(self, target):
|
|
for (vars, mc, data) in self.queue:
|
|
target.msg(vars, mc, data)
|
|
self.queue = []
|
|
self.connected = target
|
|
def recv_notice_circuit_established(self, vars, mc, data, protocol):
|
|
print 'got _notice_circuit_established'
|
|
protocol.msg({'_source' : self.myname,
|
|
'_target' : self.target or vars['_source'] },
|
|
'_notice_circuit_established',
|
|
'hi there')
|
|
# TODO: what do we register here? source oder our definition of
|
|
# what the source should be (self.target)
|
|
self.center.register_remote(protocol, self.target)
|
|
self.run_queue(protocol)
|
|
|
|
|
|
class PSYCActiveConnector(PSYCConnector):
|
|
factory_type = PSYCActiveFactory
|
|
|
|
|
|
class PSYCServerFactory(ServerFactory, HostChecker):
|
|
"""funny question... do we deal all the stuff about
|
|
modules, compression, tls etc here?"""
|
|
class PSYCServerProtocol(PSYCProtocol):
|
|
def connectionMade(self):
|
|
peer = self.transport.getPeer()
|
|
PSYCProtocol.connectionMade(self)
|
|
self.msg({ '_source' : self.factory.myname,
|
|
'_target' : 'psyc://%s:-%d'%(peer.host, peer.port)},
|
|
'_notice_circuit_established',
|
|
'Connection to [_source] established')
|
|
|
|
protocol = PSYCServerProtocol
|
|
def packetReceived(self, vars, mc, data, protocol, peer):
|
|
self.check(vars, mc, data, protocol, peer)
|
|
def recv_notice_circuit_established(self, vars, mc, data, protocol):
|
|
self.center.register_remote(protocol, vars['_source'])
|