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 GetLabelsFromFleetspeak(client_id): """Returns labels for a Fleetspeak-enabled client. Fleetspeak-enabled clients delegate labeling to Fleetspeak, as opposed to using labels in the GRR config. Args: client_id: Id of the client to fetch Fleetspeak labels for. Returns: A list of client labels. """ res = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest( client_ids=[GRRIDToFleetspeakID(client_id)])) if not res.clients or not res.clients[0].labels: return [] grr_labels = [] label_prefix = config.CONFIG["Server.fleetspeak_label_prefix"] for fs_label in res.clients[0].labels: if (fs_label.service_name != "client" or (label_prefix and not fs_label.label.startswith(label_prefix))): continue try: grr_labels.append(fleetspeak_connector.label_map[fs_label.label]) except KeyError: grr_labels.append(fs_label.label) return grr_labels
def _GetAddrFromFleetspeak(client_id): res = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest( client_ids=[fleetspeak_utils.GRRIDToFleetspeakID(client_id)])) if not res.clients or not res.clients[0].last_contact_address: return "", None # last_contact_address typically includes a port parsed = urlparse.urlparse("//{}".format(res.clients[0].last_contact_address)) ip_str = parsed.hostname return ip_str, ipaddress.ip_address(ip_str)
def GetLabelFromFleetspeak(client_id): """Returns the primary GRR label to use for a fleetspeak client.""" res = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest(client_ids=[GRRIDToFleetspeakID(client_id)])) if not res.clients or not res.clients[0].labels: return fleetspeak_connector.unknown_label for label in res.clients[0].labels: if label.service_name != "client": continue if label.label in fleetspeak_connector.label_map: return fleetspeak_connector.label_map[label.label] return fleetspeak_connector.unknown_label
def UpdateClientsFromFleetspeak(clients): """Updates ApiClient records to include info from Fleetspeak.""" if not fleetspeak_connector.CONN or not fleetspeak_connector.CONN.outgoing: # FS not configured, or an outgoing connection is otherwise unavailable. return id_map = {} for client in clients: if client.fleetspeak_enabled: id_map[fleetspeak_utils.GRRIDToFleetspeakID(client.client_id)] = client if not id_map: return res = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest(client_ids=list(iterkeys(id_map)))) for read in res.clients: api_client = id_map[read.client_id] api_client.last_seen_at = fleetspeak_utils.TSToRDFDatetime( read.last_contact_time) api_client.last_clock = fleetspeak_utils.TSToRDFDatetime(read.last_clock)
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)