def test_subscriber_policy(self): """ Classify DPI flow, verify internal packet is generated Assert: snapshots math """ imsi = 'IMSI010000000088888' ue_mac = '5e:cc:cc:b1:49:4b' self.ue_mac_controller.add_ue_mac_flow(imsi, ue_mac) flow_match = FlowMatch( ip_proto=FlowMatch.IPPROTO_TCP, ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.1'), ip_src=convert_ipv4_str_to_ip_proto('1.2.3.0'), tcp_dst=80, tcp_src=51115, direction=FlowMatch.UPLINK) self.dpi_controller.add_classify_flow( flow_match, FlowRequest.FLOW_FINAL_CLASSIFICATION, 'base.ip.http.facebook', 'tbd') snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, include_stats=False) with snapshot_verifier: pass
def test_deny_rule_install(self): """ Adds a policy to a subscriber. Verifies that flows are properly installed in enforcement and enforcement stats. Assert: Policy classification flows installed in enforcement Policy match flows installed in enforcement_stats """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller) imsi = 'IMSI001010000000014' sub_ip = '192.16.15.7' num_pkt_unmatched = 4096 flow_list = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('1.1.0.0/24'), direction=FlowMatch.UPLINK), action=FlowDescription.DENY) ] policy = PolicyRule(id='rule1', priority=3, flow_list=flow_list) self.service_manager.session_rule_version_mapper.update_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1') """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller).add_dynamic_rule(policy) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packet = IPPacketBuilder() \ .set_ip_layer('45.10.0.0/20', sub_ip) \ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00") \ .build() # =========================== Verification =========================== # Verifies that 1 flow is installed in enforcement and 2 flows are # installed in enforcement stats, one for uplink and one for downlink. snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with isolator, sub_context, snapshot_verifier: pkt_sender.send(packet) enf_stat_name = imsi + '|' + self.DEFAULT_DROP_FLOW_NAME + '|' + sub_ip wait_for_enforcement_stats(self.enforcement_stats_controller, [enf_stat_name]) stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) self.assertEqual(stats[enf_stat_name].sid, imsi) self.assertEqual(stats[enf_stat_name].rule_id, self.DEFAULT_DROP_FLOW_NAME) self.assertEqual(stats[enf_stat_name].dropped_rx, 0) self.assertEqual(stats[enf_stat_name].dropped_tx, num_pkt_unmatched * len(packet))
def activate_flows(client, args): request = ActivateFlowsRequest( sid=SIDUtils.to_pb(args.imsi), ip_addr=args.ipv4, policies=[ VersionedPolicy( rule=PolicyRule( id=args.rule_id, priority=args.priority, hard_timeout=args.hard_timeout, flow_list=[ FlowDescription( match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto(args.ipv4_dst), direction=FlowMatch.UPLINK, ), ), FlowDescription( match=FlowMatch( ip_src=convert_ipv4_str_to_ip_proto(args.ipv4_dst), direction=FlowMatch.DOWNLINK, ), ), ], ), version=1, ), ], request_origin=RequestOriginType(type=RequestOriginType.GX), shard_id=args.shard_id, ) response = client.ActivateFlows(request) _print_rule_mod_results(response.policy_results)
def _ng_qer_update( self, request: SessionSet, pdr_entry: PDRRuleEntry, ) -> Tuple[List[RuleModResult], List[RuleModResult]]: enforcement_res = [] failed_policy_rules_results = [] session_version = request.session_version local_f_teid_ng = request.local_f_teid # PDR is deleted with ActiveRules or DelActive rules recieved if pdr_entry.pdr_state == PdrState.Value('REMOVE'): qos_enforce_rule = pdr_entry.del_qos_enforce_rule if qos_enforce_rule.ip_addr: ipv4 = convert_ipv4_str_to_ip_proto(qos_enforce_rule.ip_addr) self._ng_deactivate_qer_flows( ipv4, local_f_teid_ng, qos_enforce_rule, session_version, ) if qos_enforce_rule.ipv6_addr: ipv6 = convert_ipv6_bytes_to_ip_proto(qos_enforce_rule.ipv6_addr) self._ng_deactivate_qer_flows( ipv6, local_f_teid_ng, qos_enforce_rule, session_version, ) elif pdr_entry.pdr_state == PdrState.Value('IDLE'): qos_enforce_rule = pdr_entry.add_qos_enforce_rule if qos_enforce_rule.ip_addr: ipv4 = convert_ipv4_str_to_ip_proto(qos_enforce_rule.ip_addr) self._ng_inactivate_qer_flows(ipv4, qos_enforce_rule, session_version) if qos_enforce_rule.ipv6_addr: ipv6 = convert_ipv6_bytes_to_ip_proto(qos_enforce_rule.ipv6_addr) self._ng_inactivate_qer_flows(ipv6, qos_enforce_rule, session_version) # Install PDR rules elif pdr_entry.pdr_state == PdrState.Value('INSTALL'): qos_enforce_rule = pdr_entry.add_qos_enforce_rule if qos_enforce_rule.ip_addr: ipv4 = convert_ipv4_str_to_ip_proto(qos_enforce_rule.ip_addr) enforcement_res = \ self._ng_activate_qer_flow( ipv4, local_f_teid_ng, qos_enforce_rule, session_version, ) failed_policy_rules_results = \ _retrieve_failed_results(enforcement_res) if qos_enforce_rule.ipv6_addr: ipv6 = convert_ipv6_bytes_to_ip_proto(qos_enforce_rule.ipv6_addr) enforcement_res = \ self._ng_activate_qer_flow( ipv6, local_f_teid_ng, qos_enforce_rule, session_version, ) failed_policy_rules_results = \ _retrieve_failed_results(enforcement_res) return failed_policy_rules_results
def test_poll(self): """ Unit test to help verify stats polling using cookie and cookie_mask """ fake_controller_setup( self.enforcement_controller, self.enforcement_stats_controller, ) imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' flow_list = [ FlowDescription( match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/25'), direction=FlowMatch.UPLINK, ), action=FlowDescription.PERMIT, ), ] policy = VersionedPolicy( rule=PolicyRule(id='rule1', priority=3, flow_list=flow_list), version=1, ) self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1', 1, ) """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller, ).add_policy(policy) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with sub_context, snapshot_verifier: rule_map = self.enforcement_stats_controller.get_stats() if (rule_map.records[0].rule_id == self.DEFAULT_DROP_FLOW_NAME): rule_record = rule_map.records[1] else: rule_record = rule_map.records[0] self.assertEqual(rule_record.sid, imsi) self.assertEqual(rule_record.rule_id, "rule1") self.assertEqual(rule_record.bytes_tx, 0) self.assertEqual(rule_record.bytes_rx, 0) rule_map_cookie = self.enforcement_stats_controller.get_stats(1, 0) if (rule_map_cookie.records[0].rule_id == self.DEFAULT_DROP_FLOW_NAME): rule_record_cookie = rule_map_cookie.records[1] else: rule_record_cookie = rule_map_cookie.records[0] self.assertEqual(rule_record_cookie.sid, imsi) self.assertEqual(rule_record_cookie.rule_id, "rule1") self.assertEqual(rule_record_cookie.bytes_tx, 0) self.assertEqual(rule_record_cookie.bytes_rx, 0)
def test_subscriber_policy(self): """ Classify DPI flow, verify internal packet is generated Assert: snapshots math """ imsi = 'IMSI010000000088888' ue_mac = '5e:cc:cc:b1:49:4b' self.ue_mac_controller.add_ue_mac_flow(imsi, ue_mac) flow_match = FlowMatch( ip_proto=FlowMatch.IPPROTO_TCP, ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.1'), ip_src=convert_ipv4_str_to_ip_proto('1.2.3.0'), tcp_dst=80, tcp_src=51115, direction=FlowMatch.UPLINK, ) self.dpi_controller.add_classify_flow( flow_match, FlowRequest.FLOW_FINAL_CLASSIFICATION, 'base.ip.http.facebook', 'tbd', ) self.ipfix_controller.add_ue_sample_flow( imsi, "magma_is_awesome_msisdn", "00:11:22:33:44:55", "apn_name123456789", 145, ) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, include_stats=False, ) with snapshot_verifier: pass self.ipfix_controller.delete_ue_sample_flow(imsi) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, 'after_deletion', include_stats=False, ) with snapshot_verifier: pass
def CreateAddQERinPDR( qos_enforce_rule: QoSEnforceRuleEntry, ue_ip_addr: str, apn_ambr: AggregatedMaximumBitrate, ) -> ActivateFlowsRequest: if qos_enforce_rule.allow == 'YES': allow = FlowDescription.PERMIT else: allow = FlowDescription.DENY ip_dst = None ip_src = None if qos_enforce_rule.ipv4_dst: ip_dst = convert_ipv4_str_to_ip_proto(qos_enforce_rule.ipv4_dst) ip_src = convert_ipv4_str_to_ip_proto(qos_enforce_rule.ipv4_dst) if qos_enforce_rule.direction == FlowMatch.UPLINK: flow_list = [ FlowDescription( match=FlowMatch( ip_dst=ip_dst, direction=qos_enforce_rule.direction, ), action=allow, ), ] else: flow_list = [ FlowDescription( match=FlowMatch( ip_src=ip_src, direction=qos_enforce_rule.direction, ), action=allow, ), ] qos_enforce_rule = ActivateFlowsRequest( sid=SIDUtils.to_pb(qos_enforce_rule.imsi), ip_addr=ue_ip_addr, policies=[ VersionedPolicy( rule=PolicyRule( id=qos_enforce_rule.rule_id, priority=qos_enforce_rule.priority, hard_timeout=qos_enforce_rule.hard_timeout, flow_list=flow_list, ), version=1, ), ], request_origin=RequestOriginType(type=RequestOriginType.N4), apn_ambr=apn_ambr, ) return qos_enforce_rule
def test_rule_install(self): """ Adds a policy to a subscriber. Verifies that flows are properly installed in enforcement and enforcement stats. Assert: Policy classification flows installed in enforcement Policy match flows installed in enforcement_stats """ fake_controller_setup( self.enforcement_controller, self.enforcement_stats_controller, ) imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' flow_list = [ FlowDescription( match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/25'), direction=FlowMatch.UPLINK, ), action=FlowDescription.PERMIT, ), ] policy = VersionedPolicy( rule=PolicyRule(id='rule1', priority=3, flow_list=flow_list), version=1, ) self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1', 1, ) """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller, ).add_policy(policy) # =========================== Verification =========================== # Verifies that 1 flow is installed in enforcement and 2 flows are # installed in enforcement stats, one for uplink and one for downlink. snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with sub_context, snapshot_verifier: pass
def test_session_rule_version_mapper(self): rule_ids = ['rule1', 'rule2'] imsi = 'IMSI12345' ip_addr = '1.2.3.4' self._session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(ip_addr), rule_ids[0], 1) self.assertEqual( self._session_rule_version_mapper.get_version( imsi, convert_ipv4_str_to_ip_proto(ip_addr), rule_ids[0]), 1) self._session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(ip_addr), rule_ids[1], 1) self.assertEqual( self._session_rule_version_mapper.get_version( imsi, convert_ipv4_str_to_ip_proto(ip_addr), rule_ids[1]), 1) self._session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(ip_addr), rule_ids[0], 2) self.assertEqual( self._session_rule_version_mapper.get_version( imsi, convert_ipv4_str_to_ip_proto(ip_addr), rule_ids[0]), 2) # Test updating version for all rules of a subscriber self._session_rule_version_mapper.update_all_ue_versions( imsi, convert_ipv4_str_to_ip_proto(ip_addr)) self.assertEqual( self._session_rule_version_mapper.get_version( imsi, convert_ipv4_str_to_ip_proto(ip_addr), rule_ids[0]), 3) self.assertEqual( self._session_rule_version_mapper.get_version( imsi, convert_ipv4_str_to_ip_proto(ip_addr), rule_ids[1]), 2)
def test_enforcemnet_rules(self): """ Add QOS policy to enforcement table into OVS. """ fake_controller_setup(self.enforcement_controller) imsi = 'IMSI001010000000013' sub_ip = '192.168.128.30' flow_list1 = [ FlowDescription( match=FlowMatch(direction=FlowMatch.UPLINK, ), action=FlowDescription.PERMIT, ), FlowDescription( match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto("192.168.0.0/24"), direction=FlowMatch.DOWNLINK, ), action=FlowDescription.PERMIT, ), ] self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), "rule1", 1, ) self.enforcement_controller.activate_rules( imsi, None, 0, convert_ipv4_str_to_ip_proto(sub_ip), None, policies=[ VersionedPolicy( rule=PolicyRule(id='rule1', priority=65530, flow_list=flow_list1), version=1, ), ], shard_id=0, local_f_teid_ng=100, ) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with snapshot_verifier: pass
def test_add_app_rules(self): """ Test DPI classifier flows are properly added Assert: 1 FLOW_CREATED -> no rule added as its not classified yet 1 App not tracked -> no rule installed(`notanAPP`) 3 App types are matched on: facebook other google_docs other viber audio """ flow_match1 = FlowMatch( ip_proto=FlowMatch.IPPROTO_TCP, ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.8'), ip_src=convert_ipv4_str_to_ip_proto('1.2.3.4'), tcp_dst=80, tcp_src=51115, direction=FlowMatch.UPLINK ) flow_match2 = FlowMatch( ip_proto=FlowMatch.IPPROTO_TCP, ip_dst=convert_ipv4_str_to_ip_proto('1.10.0.1'), ip_src=convert_ipv4_str_to_ip_proto('6.2.3.1'), tcp_dst=111, tcp_src=222, direction=FlowMatch.UPLINK ) flow_match3 = FlowMatch( ip_proto=FlowMatch.IPPROTO_UDP, ip_dst=convert_ipv4_str_to_ip_proto('22.2.2.24'), ip_src=convert_ipv4_str_to_ip_proto('15.22.32.2'), udp_src=111, udp_dst=222, direction=FlowMatch.UPLINK ) flow_match_for_no_proto = FlowMatch( ip_proto=FlowMatch.IPPROTO_UDP, ip_dst=convert_ipv4_str_to_ip_proto('1.1.1.1') ) flow_match_not_added = FlowMatch( ip_proto=FlowMatch.IPPROTO_UDP, ip_src=convert_ipv4_str_to_ip_proto('22.22.22.22') ) self.dpi_controller.add_classify_flow( flow_match_not_added, FlowRequest.FLOW_CREATED, 'nickproto', 'bestproto') self.dpi_controller.add_classify_flow( flow_match_for_no_proto, FlowRequest.FLOW_PARTIAL_CLASSIFICATION, 'notanAPP', 'null') self.dpi_controller.add_classify_flow( flow_match1, FlowRequest.FLOW_PARTIAL_CLASSIFICATION, 'base.ip.http.facebook', 'NotReal') self.dpi_controller.add_classify_flow( flow_match2, FlowRequest.FLOW_PARTIAL_CLASSIFICATION, 'base.ip.https.google_gen.google_docs', 'MAGMA',) self.dpi_controller.add_classify_flow( flow_match3, FlowRequest.FLOW_PARTIAL_CLASSIFICATION, 'base.ip.udp.viber', 'AudioTransfer Receiving',) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with snapshot_verifier: pass
def _get_ue_specific_flow_msgs(self, requests: List[ActivateFlowsRequest]): msg_list = [] for add_flow_req in requests: imsi = add_flow_req.sid.id ip_addr = convert_ipv4_str_to_ip_proto(add_flow_req.ip_addr) apn_ambr = add_flow_req.apn_ambr policies = add_flow_req.policies msisdn = add_flow_req.msisdn uplink_tunnel = add_flow_req.uplink_tunnel msgs = self._get_default_flow_msgs_for_subscriber(imsi, ip_addr) if msgs: msg_list.extend(msgs) for policy in policies: # As the versions are managed by sessiond, save state here self._service_manager.session_rule_version_mapper.save_version( imsi, ip_addr, policy.rule.id, policy.version) try: if policy.rule.redirect.support == policy.rule.redirect.ENABLED: continue flow_adds = self._get_rule_match_flow_msgs(imsi, msisdn, uplink_tunnel, ip_addr, apn_ambr, policy.rule, policy.version) msg_list.extend(flow_adds) except FlowMatchError: self.logger.error("Failed to verify rule_id: %s", policy.rule.id) return {self.tbl_num: msg_list}
def _set_he_target_urls(self, ue_addr: str, rule_id: str, urls: List[str], imsi: str, msisdn: bytes) -> bool: if msisdn: msisdn_str = msisdn.decode("utf-8") else: msisdn_str = None ip_addr = convert_ipv4_str_to_ip_proto(ue_addr) return activate_he_urls_for_ue(ip_addr, rule_id, urls, imsi, msisdn_str)
def _get_ue_specific_flow_msgs(self, requests: List[ActivateFlowsRequest]): msg_list = [] for add_flow_req in requests: imsi = add_flow_req.sid.id apn_ambr = add_flow_req.apn_ambr policies = add_flow_req.policies msisdn = add_flow_req.msisdn uplink_tunnel = add_flow_req.uplink_tunnel if self._setup_type == 'CWF' or add_flow_req.ip_addr: ipv4 = convert_ipv4_str_to_ip_proto(add_flow_req.ip_addr) msgs = self._get_default_flow_msgs_for_subscriber(imsi, ipv4) if msgs: msg_list.extend(msgs) for policy in policies: msg_list.extend(self._get_policy_flows(imsi, msisdn, uplink_tunnel, ipv4, apn_ambr, policy)) if add_flow_req.ipv6_addr: ipv6 = convert_ipv6_bytes_to_ip_proto(add_flow_req.ipv6_addr) msgs = self._get_default_flow_msgs_for_subscriber(imsi, ipv6) if msgs: msg_list.extend(msgs) for policy in policies: msg_list.extend(self._get_policy_flows(imsi, msisdn, uplink_tunnel, ipv6, apn_ambr, policy)) return {self.tbl_num: msg_list}
def _get_ue_specific_flow_msgs(self, requests: List[ActivateFlowsRequest]): msg_list = [] for add_flow_req in requests: imsi = add_flow_req.sid.id ip_addr = convert_ipv4_str_to_ip_proto(add_flow_req.ip_addr) apn_ambr = add_flow_req.apn_ambr dynamic_rules = add_flow_req.dynamic_rules msisdn = add_flow_req.msisdn uplink_tunnel = add_flow_req.uplink_tunnel msgs = self._get_default_flow_msgs_for_subscriber(imsi, ip_addr) if msgs: msg_list.extend(msgs) for rule in dynamic_rules: try: if rule.redirect.support == rule.redirect.ENABLED: continue flow_adds = self._get_rule_match_flow_msgs( imsi, msisdn, uplink_tunnel, ip_addr, apn_ambr, rule) msg_list.extend(flow_adds) except FlowMatchError: self.logger.error("Failed to verify rule_id: %s", rule.id) return {self.tbl_num: msg_list}
def _activate_flows_gy( self, request: ActivateFlowsRequest, fut: 'Future[ActivateFlowsResult]') -> ActivateFlowsResult: """ Ensure that the RuleModResult is only successful if the flows are successfully added in both the enforcer app and enforcement_stats. Install enforcement_stats flows first because even if the enforcement flow install fails after, no traffic will be directed to the enforcement_stats flows. """ logging.debug('Activating GY flows for %s', request.sid.id) ipv4 = convert_ipv4_str_to_ip_proto(request.ip_addr) self._update_version(request, ipv4) # Install rules in enforcement stats enforcement_stats_res = self._activate_rules_in_enforcement_stats( request.sid.id, ipv4, request.apn_ambr, request.rule_ids, request.dynamic_rules) failed_static_rule_results, failed_dynamic_rule_results = \ _retrieve_failed_results(enforcement_stats_res) # Do not install any rules that failed to install in enforcement_stats. static_rule_ids = \ _filter_failed_static_rule_ids(request, failed_static_rule_results) dynamic_rules = \ _filter_failed_dynamic_rules(request, failed_dynamic_rule_results) gy_res = self._activate_rules_in_gy(request.sid.id, ipv4, request.apn_ambr, static_rule_ids, dynamic_rules) # Include the failed rules from enforcement_stats in the response. gy_res.static_rule_results.extend(failed_static_rule_results) gy_res.dynamic_rule_results.extend(failed_dynamic_rule_results) fut.set_result(gy_res)
def _deactivate_flows_gy(self, request): ipv4 = convert_ipv4_str_to_ip_proto(request.ip_addr) logging.debug('Deactivating GY flows for %s', request.sid.id) # all flows are deactivated self._service_manager.session_rule_version_mapper.update_version( request.sid.id, ipv4) self._gy_app.deactivate_rules(request.sid.id, ipv4, request.rule_ids)
def test_redirect_policy(self): """ Add a redirect policy, verifies that EnforcementStatsController reports correct stats to sessiond Assert: 1 Packet is matched and reported """ fake_controller_setup(self.enforcement_controller, self.enforcement_stats_controller) redirect_ips = ["185.128.101.5", "185.128.121.4"] self.enforcement_controller._redirect_manager._dns_cache.get( "about.sha.ddih.org", lambda: redirect_ips, max_age=42) imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list = [FlowDescription(match=FlowMatch())] policy = PolicyRule(id='redir_test', priority=3, flow_list=flow_list, redirect=RedirectInformation( support=1, address_type=2, server_address="http://about.sha.ddih.org/")) stat_name = imsi + '|redir_test' + '|' + sub_ip self.service_manager.session_rule_version_mapper.update_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'redir_test') """ Setup subscriber, setup table_isolation to fwd pkts """ self._static_rule_dict[policy.id] = policy sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller).add_dynamic_rule(policy) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packet = TCPPacketBuilder() \ .set_tcp_layer(42132, 80, 321) \ .set_tcp_flags("S") \ .set_ip_layer('151.42.41.122', sub_ip) \ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00") \ .build() # =========================== Verification =========================== snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) """ Send packet, wait until pkts are received by ovs and enf stats """ with isolator, sub_context, snapshot_verifier: self.enforcement_stats_controller._report_usage.reset_mock() pkt_sender.send(packet) wait_for_enforcement_stats(self.enforcement_stats_controller, [stat_name]) """ Send packets, wait until pkts are received by ovs and enf stats """ stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list) self.assertEqual(stats[stat_name].sid, imsi) self.assertEqual(stats[stat_name].rule_id, "redir_test") self.assertEqual(stats[stat_name].bytes_rx, 0) self.assertEqual(stats[stat_name].bytes_tx, len(packet))
def _delete_old_flows(self, records): """ Check if the version of any record is older than the current version. If so, delete the flow. """ for record in records: ip_addr = None if record.ue_ipv4: ip_addr = convert_ipv4_str_to_ip_proto(record.ue_ipv4) elif record.ue_ipv6: ip_addr = convert_ipv6_str_to_ip_proto(record.ue_ipv6) current_ver = self._session_rule_version_mapper.get_version( record.sid, ip_addr, record.rule_id) if current_ver == record.rule_version: continue try: self._delete_flow(record.sid, ip_addr, record.rule_id, record.rule_version) except MagmaOFError as e: self.logger.error( 'Failed to delete rule %s for subscriber %s (' 'version: %s): %s', record.rule_id, record.sid, record.rule_version, e)
def test_invalid_subscriber(self): """ Try to apply an invalid policy to a subscriber, should log and error Assert: Only 1 flow gets added to the table (drop flow) """ fake_controller_setup(self.enforcement_controller) imsi = 'IMSI000000000000001' sub_ip = '192.168.128.45' flow_list = [ FlowDescription(match=FlowMatch( ip_src=convert_ipv4_str_to_ip_proto('9999.0.0.0/24')), action=FlowDescription.DENY) ] policy = PolicyRule(id='invalid', priority=2, flow_list=flow_list) invalid_sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._tbl_num).add_dynamic_rule(policy) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( invalid_sub_context.cfg).build_requests(), self.testing_controller) flow_query = FlowQuery(self._tbl_num, self.testing_controller) num_flows_start = len(flow_query.lookup()) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with isolator, invalid_sub_context, snapshot_verifier: wait_after_send(self.testing_controller) num_flows_final = len(flow_query.lookup()) self.assertEqual(num_flows_final - num_flows_start, 0)
def _activate_flows(self, request: ActivateFlowsRequest, fut: 'Future[ActivateFlowsResult]') -> None: """ Activate flows for ipv4 / ipv6 or both CWF won't have an ip_addr passed """ ret = ActivateFlowsResult() if self._service_config['setup_type'] == 'CWF' or request.ip_addr: ipv4 = convert_ipv4_str_to_ip_proto(request.ip_addr) if request.request_origin.type == RequestOriginType.GX: ret_ipv4 = self._install_flows_gx(request, ipv4) else: ret_ipv4 = self._install_flows_gy(request, ipv4) ret.static_rule_results.extend(ret_ipv4.static_rule_results) ret.dynamic_rule_results.extend(ret_ipv4.dynamic_rule_results) if request.ipv6_addr: ipv6 = convert_ipv6_bytes_to_ip_proto(request.ipv6_addr) self._update_ipv6_prefix_store(request.ipv6_addr) if request.request_origin.type == RequestOriginType.GX: ret_ipv6 = self._install_flows_gx(request, ipv6) else: ret_ipv6 = self._install_flows_gy(request, ipv6) ret.static_rule_results.extend(ret_ipv6.static_rule_results) ret.dynamic_rule_results.extend(ret_ipv6.dynamic_rule_results) if request.uplink_tunnel and request.downlink_tunnel: self._update_tunnel_map_store(request.uplink_tunnel, request.downlink_tunnel) fut.set_result(ret)
def _activate_flows( self, request: ActivateFlowsRequest, fut: 'Future[ActivateFlowsResult]', ) -> None: """ Activate flows for ipv4 / ipv6 or both CWF won't have an ip_addr passed """ ret = ActivateFlowsResult() if self._service_config['setup_type'] == 'CWF' or request.ip_addr: ipv4 = convert_ipv4_str_to_ip_proto(request.ip_addr) if request.request_origin.type == RequestOriginType.GX: self._update_version(request, ipv4) ret_ipv4 = self._install_flows_gx(request, ipv4) else: ret_ipv4 = self._install_flows_gy(request, ipv4) ret.policy_results.extend(ret_ipv4.policy_results) if request.ipv6_addr: ipv6 = convert_ipv6_bytes_to_ip_proto(request.ipv6_addr) self._update_ipv6_prefix_store(request.ipv6_addr) if request.request_origin.type == RequestOriginType.GX: self._update_version(request, ipv6) ret_ipv6 = self._install_flows_gx(request, ipv6) else: ret_ipv6 = self._install_flows_gy(request, ipv6) ret.policy_results.extend(ret_ipv6.policy_results) fut.set_result(ret)
def test_cookie_poll(self): """ Add a subscriber policy, verify flows are properly installed Assert: Query with RULE_NUM 1 returns proper values """ original = self.enforcement_stats_controller._poll_stats self.enforcement_stats_controller._poll_stats = MagicMock() self.enforcement_stats_controller.init_finished = False self.enforcement_controller.init_finished = True imsi = 'IMSI001010000000013' sub_ip = '192.168.128.74' flow_list = [ FlowDescription( match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.0/25'), direction=FlowMatch.UPLINK, ), action=FlowDescription.PERMIT, ), ] policy = VersionedPolicy( rule=PolicyRule(id='rule1', priority=3, flow_list=flow_list), version=1, ) enf_stat_name = imsi + '|' + 'rule1' + '|' + sub_ip + '|' + "1" """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller, ).add_policy(policy) snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) self.enforcement_stats_controller._report_usage.reset_mock() with sub_context, snapshot_verifier: self.enforcement_stats_controller.init_finished = True flows.send_stats_request( self.enforcement_stats_controller._datapath, self.enforcement_stats_controller.tbl_num, 0, flows.OVS_COOKIE_MATCH_ALL, ) wait_for_enforcement_stats( self.enforcement_stats_controller, [enf_stat_name], ) stats = get_enforcement_stats( self.enforcement_stats_controller._report_usage.call_args_list, ) self.assertEqual(stats[enf_stat_name].rule_id, 'rule1') self.enforcement_stats_controller._poll_stats = original self.assertEqual(len(stats), 2)
def test_subscriber_restrict_policy(self): """ Add restrict policy to subscriber, send 4096 packets Assert: Packets are properly matched with the 'restrict_match' policy Send /20 (4096) packets, match /16 (256) packets """ fake_controller_setup(self.gy_controller) imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list1 = [ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto('8.8.8.0/24'), direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies = [ VersionedPolicy( rule=PolicyRule(id='restrict_match', priority=2, flow_list=flow_list1), version=1, ) ] pkts_matched = 256 pkts_sent = 4096 # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.gy_controller, self._tbl_num).add_policy(policies[0]) isolator = RyuDirectTableIsolator( RyuForwardFlowArgsBuilder.from_subscriber( sub_context.cfg).build_requests(), self.testing_controller) pkt_sender = ScapyPacketInjector(self.IFACE) packet = IPPacketBuilder()\ .set_ip_layer('8.8.8.8', sub_ip)\ .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00")\ .build() flow_query = FlowQuery(self._tbl_num, self.testing_controller, match=flow_match_to_magma_match( flow_list1[0].match)) # =========================== Verification =========================== # Verify aggregate table stats, subscriber 1 'simple_match' pkt count flow_verifier = FlowVerifier([ FlowTest(FlowQuery(self._tbl_num, self.testing_controller), pkts_sent), FlowTest(flow_query, pkts_matched) ], lambda: wait_after_send(self.testing_controller)) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager, include_stats=False) with isolator, sub_context, flow_verifier, snapshot_verifier: pkt_sender.send(packet)
def _build_activate_flows_data(ue_dict, disable_qos): activate_flow_reqs = [] if disable_qos: print("QOS Disabled") apn_ambr = None else: print("QOS Enabled") apn_ambr = AggregatedMaximumBitrate( max_bandwidth_ul=1000000000, max_bandwidth_dl=1000000000, ) for ue in ue_dict: request = ActivateFlowsRequest( sid=SIDUtils.to_pb(ue.imsi_str), ip_addr=ue.ipv4_src, policies=[ VersionedPolicy( rule=PolicyRule( id=ue.rule_id, priority=10, flow_list=[ FlowDescription(match=FlowMatch( ip_dst=convert_ipv4_str_to_ip_proto( ue.ipv4_src), direction=FlowMatch.UPLINK, ), ), FlowDescription(match=FlowMatch( ip_src=convert_ipv4_str_to_ip_proto( ue.ipv4_dst), direction=FlowMatch.DOWNLINK, ), ), ], ), version=1, ), ], request_origin=RequestOriginType(type=RequestOriginType.GX), apn_ambr=apn_ambr, ) request_dict = json_format.MessageToDict(request) # Dumping ActivateFlows request into json activate_flow_reqs.append(request_dict) with open('activate_flows.json', 'w') as file: json.dump(activate_flow_reqs, file, separators=(',', ':'))
def _process_redirection_rules(self, requests): for add_flow_req in requests: imsi = add_flow_req.sid.id ip_addr = convert_ipv4_str_to_ip_proto(add_flow_req.ip_addr) dynamic_rules = add_flow_req.dynamic_rules for rule in dynamic_rules: if rule.redirect.support == rule.redirect.ENABLED: self._install_redirect_flow(imsi, ip_addr, rule)
def _set_he_target_urls(self, ue_addr: str, rule_id: str, urls: List[str], imsi: str, msisdn: bytes) -> bool: msisdn_str = None ip_addr = convert_ipv4_str_to_ip_proto(ue_addr) if self.config.encryption_enabled: imsi = self.encrypt_header(imsi) if msisdn: msisdn_str = self.encrypt_header(msisdn.decode("utf-8")) return activate_he_urls_for_ue(ip_addr, rule_id, urls, imsi, msisdn_str)
def _process_redirection_rules(self, requests): for add_flow_req in requests: imsi = add_flow_req.sid.id ip_addr = convert_ipv4_str_to_ip_proto(add_flow_req.ip_addr) policies = add_flow_req.policies for policy in policies: if policy.rule.redirect.support == policy.rule.redirect.ENABLED: self._install_redirect_flow(imsi, ip_addr, policy.rule, policy.version)
def test_remove_app_rules(self): """ Test DPI classifier flows are properly removed Assert: Remove the facebook match flow """ flow_match1 = FlowMatch( ip_proto=FlowMatch.IPPROTO_TCP, ip_dst=convert_ipv4_str_to_ip_proto('45.10.0.8'), ip_src=convert_ipv4_str_to_ip_proto('1.2.3.4'), tcp_dst=80, tcp_src=51115, direction=FlowMatch.UPLINK ) self.dpi_controller.remove_classify_flow(flow_match1) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with snapshot_verifier: pass
def test_ipv6_rule_install(self): """ Adds a ipv6 policy to a subscriber. Verifies that flows are properly installed in enforcement and enforcement stats. Assert: Policy classification flows installed in enforcement Policy match flows installed in enforcement_stats """ fake_controller_setup( self.enforcement_controller, self.enforcement_stats_controller, ) imsi = 'IMSI001010000000013' sub_ip = 'de34:431d:1bc::' flow_list = [ FlowDescription( match=FlowMatch( ip_dst=convert_ipv6_bytes_to_ip_proto( 'f333:432::dbca'.encode('utf-8'), ), direction=FlowMatch.UPLINK, ), action=FlowDescription.PERMIT, ), ] policy = VersionedPolicy( rule=PolicyRule(id='rule1', priority=3, flow_list=flow_list), version=1, ) self.service_manager.session_rule_version_mapper.save_version( imsi, convert_ipv4_str_to_ip_proto(sub_ip), 'rule1', 1, ) """ Setup subscriber, setup table_isolation to fwd pkts """ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._main_tbl_num, self.enforcement_stats_controller, ).add_policy(policy) # =========================== Verification =========================== snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, ) with sub_context, snapshot_verifier: pass