Exemple #1
0
	def __init__(self, type, data={}):
		self._content = {
			'type': type,
			'timestamp': time.time(),
			'sender': kozoSystem().getSelfNode().getName(),
			'data': data
		}
		self._size = None
Exemple #2
0
	def init(self):
		if self['incomingOnly'] and self['outgoingOnly']:
			raise KozoError('Cannot have both incomingOnly and outgoingOnly enabled.')
		if self['outgoingOnly'] and self['address']:
			raise KozoError('Cannot provide both outgoingOnly and address.')
		if not self['outgoingOnly']:
			if not self['address']:
				raise KozoError('Must provide .onion address.')
			if not self['address'].endswith('.onion'):
				raise KozoError('Address must end in .onion.')
		if self['onionPort'] is None:
			self['onionPort'] = self['port']
		self._serverSocket = None
		self._maxNodeNameLength = max(len(node.getName()) for node in kozoSystem().getNodes())
		if self._maxNodeNameLength + self.RANDOM_LENGTH[1] > self.MAX_INITIAL_SIGN_LENGTH / 2:
			raise KozoError('Some Node in the system has a name that is too long for the onion Transport to work.')
Exemple #3
0
	def getSender(self):
		return kozoSystem().getNodeByName(self._content['sender'])
Exemple #4
0
	def getRecipientNodes(self):
		return kozoSystem().getNodes()
Exemple #5
0
	def accept(self):
		infoTransport(self, 'Waiting for a connection')
		assert self._serverSocket is not None
		selfNode = self.getNode()
		selfName = selfNode.getName()
		connection = self._serverSocket.accept()[0]
		try:
			connection.settimeout(kozoConfig('connectionRetry'))
			# Parse header.
			knockHeader = self._readLoop(connection.recv, len(self.MAGIC_KNOCKKNOCK))
			if knockHeader != self.MAGIC_KNOCKKNOCK:
				raise KozoError('Invalid header received')
			nodeNameLength = struct.unpack('=H', self._readLoop(connection.recv, struct.calcsize('=H')))[0]
			if nodeNameLength > self._maxNodeNameLength:
				raise KozoError('Node length field larger than largest-named node defined in the system:', nodeNameLength)
			remoteName = self._readLoop(connection.recv, nodeNameLength).decode('utf8')
			remoteNode = kozoSystem().getNodeByName(remoteName)
			if remoteNode is None:
				raise KozoError('Unknown node name received', repr(remoteName))
			remoteKey = paramiko.RSAKey(data=base64.b64decode(remoteNode.getPublicKey()[1]))
			# Generate message to sign.
			selfDate = int(time.time())
			selfRandom = self._genRandom()
			initialToSign = self.INITIAL_SIGN_FORMAT.format(
				date=str(selfDate).encode('utf8'),
				server=selfName.encode('utf8'),
				client=remoteName.encode('utf8'),
				random=selfRandom
			)
			# Send it.
			connection.sendall(struct.pack('=H', len(initialToSign)) + initialToSign)
			# Get and verify signed response.
			remoteDate, remoteRandomLength, remoteSignedLength = struct.unpack('=Qii', self._readLoop(connection.recv, struct.calcsize('=Qii')))
			if abs(remoteDate - selfDate) > self.MAX_DATE_DELTA:
				raise KozoError('Clocks differ by', abs(remoteDate - selfDate), 'seconds; rejecting message')
			if remoteRandomLength < self.RANDOM_LENGTH[0]:
				raise KozoError('Remote random string is shorter than minimum of', self.RANDOM_LENGTH[0], 'bytes')
			if remoteRandomLength > self.RANDOM_LENGTH[1]:
				raise KozoError('Remote random string is longer than maximum of', self.RANDOM_LENGTH[1], 'bytes')
			remoteRandom = self._readLoop(connection.recv, remoteRandomLength)
			actualToSign = self.ACTUAL_SIGN_FORMAT.format(
				initial=initialToSign,
				date=str(remoteDate).encode('utf8'),
				server=selfName.encode('utf8'),
				client=remoteName.encode('utf8'),
				random=remoteRandom
			)
			if len(actualToSign) > self.MAX_ACTUAL_SIGN_LENGTH:
				raise KozoError('Message to sign is too long:', len(actualToSign), 'bytes while max is', self.MAX_ACTUAL_SIGN_LENGTH)
			if remoteSignedLength > len(actualToSign) * self.SIGNED_MAX_EXPANSION_FACTOR:
				raise KozoError('Signed message is too long:', remoteSignedLength, 'bytes while max is', len(actualToSign) * self.SIGNED_MAX_EXPANSION_FACTOR)
			actualSigned = paramiko.Message(self._readLoop(connection.recv, remoteSignedLength))
			if not remoteKey.verify_ssh_sig(actualToSign, actualSigned):
				raise KozoError('Invalid signature received')
			# Send acknowledgement.
			connection.sendall(self.SIGN_OK)
			# We're clear.
			return OnionChannel(remoteNode, selfNode, connection)
		except BaseException:
			try:
				connection.close()
			except:
				pass
			raise