def _ProcessGRRMessages(self, fs_client_id: bytes, grr_messages: Iterable[rdf_flows.GrrMessage], validation_info: Dict[str, str]): """Handles messages from GRR clients received via Fleetspeak. This method updates the last-ping timestamp of the client before beginning processing. Args: fs_client_id: The Fleetspeak client-id for the client. grr_messages: An Iterable of GrrMessages. validation_info: """ grr_client_id = fleetspeak_utils.FleetspeakIDToGRRID(fs_client_id) for grr_message in grr_messages: grr_message.source = grr_client_id grr_message.auth_state = ( rdf_flows.GrrMessage.AuthorizationState.AUTHENTICATED) client_is_new = self.frontend.EnrolFleetspeakClient( client_id=grr_client_id) if not client_is_new: data_store.REL_DB.WriteClientMetadata( grr_client_id, last_ping=rdfvalue.RDFDatetime.Now(), fleetspeak_validation_info=validation_info) self.frontend.ReceiveMessages(client_id=grr_client_id, messages=grr_messages)
def _GetLastContactFromFleetspeak(client_ids): """Fetches last contact times for the given clients from Fleetspeak. Args: client_ids: Iterable containing GRR client ids. Returns: A dict mapping the given client ids to timestamps representing when Fleetspeak last contacted the clients. """ if not fleetspeak_connector.CONN or not fleetspeak_connector.CONN.outgoing: logging.warning( "Tried to get last-contact timestamps for Fleetspeak clients " "without an active connection to Fleetspeak.") return {} fs_ids = [fleetspeak_utils.GRRIDToFleetspeakID(cid) for cid in client_ids] fs_result = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest(client_ids=fs_ids)) if len(client_ids) != len(fs_result.clients): logging.error("Expected %d results from Fleetspeak; got %d instead.", len(client_ids), len(fs_result.clients)) last_contact_times = {} for fs_client in fs_result.clients: grr_id = fleetspeak_utils.FleetspeakIDToGRRID(fs_client.client_id) last_contact_times[grr_id] = fleetspeak_utils.TSToRDFDatetime( fs_client.last_contact_time) return last_contact_times
def FromFleetspeakProto( cls, proto: common_pb2.Address) -> "ApiFleetspeakAddress": if proto.client_id: client_id = fleetspeak_utils.FleetspeakIDToGRRID(proto.client_id) else: client_id = None return ApiFleetspeakAddress( client_id=client_id, service_name=proto.service_name, )
def _ProcessGrrMessage(self, fs_msg): """Process a FS message when message_type is GrrMessage.""" grr_id = fleetspeak_utils.FleetspeakIDToGRRID(fs_msg.source.client_id) msg = rdf_flows.GrrMessage.FromSerializedString(fs_msg.data.value) msg.source = grr_id # Fleetspeak ensures authentication. msg.auth_state = rdf_flows.GrrMessage.AuthorizationState.AUTHENTICATED self.frontend.EnrolFleetspeakClient(client_id=grr_id) self.frontend.ReceiveMessages(client_id=grr_id, messages=[msg])
def _ProcessMessageList(self, fs_msg): """Process a FS message when message_type is MessageList.""" grr_id = fleetspeak_utils.FleetspeakIDToGRRID(fs_msg.source.client_id) msg_list = rdf_flows.PackedMessageList.FromSerializedString( fs_msg.data.value) msg_list = communicator.Communicator.DecompressMessageList(msg_list) for msg in msg_list.job: msg.source = grr_id msg.auth_state = rdf_flows.GrrMessage.AuthorizationState.AUTHENTICATED self.frontend.EnrolFleetspeakClient(client_id=grr_id) self.frontend.ReceiveMessages(client_id=grr_id, messages=msg_list.job)
def StoreMessage(fs_msg: common_pb2.Message): """Emulates sending of a message to Fleetspeak by storing it in-memory.""" if not fs_msg.destination.client_id: raise ValueError("No destination set for Fleetspeak message:\n%s" % fs_msg) grr_id = fleetspeak_utils.FleetspeakIDToGRRID(fs_msg.destination.client_id) raw_grr_msg = jobs_pb2.GrrMessage() fs_msg.data.Unpack(raw_grr_msg) grr_msg = rdf_flows.GrrMessage.FromSerializedBytes( raw_grr_msg.SerializeToString()) with _message_lock: try: _messages_by_client_id[grr_id].append(grr_msg) except KeyError: _messages_by_client_id[grr_id] = collections.deque([grr_msg])
def Run(self): if not fleetspeak_connector.CONN or not fleetspeak_connector.CONN.outgoing: # Nothing to do if Fleetspeak is not enabled. self.Log("Fleetspeak has not been initialized. Will do nothing.") return if not data_store.RelationalDBWriteEnabled(): raise NotImplementedError( "Cronjob does not support the legacy datastore.") age_threshold = config.CONFIG["Server.fleetspeak_last_ping_threshold"] max_last_ping = rdfvalue.RDFDatetime.Now() - age_threshold last_pings = data_store.REL_DB.ReadClientLastPings( max_last_ping=max_last_ping, fleetspeak_enabled=True) num_clients_updated = 0 batch_size = config.CONFIG["Server.fleetspeak_list_clients_batch_size"] for client_ids in collection.Batch(iterkeys(last_pings), batch_size): fs_ids = [ fleetspeak_utils.GRRIDToFleetspeakID(i) for i in client_ids ] request_start = rdfvalue.RDFDatetime.Now() fs_result = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest(client_ids=fs_ids)) latency = rdfvalue.RDFDatetime.Now() - request_start logging.info("Fleetspeak ListClients() took %s.", latency) stats_collector_instance.Get().RecordEvent( "fleetspeak_last_ping_latency_millis", latency.milliseconds) for fs_client in fs_result.clients: grr_id = fleetspeak_utils.FleetspeakIDToGRRID( fs_client.client_id) new_last_ping = fleetspeak_utils.TSToRDFDatetime( fs_client.last_contact_time) if last_pings[grr_id] is None or last_pings[ grr_id] < new_last_ping: data_store.REL_DB.WriteClientMetadata( grr_id, last_ping=new_last_ping) num_clients_updated += 1 self.Log("Updated timestamps for %d clients.", num_clients_updated)