def _set_port_sequestered(self, mac): """Set port to sequester vlan""" operational_behavior = (self._static_device_behaviors.get(mac) or self._dynamic_device_behaviors.get(mac)) if self._device_state_reporter: assert operational_behavior, f'No operational device behavior available for {mac}' operational_vlan = self._get_vlan_from_segment( operational_behavior.segment) assert operational_vlan, f'No operational vlan available for device {mac}' self._device_state_reporter.process_port_assign( mac, operational_vlan) device_behavior = DeviceBehavior( segment=self._sequester_segment, assigned_segment=operational_behavior.segment) self._process_device_behavior(mac, device_behavior, static=False) self._update_device_state_varz(mac, DVAState.sequestered) if self._sequester_timeout: def handler(): self._handle_sequestering_timeout(mac.lower()) timeout = datetime.now() + timedelta( seconds=self._sequester_timeout) self._logger.info('Setting device %s sequester timeout at %s', mac, timeout) self._sequester_timer[mac.lower()] = threading.Timer( self._sequester_timeout, handler) self._sequester_timer[mac.lower()].start()
def process_device_behavior(self, eth_src, behavior, static=False): """Process device behavior""" eth_src = eth_src.lower() device_type = STATIC_DEVICE if static else DYNAMIC_DEVICE with self._lock: if behavior.segment: behavior_map = self._device_behaviors.setdefault(eth_src, {}) behavior_map[DEVICE_TYPE] = device_type device_behavior = behavior_map.setdefault( DEVICE_BEHAVIOR, DeviceBehavior()) device_behavior.CopyFrom(behavior) self._logger.info( 'Received %s behavior: %s, %s (assigned: %s), %s', device_type, eth_src, device_behavior.segment, device_behavior.assigned_segment, device_behavior.role) else: removed = self._device_behaviors.pop(eth_src, None) if removed: removed_behavior = removed[DEVICE_BEHAVIOR] self._logger.info('Removed %s behavior: %s, %s, %s', device_type, eth_src, removed_behavior.segment, removed_behavior.role) self.flush_behavioral_config()
def _set_port_sequestered(self, mac): """Set port to sequester vlan""" if not self._process_device_behavior: return device_behavior = DeviceBehavior(segment=self._testing_segment) self._process_device_behavior(mac, device_behavior, static=False) self._update_device_state_varz(mac, DVAState.sequestered)
def handle_auth_result(self, mac, access, segment, role): """Method passed as callback to authenticator to forward auth results""" self._faucet_collector.update_radius_result(mac, access, segment, role) with self._lock: if self._should_ignore_auth_result: LOGGER.warning('Ingoring authentication result for device %s', mac) else: device_behavior = DeviceBehavior(segment=segment, role=role) self._port_state_manager.handle_device_behavior(mac, device_behavior)
def _handle_auth_result(self, mac, access, segment, role): self._faucet_collector.update_radius_result(mac, access, segment, role) with self._states_lock: if self._should_ignore_auth_result: self._logger.warning( 'Ingoring authentication result for device %s', mac) else: device_behavior = DeviceBehavior(segment=segment, role=role) self._port_state_manager.handle_device_behavior( mac, device_behavior)
def _unauthenticate_devices(self, unauthenticated_devices, expected_device_behaviors): for mac in unauthenticated_devices: self._port_state_manager.handle_device_behavior(mac, DeviceBehavior()) expected_states = { '00:0Y:00:00:00:02': self.UNAUTHENTICATED, '00:0Z:00:00:00:03': self.INFRACTED, '00:0A:00:00:00:04': self.UNAUTHENTICATED } self._verify_ports_states(expected_states) expected_device_behaviors.extend([('00:0A:00:00:00:04', '', False)]) self._verify_received_device_behaviors(expected_device_behaviors)
def _handle_unauthenticated_device(self, mac, static): """Handle an unauthenticated device""" with self._lock: try: device_behaviors = ( self._static_device_behaviors if static else self._dynamic_device_behaviors) device_behaviors.pop(mac) if static or mac not in self._static_device_behaviors: self._state_machines.pop(mac) self._process_device_behavior(mac, DeviceBehavior(), static=static) except KeyError as error: LOGGER.warning('MAC %s does not exist: %s', mac, error)
def _handle_authenticated_device(self, mac, device_behavior, static): """Initialize or update the state machine for an authenticated device""" with self._lock: device_behaviors = (self._static_device_behaviors if static else self._dynamic_device_behaviors) device_behaviors.setdefault( mac, DeviceBehavior()).CopyFrom(device_behavior) auto_sequester = self._auto_sequester.get( mac, self._default_auto_sequestering) sequester_enabled = auto_sequester == PortBehavior.AutoSequestering.enabled if not self._sequester_segment or not sequester_enabled: port_behavior = PortBehavior.cleared else: port_behavior = PortBehavior.sequestered if mac in self._state_machines: self._state_machines[mac].handle_port_behavior(port_behavior)
def _handle_authenticated_device(self, mac, device_behavior, static): """Initialize or update the state machine for an authenticated device""" with self._lock: device_behaviors = ( self._static_device_behaviors if static else self._dynamic_device_behaviors) device_behaviors.setdefault(mac, DeviceBehavior()).CopyFrom(device_behavior) static_port_behavior = self._static_port_behaviors.get(mac) if not self._testing_segment or static_port_behavior == PortBehavior.cleared: port_behavior = PortBehavior.cleared else: port_behavior = PortBehavior.sequestered new_state_machine = PortStateMachine( mac, PortStateMachine.AUTHENTICATED, self._set_port_sequestered, self._set_port_operational) state_machine = self._state_machines.setdefault(mac, new_state_machine) state_machine.handle_port_behavior(port_behavior)
def _handle_authenticated_device(self, mac, device_behavior, static): """Initialize or update the state machine for an authenticated device""" if not self._process_device_behavior: return with self._lock: device_behaviors = (self._static_device_behaviors if static else self._dynamic_device_behaviors) device_behaviors.setdefault( mac, DeviceBehavior()).CopyFrom(device_behavior) static_port_behavior = self._static_port_behaviors.get(mac) if not self._testing_segment or static_port_behavior == PortBehavior.cleared: port_behavior = PortBehavior.cleared else: port_behavior = PortBehavior.sequestered if mac in self._state_machines: self._state_machines[mac].handle_port_behavior(port_behavior)
def _handle_deauthenticated_device(self, mac, static): """Handle an deauthenticated device""" with self._lock: device_behaviors = (self._static_device_behaviors if static else self._dynamic_device_behaviors) if mac in device_behaviors: device_behaviors.pop(mac) else: self._logger.warning('%s behavior does not exist for %s', 'static' if static else 'dynamic', mac) # ignore dynamic behavior for device that has static behavior defined if not static and mac in self._static_device_behaviors: return if mac in self._state_machines: port_behavior = PortBehavior.deauthenticated self._state_machines[mac].handle_port_behavior(port_behavior) self._process_device_behavior(mac, DeviceBehavior(), static=static)
def _set_port_sequestered(self, mac): """Set port to sequester vlan""" operational_behavior = (self._static_device_behaviors.get(mac) or self._dynamic_device_behaviors.get(mac)) device_behavior = DeviceBehavior( segment=self._sequester_segment, assigned_segment=operational_behavior.segment) self._process_device_behavior(mac, device_behavior, static=False) self._update_device_state_varz(mac, DVAState.sequestered) if self._sequester_timeout > 0: def handler(): self._handle_sequestering_timeout(mac.lower()) timeout = datetime.now() + timedelta( seconds=self._sequester_timeout) self._logger.info('Setting device %s sequester timeout at %s', mac, timeout) self._sequester_timer[mac.lower()] = threading.Timer( self._sequester_timeout, handler) self._sequester_timer[mac.lower()].start()
def handle_auth_result(src_mac, access, segment, role): device_behavior = DeviceBehavior(segment=segment, role=role) self._forchestrator._port_state_manager.handle_device_behavior( src_mac, device_behavior)
def _handle_infracted_state(self, mac): static = mac in self._static_device_behaviors self._process_device_behavior(mac, DeviceBehavior(), static=static) self._update_device_state_varz(mac, DVAState.infracted)
def test_ports_states(self): """Test the port states with different signals""" static_device_behaviors = { '00:0X:00:00:00:01': {'segment': 'SEG_A', 'port_behavior': 'cleared'}, '00:0Y:00:00:00:02': {'port_behavior': 'cleared'} } authentication_results = { '00:0X:00:00:00:01': {'segment': 'SEG_X'}, '00:0Z:00:00:00:03': {'segment': 'SEG_C'}, '00:0A:00:00:00:04': {'segment': 'SEG_D'}, '00:0B:00:00:00:05': {'segment': 'SEG_E'} } testing_results = [ ('00:0X:00:00:00:01', 'failed'), ('00:0Y:00:00:00:02', 'passed'), ('00:0Z:00:00:00:03', 'failed'), ('00:0A:00:00:00:04', 'passed') ] unauthenticated_devices = ['00:0X:00:00:00:01', '00:0A:00:00:00:04'] expired_device_vlans = [ ('00:0B:00:00:00:05', 600), ('00:0B:00:00:00:05', 500), ] # load static device behaviors for mac, device_behavior_map in static_device_behaviors.items(): self._port_state_manager.handle_static_device_behavior( mac, dict_proto(device_behavior_map, DeviceBehavior)) # devices are authenticated for mac, device_behavior_map in authentication_results.items(): self._port_state_manager.handle_device_behavior( mac, dict_proto(device_behavior_map, DeviceBehavior)) expected_states = { '00:0X:00:00:00:01': self.OPERATIONAL, '00:0Z:00:00:00:03': self.SEQUESTERED, '00:0A:00:00:00:04': self.SEQUESTERED, '00:0B:00:00:00:05': self.SEQUESTERED } self._verify_ports_states(expected_states) expected_received_device_behaviors = [ ('00:0X:00:00:00:01', 'SEG_A', True), ('00:0X:00:00:00:01', 'SEG_A', True), ('00:0Z:00:00:00:03', 'TESTING', False), ('00:0A:00:00:00:04', 'TESTING', False), ('00:0B:00:00:00:05', 'TESTING', False) ] self._verify_received_device_behaviors(expected_received_device_behaviors) # received testing results for devices for testing_result in testing_results: self._port_state_manager.handle_testing_result( self._encapsulate_testing_result(*testing_result)) expected_states = { '00:0X:00:00:00:01': self.OPERATIONAL, '00:0Z:00:00:00:03': self.INFRACTED, '00:0A:00:00:00:04': self.OPERATIONAL, '00:0B:00:00:00:05': self.SEQUESTERED } self._verify_ports_states(expected_states) expected_received_device_behaviors.extend([('00:0A:00:00:00:04', 'SEG_D', False)]) self._verify_received_device_behaviors(expected_received_device_behaviors) # devices are unauthenticated for mac in unauthenticated_devices: self._port_state_manager.handle_device_behavior(mac, DeviceBehavior()) expected_states = { '00:0X:00:00:00:01': self.OPERATIONAL, '00:0Z:00:00:00:03': self.INFRACTED, '00:0B:00:00:00:05': self.SEQUESTERED } self._verify_ports_states(expected_states) expected_received_device_behaviors.extend([('00:0A:00:00:00:04', '', False)]) self._verify_received_device_behaviors(expected_received_device_behaviors) # devices are expired for expired_device_vlan in expired_device_vlans: mac = expired_device_vlan[0] expired_vlan = expired_device_vlan[1] self._port_state_manager.handle_device_placement( mac, DevicePlacement(switch='switch', port=1), False, expired_vlan) expired_received_device_placements = [('00:0B:00:00:00:05', False, False)] self._verify_received_device_placements(expired_received_device_placements)
def _set_port_sequestered(self, mac): """Set port to sequester vlan""" device_behavior = DeviceBehavior(segment=self._testing_segment) self._process_device_behavior(mac, device_behavior, static=False)