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, ipv4_dst='45.10.0.8', ipv4_src='1.2.3.4', tcp_dst=80, tcp_src=51115, direction=FlowMatch.UPLINK) flow_match2 = FlowMatch(ip_proto=FlowMatch.IPPROTO_TCP, ipv4_dst='1.10.0.1', ipv4_src='6.2.3.1', tcp_dst=111, tcp_src=222, direction=FlowMatch.UPLINK) flow_match3 = FlowMatch(ip_proto=FlowMatch.IPPROTO_UDP, ipv4_dst='22.2.2.24', ipv4_src='15.22.32.2', udp_src=111, udp_dst=222, direction=FlowMatch.UPLINK) flow_match_for_no_proto = FlowMatch(ip_proto=FlowMatch.IPPROTO_UDP, ipv4_dst='1.1.1.1') flow_match_not_added = FlowMatch(ip_proto=FlowMatch.IPPROTO_UDP, ipv4_src='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_whitelist_flows(self, ip: str, port: int) -> List[FlowDescription]: """ Args: ip: IP address to allow traffic to. This should be the captive portal address port: Port of the captive portal server. Probably 80. Returns: Two flows, one for traffic towards the captive portal server, and a second for traffic from the captive portal server. """ return [ # Set flow match for outgoing TCP packets to whitelisted IP # Don't set the app_name field FlowDescription( # uplink flow match=FlowMatch( ipv4_dst=ip, tcp_dst=port, ip_proto=FlowMatch.IPProto.Value("IPPROTO_TCP"), direction=FlowMatch.Direction.Value("UPLINK"), ), action=FlowDescription.Action.Value("PERMIT"), ), # Set flow match for incoming TCP packets from whitelisted IP # Don't set the app_name field FlowDescription( # downlink flow match=FlowMatch( ipv4_src=ip, tcp_src=port, ip_proto=FlowMatch.IPProto.Value("IPPROTO_TCP"), direction=FlowMatch.Direction.Value("DOWNLINK"), ), action=FlowDescription.Action.Value("PERMIT"), ), ]
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 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(ipv4_dst='45.10.0.0/25', direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policy = PolicyRule(id='rule1', priority=3, flow_list=flow_list) self.service_manager.session_rule_version_mapper.update_version( imsi, 'rule1') version = \ self.service_manager.session_rule_version_mapper.get_version( imsi, 'rule1') """ 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_static_rule(policy.id) # =========================== Verification =========================== rule_num = self.enforcement_stats_controller._rule_mapper \ .get_or_create_rule_num(policy.id) enf_query = FlowQuery(self._main_tbl_num, self.testing_controller, match=flow_match_to_magma_match( FlowMatch(ipv4_dst='45.10.0.0/25', direction=FlowMatch.UPLINK)), cookie=rule_num) es_query = FlowQuery(self._scratch_tbl_num, self.testing_controller, match=MagmaMatch(imsi=encode_imsi(imsi), reg2=rule_num, rule_version=version), cookie=rule_num) # Verifies that 1 flow is installed in enforcement and 2 flows are # installed in enforcement stats, one for uplink and one for downlink. flow_verifier = FlowVerifier([ FlowTest(enf_query, 0, flow_count=1), FlowTest(es_query, 0, flow_count=2), ], lambda: None) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with sub_context, flow_verifier, snapshot_verifier: pass flow_verifier.verify()
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_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 _get_allow_all_traffic_policies(self): """ Policy to allow all traffic to the internet """ return [ PolicyRule( id='allow_all_traffic', priority=self.ALLOW_ALL_PRIORITY, flow_list=[ FlowDescription(match=FlowMatch( direction=FlowMatch.UPLINK)), FlowDescription(match=FlowMatch( direction=FlowMatch.DOWNLINK)), ], ) ]
def test_add_app_rules(self): """ Test DPI classifier flows are properly added Assert: 1 App not tracked -> no rule installed(`notanAPP`) 3 App types are matched on: facebook other google_docs other viber audio """ MAC_DEST = "5e:cc:cc:b1:49:4b" flow_match1 = FlowMatch(ip_proto=FlowMatch.IPPROTO_TCP, ipv4_dst='45.10.0.8', ipv4_src='1.2.3.4', tcp_dst=80, tcp_src=51115, direction=FlowMatch.UPLINK) flow_match2 = FlowMatch(ip_proto=FlowMatch.IPPROTO_TCP, ipv4_dst='1.10.0.1', ipv4_src='6.2.3.1', tcp_dst=111, tcp_src=222, direction=FlowMatch.UPLINK) flow_match3 = FlowMatch(ip_proto=FlowMatch.IPPROTO_UDP, ipv4_dst='22.2.2.24', ipv4_src='15.22.32.2', udp_src=111, udp_dst=222, direction=FlowMatch.UPLINK) flow_match_for_no_proto = FlowMatch(ip_proto=FlowMatch.IPPROTO_UDP, ipv4_dst='1.1.1.1') self.dpi_controller.add_classify_flow(flow_match_for_no_proto, 'notanAPP', 'null', MAC_DEST, MAC_DEST) self.dpi_controller.add_classify_flow(flow_match1, 'base.ip.http.facebook', 'NotReal', MAC_DEST, MAC_DEST) self.dpi_controller.add_classify_flow( flow_match2, 'base.ip.https.google_gen.google_docs', 'MAGMA', MAC_DEST, MAC_DEST) self.dpi_controller.add_classify_flow(flow_match3, 'base.ip.udp.viber', 'AudioTransfer Receiving', MAC_DEST, MAC_DEST) snapshot_verifier = SnapshotVerifier(self, self.BRIDGE, self.service_manager) with snapshot_verifier: pass
def activate_dynamic_rule(client, args): request = ActivateFlowsRequest( sid=SIDUtils.to_pb(args.imsi), dynamic_rules=[PolicyRule( id=args.rule_id, priority=args.priority, hard_timeout=args.hard_timeout, flow_list=[ FlowDescription(match=FlowMatch( ipv4_dst=args.ipv4_dst, direction=FlowMatch.UPLINK)), FlowDescription(match=FlowMatch( ipv4_src=args.ipv4_dst, direction=FlowMatch.DOWNLINK)), ], )]) client.ActivateFlows(request)
def create_uplink_rule(id, rating_group, ip_dest, m_key=None, priority=10, tracking=PolicyRule.ONLY_OCS, action=FlowDescription.PERMIT): """ Create a rule with a single uplink IP flow, useful for testing Args: id (string): rule id rating_group (int): charging key ip_dest (string): IP destination for rule flow m_key (optional string): monitoring key, if the rule is tracked by PCRF priority (int): priority of flow, the greater the higher the priority tracking (PolicyRule.TrackingType): enum to dictate whether OCS or PCRF or both is tracking the credit action: permit or deny Returns: PolicyRule with single uplink IP flow """ return PolicyRule( id=id, priority=priority, flow_list=[ FlowDescription(match=FlowMatch(ipv4_dst=ip_dest, direction=FlowMatch.UPLINK), action=action) ], tracking_type=tracking, rating_group=rating_group, monitoring_key=m_key, )
def add_rule(args): rule_id = args.rule_id policy_dict = PolicyRuleDict() arg_list = { 'ip_proto': args.ip_proto, 'ip_dst': IPAddress(version=IPAddress.IPV4, address=args.ipv4_dst.encode('utf-8')), 'ip_src': IPAddress(version=IPAddress.IPV4, address=args.ipv4_src.encode('utf-8')), 'tcp_dst': args.tcp_dst, 'tcp_src': args.tcp_src, 'udp_dst': args.udp_dst, 'udp_src': args.udp_src, 'direction': args.direction } match = FlowMatch(**arg_list) flow = FlowDescription(match=match, action=args.action) rule = policy_dict.get(rule_id) if not rule or args.overwrite: action = 'add' rule = PolicyRule(id=rule_id, flow_list=[flow]) else: action = 'edit' rule.flow_list.extend([flow]) policy_dict[rule_id] = rule print("Rule '%s' successfully %sed!" % (rule_id, action))
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 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 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
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 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, ipv4_dst='45.10.0.1', ipv4_src='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_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 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 _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 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_ipv6_policy(self): """ Add policy to subscriber, send 4096 packets Assert: Packets are properly matched with the 'simple_match' policy Send /20 (4096) packets, match /16 (256) packets """ fake_controller_setup(self.enforcement_controller) imsi = 'IMSI010000000088888' sub_ip = 'de34:431d:1bc::' flow_list1 = [ FlowDescription( match=FlowMatch( ip_dst=convert_ipv6_bytes_to_ip_proto( 'f333:432::dbca'.encode('utf-8'), ), direction=FlowMatch.UPLINK, ), action=FlowDescription.PERMIT, ), ] policies = [ VersionedPolicy( rule=PolicyRule(id='simple_match', priority=2, flow_list=flow_list1), version=1, ), ] # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_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 = IPv6PacketBuilder() \ .set_ip_layer('f333:432::dbca', 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, ) with isolator, sub_context, snapshot_verifier: pkt_sender.send(packet)
def _get_allow_all_flows() -> List[FlowDescription]: """ Get flows for allowing all traffic Returns: Two flows, for outgoing and incoming traffic """ return [ # Set flow match for all packets # Don't set the app_name field FlowDescription( # uplink flow match=FlowMatch(direction=FlowMatch.Direction.Value("UPLINK"), ), action=FlowDescription.Action.Value("PERMIT"), ), FlowDescription( # downlink flow match=FlowMatch(direction=FlowMatch.Direction.Value("DOWNLINK"), ), action=FlowDescription.Action.Value("PERMIT"), ), ]
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 activate_dynamic_rule(client, args): request = ActivateFlowsRequest( sid=SIDUtils.to_pb(args.imsi), dynamic_rules=[ PolicyRule( id=args.rule_id, priority=args.priority, hard_timeout=args.hard_timeout, flow_list=[ FlowDescription(match=FlowMatch( ipv4_dst=args.ipv4_dst, direction=FlowMatch.UPLINK)), FlowDescription(match=FlowMatch( ipv4_src=args.ipv4_dst, direction=FlowMatch.DOWNLINK)), ], ) ], request_origin=RequestOriginType(type=RequestOriginType.GX)) response = client.ActivateFlows(request) _print_rule_mod_results(response.dynamic_rule_results)
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
def get_flow_match(self, flow_list, flow_match_list): """ Populates flow match list """ for flow in flow_list: flow_direction = (FlowMatch.UPLINK if flow["direction"] == "UL" else FlowMatch.DOWNLINK) ip_protocol = flow["ip_proto"] if ip_protocol == "TCP": ip_protocol = FlowMatch.IPPROTO_TCP udp_src_port = 0 udp_dst_port = 0 tcp_src_port = (int(flow["tcp_src_port"]) if "tcp_src_port" in flow else 0) tcp_dst_port = (int(flow["tcp_dst_port"]) if "tcp_dst_port" in flow else 0) elif ip_protocol == "UDP": ip_protocol = FlowMatch.IPPROTO_UDP tcp_src_port = 0 tcp_dst_port = 0 udp_src_port = (int(flow["udp_src_port"]) if "udp_src_port" in flow else 0) udp_dst_port = (int(flow["udp_dst_port"]) if "udp_dst_port" in flow else 0) else: udp_src_port = 0 udp_dst_port = 0 tcp_src_port = 0 tcp_dst_port = 0 ipv4_src_addr = None if flow.get("ipv4_src", None): ipv4_src_addr = IPAddress( version=IPAddress.IPV4, address=flow.get("ipv4_src").encode('utf-8')) ipv4_dst_addr = None if flow.get("ipv4_dst", None): ipv4_dst_addr = IPAddress( version=IPAddress.IPV4, address=flow.get("ipv4_dst").encode('utf-8')) flow_match_list.append( FlowDescription( match=FlowMatch( ip_dst=ipv4_dst_addr, ip_src=ipv4_src_addr, tcp_src=tcp_src_port, tcp_dst=tcp_dst_port, udp_src=udp_src_port, udp_dst=udp_dst_port, ip_proto=ip_protocol, direction=flow_direction, ), action=FlowDescription.PERMIT, ))
def test_subscriber_policy(self): """ Add policy to subscriber, send 4096 packets Assert: Packets are properly matched with the 'simple_match' policy Send /20 (4096) packets, match /16 (256) packets """ imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' flow_list1 = [FlowDescription( match=FlowMatch( ipv4_dst='45.10.0.0/24', direction=FlowMatch.UPLINK), action=FlowDescription.PERMIT) ] policies = [ PolicyRule(id='simple_match', priority=2, flow_list=flow_list1) ] pkts_matched = 256 pkts_sent = 4096 self._static_rule_dict[policies[0].id] = policies[0] # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.enforcement_controller, self._tbl_num ).add_static_rule(policies[0].id) 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() 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)) with isolator, sub_context, flow_verifier: pkt_sender.send(packet) flow_verifier.verify()
def test_subscriber_redirect_policy(self): """ Add redirect policy to subscriber, send 4096 packets Assert: Packets are properly matched with the 'simple_match' policy Send /20 (4096) packets, match /16 (256) packets """ fake_controller_setup(self.gy_controller) imsi = 'IMSI010000000088888' sub_ip = '192.168.128.74' redirect_ips = ["185.128.101.5", "185.128.121.4"] self.gy_controller._redirect_manager._dns_cache.get( "about.sha.ddih.org", lambda: redirect_ips, max_age=42, ) flow_list = [FlowDescription(match=FlowMatch())] policy = VersionedPolicy( rule=PolicyRule( id='redir_test', priority=3, flow_list=flow_list, redirect=RedirectInformation( support=1, address_type=2, server_address="http://about.sha.ddih.org/", ), ), version=1, ) # ============================ Subscriber ============================ sub_context = RyuDirectSubscriberContext( imsi, sub_ip, self.gy_controller, self._tbl_num, ).add_policy(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, 2)\ .set_tcp_flags("S")\ .set_ip_layer('151.42.41.122', sub_ip)\ .set_ether_layer(self.MAC_DEST, "01:20:10:20:aa:bb")\ .build() snapshot_verifier = SnapshotVerifier( self, self.BRIDGE, self.service_manager, include_stats=False, ) with isolator, sub_context, snapshot_verifier: pkt_sender.send(packet)
def _get_allow_all_flows(self) -> List[FlowDescription]: """ Returns: Two flows, for outgoing and incoming traffic """ return [ # Set flow match for ll packets # Don't set the app_name field FlowDescription( # uplink flow match=FlowMatch(), action=FlowDescription.Action.Value("PERMIT"), ), ]
def CreateAddQERinPDR(qos_enforce_rule: QoSEnforceRuleEntry, ue_ip_addr: str) -> 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, dynamic_rules=[ PolicyRule(id=qos_enforce_rule.rule_id, priority=qos_enforce_rule.priority, hard_timeout=qos_enforce_rule.hard_timeout, flow_list=flow_list) ], request_origin=RequestOriginType(type=RequestOriginType.N4)) return qos_enforce_rule