def process_loop(self): # _logger.debug('{0} processing loop called'.format(self.get_name())) if self._startup: self._startup = False task = QueueTask( TASK_FIREWALL_INSERT_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=self.create_logging_rules()) self.send_parent_task(task) if self._log_handle: # See if we have iptables log event data data = self._log_handle.readline() while data: if self.node_info.platform == 'linux' and 'kernel: SDC' in data: # See tests/iptables_logging_test.py for example log events. ev = IPLogEvent(data) for mod_name in self._subscribers: # _logger.debug('{0}: sending {1} log event.'.format(self.get_name(), mod_name)) task = QueueTask(TASK_LOG_EVENT, src_module=self.get_name(), dest_module=mod_name, data=ev) self.send_parent_task(task) data = self._log_handle.readline()
def check_service(self, name): """ Check the service for rules and add them to the firewall. :param name: Service discovery module name """ module_name, class_name = name.rsplit('.', 1) _logger.debug('{0}: Loading service object {1}'.format(self.get_name(), class_name)) module = import_by_str(name) cls = module(config=self.config) disabled = getattr(self, cls.get_config_property_name()) if type(disabled) is str: # Python 2.7 returns string type from getattr(), Python 3.4 returns bool. disabled = ast.literal_eval(disabled) # _logger.debug('Property: {0}: Value: {1}'.format(cls.get_config_property_name(), disabled)) # See if this discovery service has been disabled. Name value must match one of our property names. if disabled: _logger.debug('{0}: {1} service disabled by config.'.format(self.get_name(), class_name)) return 0 rules, slot = cls.discover() if rules: # See if we already have saved rules for this slot id if slot in self._mss_slots: if self.rules_have_changed(self._mss_slots[slot], rules): _logger.debug('{0}: {1}: Rules have changed, notifying firewall manager.'.format( self.get_name(), class_name)) # Notify the firewall module to delete the old rules. task = QueueTask(TASK_FIREWALL_DELETE_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=self._mss_slots[slot]) self.send_parent_task(task) else: return 0 # Save rules so we can check against them next time. self._mss_slots[slot] = rules # Notify the firewall module to reload the rules. task = QueueTask(TASK_FIREWALL_INSERT_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=rules) self.send_parent_task(task) else: _logger.info('{0}: {1}: service did not return any rules.'.format( self.get_name(), class_name)) return 0 return len(rules)
def process_loop(self): # TODO: Things to do occasionally; Hash rule files and compare to hashes saved on server to look for tampering. #if self.t_seconds > 45: # print "debug 1 message" if self.t_seconds > 120: print "debug 2 message" task = QueueTask( TASK_FIREWALL_RELOAD_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name()) self.send_parent_task(task) pass
def process_loop(self): # Print a debug message every 45 seconds if self.timed_event('_t_debug_message', 45): _logger.debug('{0} 45 second debug message'.format( self.get_name())) # Tell the firewall module to reload the firewall rules every 2 minutes. if self.timed_event('_t_reload_task', 120): # Notify the firewall module to reload the rules. task = QueueTask( TASK_FIREWALL_RELOAD_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name()) self.send_parent_task(task)
def add_url_rule_to_firewall(self, rules): """ Add rules allowing access immediately to the firewall. :param rules: rules list """ if not rules: return # Notify the firewall module to reload the rules. task = QueueTask( TASK_FIREWALL_INSERT_RULES, src_module=self._parent.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=rules) self._parent.send_parent_task(task) time.sleep( 2) # Give the firewall manager time to add the rule to the kernel
def allow_remote_config_access(self): rules = list() if self._uri.scheme == 'http': rules.append(self.get_http_rule_by_hostname()) elif self._uri.scheme == 'https': rules.append(self.get_https_rule_by_hostname()) elif self._uri.scheme == 'ftp': rules.append(self.get_ftp_rule_by_hostname()) # Notify the firewall module to reload the rules. task = QueueTask( TASK_FIREWALL_INSERT_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=rules) self.send_parent_task(task)
def _add_server_access_rule(self): """ Add a management server connection rule so we can connect :return: """ rule = create_iptables_egress_ingress_rule( self._server, self._port, 'tcp', Slots.silentdune_server, transport=ipt.TRANSPORT_AUTO) # Notify the firewall module to reload the rules. task = QueueTask( TASK_FIREWALL_INSERT_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=rule) self.send_parent_task(task)
def update_node_firewall_rules_from_server(self): """ Retrieve the node bundle rules from the server and send them to the Firewall module. :return: """ # TODO: Save current bundle machine subsets and then look for any orphaned sets and remove them # from the firewall. if self._bundle_machine_subsets: # Until the orphan rule check is in place, just tell the firewall to delete all rules. task = QueueTask( TASK_FIREWALL_DELETE_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=self._bundle_machine_subsets) self.send_parent_task(task) # Get updated bundle information. self._node_bundle, status_code = self._sds_conn.get_node_bundle_by_node_id( self._node.id) self._bundle, status_code = self._sds_conn.get_bundle_by_id( self._node_bundle.bundle) if not self._download_bundleset(): if self._sds_conn.request_error: _logger.error( '{0}: request to server failed, changing state to not connected' .format(self.get_name())) self._connected = False return False if self._bundle_machine_subsets and len( self._bundle_machine_subsets) > 0: rules = self.flatten_rules(self._bundle_machine_subsets) # Check to see if we are in lockdown mode. If so filter out all if self._locked: data = list() for i in rules: if i.slot <= self._globals.lockdown_slot_level or i.slot >= self._globals.rejection_slot_level: data.append(i) else: data = rules # Notify the firewall module to reload the rules. task = QueueTask( TASK_FIREWALL_INSERT_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=data) self.send_parent_task(task) # Notify the firewall module to reload the rules. # task = QueueTask(TASK_FIREWALL_RELOAD_RULES, # src_module=self.get_name(), # dest_module=SilentDuneClientFirewallModule().get_name()) # self.send_parent_task(task) # Reset the node rule bundle check timer self._t_next_check = self.t_seconds else: _logger.error( '{0}: No rules downloaded from server, unable to update firewall module.' .format(self.get_name())) return False return True
def process_loop(self): if self._startup: self._startup = False self._add_server_access_rule() time.sleep( 3 ) # Give the firewall time to add the rules before we attempt to connect self.service_connect_to_server() if self._sds_conn.status == ConnStatus.not_registered: _logger.error( '{0} this node is not registered, unable to download rules' .format(self.get_name())) # If we are not registered, just return if self._sds_conn and self._sds_conn.status == ConnStatus.not_registered: return # If we are not connected to the server, try reconnecting every 60 seconds. if not self._connected: if self.timed_event('_t_connection_retry', 60): self._t_connection_retry = self.t_seconds self.service_connect_to_server() if self._connected: # Check to see if the connection to the server has just started. if self._connection_start: # Get the global preferences self.get_global_preferences() # Notify the server we are active now. self._node.active = True self.update_server_node_info(active=True) # Set our lock down mode value. self.set_lockdown_mode() # Update our firewall with rules from the server. self.update_node_firewall_rules_from_server() self._connection_start = False # Subscribe to log events task = QueueTask( TASK_SUBSCRIBE_LOG_EVENTS, src_module=self.get_name(), dest_module=SilentDuneClientLoggingModule().get_name()) self.send_parent_task(task) _logger.debug('Next server check in {0} seconds.'.format( self._t_check_interval)) # Check to see if the node rule bundle information has changed. if self.timed_event('_t_next_check', self._t_check_interval): _logger.debug('Next server check in {0} seconds.'.format( self._t_check_interval)) self._node, status_code = self._sds_conn.get_node_by_machine_id( self.node_info.machine_id) # Check to see if we need to update our firewall rules bundle. if self._node.sync: _logger.info( '{0}: Found signal to update the firewall rules bundle.' .format(self.get_name())) self.set_lockdown_mode() self.update_node_firewall_rules_from_server() # Update our information with the server. self.update_server_node_info(sync=False)
def apply_remote_config(self): rules = list() try: if self._uri.scheme == 'file': with open(self._uri.path) as handle: rq = handle.read().decode('utf-8') else: rq = requests.get(self._remote_config_url, verify=False) if rq.status_code != 200: _logger.error( '{0}: unable to retrieve remote configuration'.format( self.get_name())) return False except: _logger.error('{0}: unable to retrieve remote config rules'.format( self.get_name())) return False try: if self._uri.scheme == 'file': rc = RemoteConfig(json.loads(rq)) rule_text = rq else: rc = RemoteConfig(rq.json()) rule_text = rq.text except: _logger.error('{0}: parsing configuration json failed'.format( self.get_name())) return False # See if we should check the hash value against a DNS TXT lookup hash value if self._remote_config_dns_name: if not rc.hash_method or rc.hash_method not in [ 'sha1', 'sha256', 'sha512' ]: _logger.error( '{0}: unsupported hashing algorithm in remote config ({1})' .format(self.get_name(), rc.hash_method)) return False if rc.hash_method == 'sha1': hash_value = hashlib.sha1(rule_text).hexdigest() elif rc.hash_method == 'sha256': hash_value = hashlib.sha256(rule_text).hexdigest() elif rc.hash_method == 'sha512': hash_value = hashlib.sha512(rule_text).hexdigest() if self.get_remote_dns_hash() != hash_value: _logger.error( '{0}: remote DNS TXT hash value does not match calculated hash' .format(self.get_name())) return False _logger.debug('{0}: deleting rules for slot {1}'.format( self.get_name(), self._slot_config_apply)) task = QueueTask( TASK_FIREWALL_DELETE_SLOT, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=self._slot_config_apply) self.send_parent_task(task) for rule in rc.rules: try: # See if we need to try and resolve the host name if not is_valid_ipv6_address( rule.host) and not is_valid_ipv6_address(rule.host): addrs = self.get_ip_from_hostname(rule.host, rule.port) if not addrs: _logger.error( '{0}: error: unable to resolve rule host {1}'. format(self.get_name(), rule.host)) return False for addr in addrs: _logger.debug( '{0}: adding rules slot: {1}, ip address: {2}, port: {3}, protocol: {4}' .format(self.get_name(), self._slot_config_apply, addr, rule.port, rule.protocol)) rules.append( create_iptables_remote_config( addr, rule.mask, rule.port, rule.protocol, self._slot_config_apply, rule.uid, rule.gid, transport=ipt.TRANSPORT_AUTO)) else: _logger.debug( '{0}: adding rules slot: {1}, ip address: {2}, port: {3}, protocol: {4}' .format(self.get_name(), self._slot_config_apply, rule.host, rule.port, rule.protocol)) rules.append( create_iptables_remote_config( rule.host, rule.mask, rule.port, rule.protocol, self._slot_config_apply, rule.uid, rule.gid, transport=ipt.TRANSPORT_AUTO)) except: _logger.error('{0}: parsing remote config rule failed.'.format( self.get_name())) return False if rules: task = QueueTask( TASK_FIREWALL_INSERT_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=rules) self.send_parent_task(task) return True
def check_service(self, name): """ Check the service for rules and add them to the firewall. :param name: Service discovery module name """ module_name, class_name = name.rsplit('.', 1) _logger.debug('{0}: Loading auto discover object {1}'.format( self.get_name(), class_name)) module = import_by_str(name) cls = module(config=self.config) disabled = getattr(self, cls.get_config_property_name()) if type( disabled ) is str: # Python 2.7 returns string type from getattr(), Python 3.4 returns bool. disabled = ast.literal_eval(disabled) # _logger.debug('Property: {0}: Value: {1}'.format(cls.get_config_property_name(), disabled)) # See if this discovery service has been disabled. Name value must match one of our property names. if disabled: _logger.debug( '{0}: {1} discovery service disabled by config.'.format( self.get_name(), class_name)) return 0 rules, slot = cls.discover(self) rules = self.flatten_rules(rules) if rules: # Notify the firewall module to delete the old rules. task = QueueTask( TASK_FIREWALL_DELETE_SLOT, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=slot) self.send_parent_task(task) # Notify the firewall module to load the new rules. task = QueueTask( TASK_FIREWALL_INSERT_RULES, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name(), data=rules) self.send_parent_task(task) time.sleep(1) # Let the firewall apply the rule changes else: _logger.info( '{0}: {1}: discovery service did not return any rules.'.format( self.get_name(), class_name)) _logger.debug('SLOTS: {0}: {1}'.format(Slots.ntp, slot)) # If there were no rules discovered for NTP, open up access to all NTP servers. # In self._t_ntp_check_interval seconds we will check to see if any NTP servers are active. if slot == Slots.ntp and is_service_running('ntpd'): self._all_ntp_access_enabled = True _logger.debug( '{0}: Asking Firewall Module to enable generic NTP access.' .format(self.get_name())) task = QueueTask( TASK_FIREWALL_ALLOW_ALL_NTP_ACCESS, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name()) self.send_parent_task(task) return 0 return len(rules)
def process_loop(self): if self._startup: # Try resolving example.org, if we get an error try enabling generic all DNS access. # This block may be called multiple times during startup to make sure DNS is working. try: resolve_hostname('example.org', ipt.TRANSPORT_AUTO) except socket.gaierror: # If we have reached here, we have no DNS access at all. if self._all_dns_access_enabled: # raise OSError('No external DNS access available. Unable to complete auto discovery.') _logger.error( '{0}: No external DNS available. Waiting 5 minutes to try again.' .format(self.get_name())) time.sleep(300) return _logger.debug( '{0}: Asking Firewall Module to enable generic DNS access.' .format(self.get_name())) # Tell the firewall manager to enable generic all DNS access. self._all_dns_access_enabled = True task = QueueTask( TASK_FIREWALL_ALLOW_ALL_DNS_ACCESS, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name()) self.send_parent_task(task) return self._startup = False self.discover_services() # Tell the firewall manager to remove generic all DNS access rules. if self._all_dns_access_enabled: self._all_dns_access_enabled = False _logger.debug( '{0}: Asking Firewall Module to disable generic DNS access.' .format(self.get_name())) task = QueueTask( TASK_FIREWALL_DISABLE_ALL_DNS_ACCESS, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name()) self.send_parent_task(task) # After the check interval has passed, check services again. if self.timed_event('_t_all_service_check', self._t_all_check_interval): self.discover_services() # See we need to remove the all access ntp rules. if self._all_ntp_access_enabled and self.timed_event( '_t_ntp_service_check', self._t_ntp_check_interval): rule_count = self.check_service(NTP_DISCOVERY_SERVICE) # If we found NTP rules, tell the firewall manager to remove generic all NTP access rules. if self._all_ntp_access_enabled and rule_count > 0: self._all_ntp_access_enabled = False _logger.debug( '{0}: Asking Firewall Module to disable generic NTP access.' .format(self.get_name())) task = QueueTask( TASK_FIREWALL_DISABLE_ALL_NTP_ACCESS, src_module=self.get_name(), dest_module=SilentDuneClientFirewallModule().get_name()) self.send_parent_task(task)