async def secure_send(msg: dict, service, wallet: Wallet, vk, ip, ctx: zmq.asyncio.Context, linger=500, cert_dir=DEFAULT_DIR): #if wallet.verifying_key == vk: # return socket = ctx.socket(zmq.DEALER) socket.setsockopt(zmq.LINGER, linger) socket.setsockopt(zmq.TCP_KEEPALIVE, 1) socket.curve_secretkey = wallet.curve_sk socket.curve_publickey = wallet.curve_vk filename = str(cert_dir / f'{vk}.key') if not os.path.exists(filename): return None server_pub, _ = load_certificate(filename) socket.curve_serverkey = server_pub try: socket.connect(ip) except ZMQBaseError: socket.close() return None message = build_message(service=service, message=msg) payload = encode(message).encode() await socket.send(payload, flags=zmq.NOBLOCK) socket.close()
async def secure_request(msg: dict, service: str, wallet: Wallet, vk: str, ip: str, ctx: zmq.asyncio.Context, linger=500, timeout=1000, cert_dir=DEFAULT_DIR): #if wallet.verifying_key == vk: # return socket = ctx.socket(zmq.DEALER) socket.setsockopt(zmq.LINGER, linger) socket.setsockopt(zmq.TCP_KEEPALIVE, 1) socket.curve_secretkey = wallet.curve_sk socket.curve_publickey = wallet.curve_vk filename = str(cert_dir / f'{vk}.key') if not os.path.exists(filename): return None server_pub, _ = load_certificate(filename) socket.curve_serverkey = server_pub try: socket.connect(ip) except ZMQBaseError: logger.debug(f'Could not connect to {ip}') socket.close() return None message = build_message(service=service, message=msg) payload = encode(message).encode() await socket.send(payload) event = await socket.poll(timeout=timeout, flags=zmq.POLLIN) msg = None if event: #logger.debug(f'Message received on {ip}') response = await socket.recv() msg = decode(response) socket.close() return msg
async def secure_send_out(wallet, ctx, msg, socket_id, server_vk, cert_dir='cilsocks'): # Setup a socket and its monitor socket = ctx.socket(zmq.DEALER) socket.curve_secretkey = wallet.curve_sk socket.curve_publickey = wallet.curve_vk cert_dir = pathlib.Path.home() / cert_dir cert_dir.mkdir(parents=True, exist_ok=True) server_pub, _ = load_certificate(str(cert_dir / f'{server_vk}.key')) socket.curve_serverkey = server_pub s = socket.get_monitor_socket() # Try to connect socket.connect(str(socket_id)) event = 2 evnt_dict = {} while event == 2: evnt = await s.recv_multipart() evnt_dict = monitor.parse_monitor_message(evnt) event = evnt_dict['event'] # If so, shoot out the message if event == 1: socket.send(msg, flags=zmq.NOBLOCK) socket.disconnect(str(socket_id)) return True, evnt_dict['endpoint'].decode() # Otherwise, close the socket. Return result and the socket for further processing / updating sockets socket.disconnect(str(socket_id)) return False, evnt_dict['endpoint'].decode()
def message_proxy(self, work_dir): """ drone_data_inboud is for data comming from drones drone_data_outbound is for commands to the drone, topic must either be a drone ID or all for sending a broadcast message to all drones """ ctx = zmq.Context() public_keys_dir = os.path.join(work_dir, 'certificates', 'public_keys') secret_keys_dir = os.path.join(work_dir, 'certificates', 'private_keys') # start and configure auth worker auth = IOLoopAuthenticator() auth.start() auth.allow('127.0.0.1') auth.configure_curve(domain='*', location=public_keys_dir) # external interfaces for communicating with drones server_secret_file = os.path.join(secret_keys_dir, 'beeswarm_server.pri') server_public, server_secret = load_certificate(server_secret_file) drone_data_inbound = ctx.socket(zmq.PULL) drone_data_inbound.curve_secretkey = server_secret drone_data_inbound.curve_publickey = server_public drone_data_inbound.curve_server = True drone_data_inbound.bind('tcp://*:{0}'.format(self.config['network']['zmq_port'])) drone_data_outbound = ctx.socket(zmq.PUB) drone_data_outbound.curve_secretkey = server_secret drone_data_outbound.curve_publickey = server_public drone_data_outbound.curve_server = True drone_data_outbound.bind('tcp://*:{0}'.format(self.config['network']['zmq_command_port'])) # internal interfaces # all inbound session data from drones will be replayed in this socket sessionPublisher = ctx.socket(zmq.PUB) sessionPublisher.bind('ipc://sessionPublisher') # all commands received on this will be published on the external interface drone_command_receiver = ctx.socket(zmq.PULL) drone_command_receiver.bind('ipc://droneCommandReceiver') poller = zmq.Poller() poller.register(drone_data_inbound, zmq.POLLIN) poller.register(drone_command_receiver, zmq.POLLIN) while True: # .recv() gives no context switch - why not? using poller with timeout instead socks = dict(poller.poll(1)) gevent.sleep() if drone_command_receiver in socks and socks[drone_command_receiver] == zmq.POLLIN: data = drone_command_receiver.recv() topic, _ = data.split(' ', 1) logger.debug("Sending drone command to: {0}".format(topic)) # pub socket takes care of filtering drone_data_outbound.send(data) elif drone_data_inbound in socks and socks[drone_data_inbound] == zmq.POLLIN: topic, data = drone_data_inbound.recv().split(' ', 1) logger.debug("Received {0} data.".format(topic)) if topic == Messages.SESSION_HONEYPOT or topic == Messages.SESSION_CLIENT: sessionPublisher.send('{0} {1}'.format(topic, data)) elif topic == Messages.KEY or topic == Messages.CERT: # for now we just store the fingerprint # in the future it might be relevant to store the entire public key and private key # for forensic purposes if topic == Messages.CERT: drone_id, cert = data.split(' ', 1) digest = generate_cert_digest(cert) logging.debug('Storing public key digest: {0} for drone {1}.'.format(digest, drone_id)) db_session = database_setup.get_session() drone = db_session.query(Drone).filter(Drone.id == drone_id).one() drone.cert_digest = digest db_session.add(drone) db_session.commit() elif topic == Messages.PING: drone_id = data db_session = database_setup.get_session() drone = db_session.query(Drone).filter(Drone.id == drone_id).one() drone.last_activity = datetime.now() db_session.add(drone) db_session.commit() else: logger.warn('Message with unknown topic received: {0}'.format(topic))
def message_proxy(self, work_dir): """ drone_data_inboud is for data comming from drones drone_data_outbound is for commands to the drones, topic must either be a drone ID or all for sending a broadcast message to all drones """ public_keys_dir = os.path.join(work_dir, 'certificates', 'public_keys') secret_keys_dir = os.path.join(work_dir, 'certificates', 'private_keys') # start and configure auth worker auth = IOLoopAuthenticator() auth.start() auth.allow('127.0.0.1') auth.configure_curve(domain='*', location=public_keys_dir) # external interfaces for communicating with drones server_secret_file = os.path.join(secret_keys_dir, 'beeswarm_server.pri') server_public, server_secret = load_certificate(server_secret_file) drone_data_inbound = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_data_inbound.curve_secretkey = server_secret drone_data_inbound.curve_publickey = server_public drone_data_inbound.curve_server = True drone_data_inbound.bind('tcp://*:{0}'.format( self.config['network']['zmq_port'])) drone_data_outbound = beeswarm.shared.zmq_context.socket(zmq.PUB) drone_data_outbound.curve_secretkey = server_secret drone_data_outbound.curve_publickey = server_public drone_data_outbound.curve_server = True drone_data_outbound.bind('tcp://*:{0}'.format( self.config['network']['zmq_command_port'])) # internal interfaces # all inbound session data from drones will be replayed on this socket drone_data_socket = beeswarm.shared.zmq_context.socket(zmq.PUB) drone_data_socket.bind(SocketNames.DRONE_DATA.value) # all commands received on this will be published on the external interface drone_command_socket = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_command_socket.bind(SocketNames.DRONE_COMMANDS.value) poller = zmq.Poller() poller.register(drone_data_inbound, zmq.POLLIN) poller.register(drone_command_socket, zmq.POLLIN) while True: # .recv() gives no context switch - why not? using poller with timeout instead socks = dict(poller.poll(100)) gevent.sleep() if drone_command_socket in socks and socks[ drone_command_socket] == zmq.POLLIN: data = drone_command_socket.recv() drone_id, _ = data.split(' ', 1) logger.debug("Sending drone command to: {0}".format(drone_id)) # pub socket takes care of filtering drone_data_outbound.send(data) elif drone_data_inbound in socks and socks[ drone_data_inbound] == zmq.POLLIN: raw_msg = drone_data_inbound.recv() split_data = raw_msg.split(' ', 2) if len(split_data) == 3: topic, drone_id, data = split_data else: data = None topic, drone_id, = split_data logger.debug("Received {0} message from {1}.".format( topic, drone_id)) # relay message on internal socket drone_data_socket.send(raw_msg)
def message_proxy(self, work_dir): """ drone_data_inboud is for data comming from drones drone_data_outbound is for commands to the drones, topic must either be a drone ID or all for sending a broadcast message to all drones """ public_keys_dir = os.path.join(work_dir, 'certificates', 'public_keys') secret_keys_dir = os.path.join(work_dir, 'certificates', 'private_keys') # start and configure auth worker auth = IOLoopAuthenticator() auth.start() auth.allow('127.0.0.1') auth.configure_curve(domain='*', location=public_keys_dir) # external interfaces for communicating with drones server_secret_file = os.path.join(secret_keys_dir, 'beeswarm_server.pri') server_public, server_secret = load_certificate(server_secret_file) drone_data_inbound = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_data_inbound.curve_secretkey = server_secret drone_data_inbound.curve_publickey = server_public drone_data_inbound.curve_server = True drone_data_inbound.bind('tcp://*:{0}'.format( self.config['network']['zmq_port'])) drone_data_outbound = beeswarm.shared.zmq_context.socket(zmq.PUB) drone_data_outbound.curve_secretkey = server_secret drone_data_outbound.curve_publickey = server_public drone_data_outbound.curve_server = True drone_data_outbound.bind('tcp://*:{0}'.format( self.config['network']['zmq_command_port'])) # internal interfaces # all inbound session data from drones will be replayed in this socket sessionPublisher = beeswarm.shared.zmq_context.socket(zmq.PUB) sessionPublisher.bind('inproc://sessionPublisher') # all commands received on this will be published on the external interface drone_command_receiver = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_command_receiver.bind('inproc://droneCommandReceiver') poller = zmq.Poller() poller.register(drone_data_inbound, zmq.POLLIN) poller.register(drone_command_receiver, zmq.POLLIN) while True: # .recv() gives no context switch - why not? using poller with timeout instead socks = dict(poller.poll(100)) gevent.sleep() if drone_command_receiver in socks and socks[ drone_command_receiver] == zmq.POLLIN: data = drone_command_receiver.recv() drone_id, _ = data.split(' ', 1) logger.debug("Sending drone command to: {0}".format(drone_id)) # pub socket takes care of filtering drone_data_outbound.send(data) elif drone_data_inbound in socks and socks[ drone_data_inbound] == zmq.POLLIN: split_data = drone_data_inbound.recv().split(' ', 2) if len(split_data) == 3: topic, drone_id, data = split_data else: data = None topic, drone_id, = split_data logger.debug("Received {0} message from {1}.".format( topic, drone_id)) db_session = database_setup.get_session() drone = db_session.query(Drone).filter( Drone.id == drone_id).one() drone.last_activity = datetime.now() db_session.add(drone) db_session.commit() if topic == Messages.SESSION_HONEYPOT or topic == Messages.SESSION_CLIENT: sessionPublisher.send('{0} {1}'.format(topic, data)) elif topic == Messages.KEY or topic == Messages.CERT: # for now we just store the fingerprint # in the future it might be relevant to store the entire public key and private key # for forensic purposes if topic == Messages.CERT: cert = data.split(' ', 1)[1] digest = generate_cert_digest(cert) logging.debug( 'Storing public key digest: {0} for drone {1}.'. format(digest, drone_id)) db_session = database_setup.get_session() drone = db_session.query(Drone).filter( Drone.id == drone_id).one() drone.cert_digest = digest db_session.add(drone) db_session.commit() elif topic == Messages.PING: pass elif topic == Messages.IP: ip_address = data logging.debug('Drone {0} reported ip: {1}'.format( drone_id, ip_address)) db_session = database_setup.get_session() drone = db_session.query(Drone).filter( Drone.id == drone_id).one() if drone.ip_address != ip_address: drone.ip_address = ip_address db_session.add(drone) db_session.commit() send_zmq_request( 'inproc://configCommands', '{0} {1}'.format(Messages.DRONE_CONFIG_CHANGED, drone_id)) # drone want it's config transmitted elif topic == Messages.DRONE_CONFIG: config_dict = send_zmq_request( 'inproc://configCommands', '{0} {1}'.format(Messages.DRONE_CONFIG, drone_id)) drone_data_outbound.send('{0} {1} {2}'.format( drone_id, Messages.CONFIG, json.dumps(config_dict))) else: logger.warn( 'Message with unknown topic received: {0}'.format( topic))
def message_proxy(self, work_dir): """ drone_data_inboud is for data comming from drones drone_data_outbound is for commands to the drones, topic must either be a drone ID or all for sending a broadcast message to all drones """ public_keys_dir = os.path.join(work_dir, 'certificates', 'public_keys') secret_keys_dir = os.path.join(work_dir, 'certificates', 'private_keys') # start and configure auth worker auth = IOLoopAuthenticator() auth.start() auth.allow('127.0.0.1') auth.configure_curve(domain='*', location=public_keys_dir) # external interfaces for communicating with drones server_secret_file = os.path.join(secret_keys_dir, 'beeswarm_server.pri') server_public, server_secret = load_certificate(server_secret_file) drone_data_inbound = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_data_inbound.curve_secretkey = server_secret drone_data_inbound.curve_publickey = server_public drone_data_inbound.curve_server = True drone_data_inbound.bind('tcp://*:{0}'.format(self.config['network']['zmq_port'])) drone_data_outbound = beeswarm.shared.zmq_context.socket(zmq.PUB) drone_data_outbound.curve_secretkey = server_secret drone_data_outbound.curve_publickey = server_public drone_data_outbound.curve_server = True drone_data_outbound.bind('tcp://*:{0}'.format(self.config['network']['zmq_command_port'])) # internal interfaces # all inbound session data from drones will be replayed on this socket drone_data_socket = beeswarm.shared.zmq_context.socket(zmq.PUB) drone_data_socket.bind(SocketNames.DRONE_DATA.value) # all commands received on this will be published on the external interface drone_command_socket = beeswarm.shared.zmq_context.socket(zmq.PULL) drone_command_socket.bind(SocketNames.DRONE_COMMANDS.value) poller = zmq.Poller() poller.register(drone_data_inbound, zmq.POLLIN) poller.register(drone_command_socket, zmq.POLLIN) while True: # .recv() gives no context switch - why not? using poller with timeout instead socks = dict(poller.poll(100)) gevent.sleep() if drone_command_socket in socks and socks[drone_command_socket] == zmq.POLLIN: data = drone_command_socket.recv() drone_id, _ = data.split(' ', 1) logger.debug("Sending drone command to: {0}".format(drone_id)) # pub socket takes care of filtering drone_data_outbound.send(data) elif drone_data_inbound in socks and socks[drone_data_inbound] == zmq.POLLIN: raw_msg = drone_data_inbound.recv() split_data = raw_msg.split(' ', 2) if len(split_data) == 3: topic, drone_id, data = split_data else: data = None topic, drone_id, = split_data logger.debug("Received {0} message from {1}.".format(topic, drone_id)) # relay message on internal socket drone_data_socket.send(raw_msg)