From 52bc4be547a22df967b2ed35bdbca4f5bce9ab93 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 25 Feb 2022 14:11:51 +0100 Subject: [PATCH] Bugfix packet filter for pre rel11 LTE devices (#1393) * Fix conversion from IPFilterRule to packet filter As per 3GPP TS 24.008, following Packet filter component type identifier are not supported on the LTE pre release-11 UEs: IPv4 local address type IPv6 remote address/prefix length type IPv6 local address/prefix length type And, IPv6 remote address/prefix length type and IPv6 local address/prefix length type shall be used when both MS and Network support Local Address in TFTs. This commit add logic to omit adding local address in packet filters for compatibility with pre-release LTE 11 devices. The following parameter could be used to toggle omit/no to omit behavior. parameter: no_ipv4v6_local_addr_in_packet_filter: * Remove logic of supporting pre-release LTE 11 devices in PCRF --- configs/open5gs/pcrf.yaml.in | 5 -- configs/open5gs/smf.yaml.in | 4 ++ lib/ipfw/ogs-ipfw.c | 126 +++++++++++++++++++++++++---------- lib/ipfw/ogs-ipfw.h | 3 +- src/pcrf/pcrf-rx-path.c | 113 +------------------------------ src/smf/binding.c | 4 +- src/smf/gsm-build.c | 3 +- 7 files changed, 104 insertions(+), 154 deletions(-) diff --git a/configs/open5gs/pcrf.yaml.in b/configs/open5gs/pcrf.yaml.in index a457270a4..118f15c76 100644 --- a/configs/open5gs/pcrf.yaml.in +++ b/configs/open5gs/pcrf.yaml.in @@ -40,11 +40,6 @@ pcrf: # o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. # prefer_ipv4: true # -# o Legacy support for pre-release LTE 11 devices to do calling -# - Replace IPv4/v6 local addr field in AAR Media-Subcomponent AVP -# by 'any local port' -# no_ipv4v6_local_addr_in_packet_filter: true -# parameter: # diff --git a/configs/open5gs/smf.yaml.in b/configs/open5gs/smf.yaml.in index ac862dfeb..c462b8e51 100644 --- a/configs/open5gs/smf.yaml.in +++ b/configs/open5gs/smf.yaml.in @@ -458,6 +458,10 @@ upf: # o Disable selection of UPF PFCP in Round-Robin manner # no_pfcp_rr_select: true # +# o Legacy support for pre-release LTE 11 devices +# - Omits adding local address in packet filters for compatibility +# no_ipv4v6_local_addr_in_packet_filter: true +# parameter: # diff --git a/lib/ipfw/ogs-ipfw.c b/lib/ipfw/ogs-ipfw.c index 203a9ed3d..0e0e2ced4 100644 --- a/lib/ipfw/ogs-ipfw.c +++ b/lib/ipfw/ogs-ipfw.c @@ -365,7 +365,8 @@ void ogs_ipfw_rule_swap(ogs_ipfw_rule_t *ipfw_rule) } void ogs_pf_content_from_ipfw_rule( - uint8_t direction, ogs_pf_content_t *content, ogs_ipfw_rule_t *rule) + uint8_t direction, ogs_pf_content_t *content, ogs_ipfw_rule_t *rule, + bool no_ipv4v6_local_addr_in_packet_filter) { int j, len; @@ -380,57 +381,112 @@ void ogs_pf_content_from_ipfw_rule( j++; len += 2; } - if (rule->ipv4_src) { - if (direction == OGS_FLOW_DOWNLINK_ONLY) - content->component[j].type = - OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE; - else - content->component[j].type = - OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE; + /* + * As per 3GPP TS 24.008, following Packet filter component type identifier + * are not supported on the LTE pre release-11 UEs: + * + * IPv4 local address type + * IPv6 remote address/prefix length type + * IPv6 local address/prefix length type + * + * And, + * IPv6 remote address/prefix length type and + * IPv6 local address/prefix length type shall be used when both MS and + * Network support Local Address in TFTs. + */ + + if (rule->ipv4_src && (direction == OGS_FLOW_DOWNLINK_ONLY)) { + content->component[j].type = OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE; content->component[j].ipv4.addr = rule->ip.src.addr[0]; content->component[j].ipv4.mask = rule->ip.src.mask[0]; j++; len += 9; } - if (rule->ipv4_dst) { - if (direction == OGS_FLOW_DOWNLINK_ONLY) - content->component[j].type = - OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE; - else - content->component[j].type = - OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE; + if (rule->ipv4_src && (direction == OGS_FLOW_UPLINK_ONLY) && + !no_ipv4v6_local_addr_in_packet_filter) { + content->component[j].type = OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE; + content->component[j].ipv4.addr = rule->ip.src.addr[0]; + content->component[j].ipv4.mask = rule->ip.src.mask[0]; + j++; len += 9; + } + if (rule->ipv4_dst && (direction == OGS_FLOW_DOWNLINK_ONLY) && + !no_ipv4v6_local_addr_in_packet_filter) { + content->component[j].type = OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE; content->component[j].ipv4.addr = rule->ip.dst.addr[0]; content->component[j].ipv4.mask = rule->ip.dst.mask[0]; j++; len += 9; } - if (rule->ipv6_src) { - if (direction == OGS_FLOW_DOWNLINK_ONLY) - content->component[j].type = - OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE; - else - content->component[j].type = - OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE; - memcpy(content->component[j].ipv6.addr, - rule->ip.src.addr, sizeof rule->ip.src.addr); - content->component[j].ipv6.prefixlen = - contigmask((uint8_t *)rule->ip.src.mask, 128); - j++; len += 18; + if (rule->ipv4_dst && (direction == OGS_FLOW_UPLINK_ONLY)) { + content->component[j].type = OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE; + content->component[j].ipv4.addr = rule->ip.dst.addr[0]; + content->component[j].ipv4.mask = rule->ip.dst.mask[0]; + j++; len += 9; } - if (rule->ipv6_dst) { - if (direction == OGS_FLOW_DOWNLINK_ONLY) + if (rule->ipv6_src && (direction == OGS_FLOW_DOWNLINK_ONLY)) { + if (no_ipv4v6_local_addr_in_packet_filter) { content->component[j].type = - OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE; - else + OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE; + memcpy(content->component[j].ipv6_mask.addr, + rule->ip.src.addr, sizeof rule->ip.src.addr); + memcpy(content->component[j].ipv6_mask.mask, + rule->ip.src.mask, sizeof rule->ip.src.mask); + j++; len += 33; + } else { content->component[j].type = OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE; - memcpy(content->component[j].ipv6.addr, + memcpy(content->component[j].ipv6.addr, + rule->ip.src.addr, sizeof rule->ip.src.addr); + content->component[j].ipv6.prefixlen = + contigmask((uint8_t *)rule->ip.src.mask, 128); + j++; len += 18; + } + } + + if (rule->ipv6_src && (direction == OGS_FLOW_UPLINK_ONLY)) { + if (!no_ipv4v6_local_addr_in_packet_filter) { + content->component[j].type = + OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE; + memcpy(content->component[j].ipv6.addr, + rule->ip.src.addr, sizeof rule->ip.src.addr); + content->component[j].ipv6.prefixlen = + contigmask((uint8_t *)rule->ip.src.mask, 128); + j++; len += 18; + } + } + + if (rule->ipv6_dst && (direction == OGS_FLOW_DOWNLINK_ONLY)) { + if (!no_ipv4v6_local_addr_in_packet_filter) { + content->component[j].type = + OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE; + memcpy(content->component[j].ipv6.addr, rule->ip.dst.addr, sizeof rule->ip.dst.addr); - content->component[j].ipv6.prefixlen = - contigmask((uint8_t *)rule->ip.dst.mask, 128); - j++; len += 18; + content->component[j].ipv6.prefixlen = + contigmask((uint8_t *)rule->ip.dst.mask, 128); + j++; len += 18; + } + } + + if (rule->ipv6_dst && (direction == OGS_FLOW_UPLINK_ONLY)) { + if (no_ipv4v6_local_addr_in_packet_filter) { + content->component[j].type = + OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE; + memcpy(content->component[j].ipv6_mask.addr, + rule->ip.dst.addr, sizeof rule->ip.dst.addr); + memcpy(content->component[j].ipv6_mask.mask, + rule->ip.dst.mask, sizeof rule->ip.dst.mask); + j++; len += 33; + } else { + content->component[j].type = + OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE; + memcpy(content->component[j].ipv6.addr, + rule->ip.dst.addr, sizeof rule->ip.dst.addr); + content->component[j].ipv6.prefixlen = + contigmask((uint8_t *)rule->ip.dst.mask, 128); + j++; len += 18; + } } if (rule->port.src.low) { diff --git a/lib/ipfw/ogs-ipfw.h b/lib/ipfw/ogs-ipfw.h index e45ec482f..24df8af5f 100644 --- a/lib/ipfw/ogs-ipfw.h +++ b/lib/ipfw/ogs-ipfw.h @@ -130,7 +130,8 @@ typedef struct ogs_pf_content_s { } ogs_pf_content_t; void ogs_pf_content_from_ipfw_rule( - uint8_t direction, ogs_pf_content_t *content, ogs_ipfw_rule_t *rule); + uint8_t direction, ogs_pf_content_t *content, ogs_ipfw_rule_t *rule, + bool no_ipv4v6_local_addr_in_packet_filter); #ifdef __cplusplus } diff --git a/src/pcrf/pcrf-rx-path.c b/src/pcrf/pcrf-rx-path.c index 7ef6a7cb8..df8cd4420 100644 --- a/src/pcrf/pcrf-rx-path.c +++ b/src/pcrf/pcrf-rx-path.c @@ -92,8 +92,6 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp, { int rv; int ret; - int len; - char *from_str, *to_str, *rx_flow, *to_port, *to_ip, *from_ip, *from_port; struct msg *ans, *qry; struct avp *avpch1, *avpch2, *avpch3; @@ -295,117 +293,10 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp, ogs_assert(sub->num_of_flow < OGS_MAX_NUM_OF_FLOW_IN_MEDIA_SUB_COMPONENT); flow = &sub->flow[sub->num_of_flow]; - - /* IE (IPV4-local-addr field ) is not supported on - * the LTE pre release-11 UEs. In order for the call - * to work the local address in packet filter must - * be replaced by 'any local port'. - */ - if (ogs_app()-> - parameter.no_ipv4v6_local_addr_in_packet_filter - == true) { - rx_flow = NULL; - rx_flow = (char*)hdr->avp_value->os.data; - len = hdr->avp_value->os.len; - - from_str = NULL; - to_str = NULL; - to_ip = NULL; - to_port = NULL; - from_ip = NULL; - from_port = NULL; - from_str = strstr(rx_flow, "from"); - ogs_assert(from_str); - to_str = strstr(rx_flow, "to"); - ogs_assert(to_str); - - if (!strncmp(rx_flow, - "permit out", strlen("permit out"))) { - - to_ip = strstr(to_str, " "); - ogs_assert(to_ip); - - // Exclude the starting whitespace - to_ip += 1; - - to_port = strstr(to_ip, " "); - // Test for no port - if (to_port != NULL) { - flow->description = ogs_calloc(1, - len - strlen(to_str) + - strlen("to any") - + strlen(to_port) + 1); - ogs_assert(flow->description); - } else { - flow->description = ogs_calloc(1, - len - strlen(to_str) + - strlen("to any") + 1); - ogs_assert(flow->description); - } - - ogs_assert(flow->description); - strncat(flow->description, - rx_flow, - len - strlen(to_str)); - strcat(flow->description, "to any"); - if (to_port != NULL) { - strncat(flow->description, - to_port, strlen(to_port)); - } - } else if (!strncmp(rx_flow, - "permit in", strlen("permit in"))) { - - from_ip = strstr(from_str, " "); - ogs_assert(from_ip); - - /* Exclude the starting whitespace */ - from_ip += 1; - - from_port = strstr(from_ip, " "); - /* Test for no port + - * whether from_port is at "to" - * without any from port */ - if (from_port != NULL && - strncmp(from_port, " to", 3)) { - flow->description = ogs_calloc(1, - len - strlen(from_str) + - strlen(to_str) - + strlen("from any") + 1 - + (strlen(from_port) - - strlen(to_str))); - ogs_assert(flow->description); - } else { - flow->description = ogs_calloc(1, - len - strlen(from_str) + - strlen(to_str) - + strlen("from any ") + 1); - ogs_assert(flow->description); - } - - ogs_assert(flow->description); - strncat(flow->description, - rx_flow, - len - strlen(from_str)); - if (from_port != NULL && - strncmp(from_port, " to", 3)) { - strcat(flow->description, "from any"); - strncat(flow->description, - from_port, - strlen(from_port) - strlen(to_str)); - } else { - strcat(flow->description, "from any "); - } - strncat(flow->description, - to_str, - strlen(to_str)); - } - } else { - flow->description = ogs_strndup( + flow->description = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(flow->description); - } - + ogs_assert(flow->description); sub->num_of_flow++; break; default: diff --git a/src/smf/binding.c b/src/smf/binding.c index 81f14f109..ea65197b2 100644 --- a/src/smf/binding.c +++ b/src/smf/binding.c @@ -101,7 +101,9 @@ static void encode_traffic_flow_template( tft->pf[i].precedence = pf->precedence - 1; ogs_pf_content_from_ipfw_rule( - pf->direction, &tft->pf[i].content, &pf->ipfw_rule); + pf->direction, &tft->pf[i].content, &pf->ipfw_rule, + ogs_app()-> + parameter.no_ipv4v6_local_addr_in_packet_filter); } i++; diff --git a/src/smf/gsm-build.c b/src/smf/gsm-build.c index d688f9666..970d222aa 100644 --- a/src/smf/gsm-build.c +++ b/src/smf/gsm-build.c @@ -282,7 +282,8 @@ static void encode_qos_rule_packet_filter( qos_rule->pf[i].identifier = pf->identifier; ogs_pf_content_from_ipfw_rule( - pf->direction, &qos_rule->pf[i].content, &pf->ipfw_rule); + pf->direction, &qos_rule->pf[i].content, &pf->ipfw_rule, + ogs_app()->parameter.no_ipv4v6_local_addr_in_packet_filter); i++; } qos_rule->num_of_packet_filter = i;