diff --git a/include/asterisk/acl.h b/include/asterisk/acl.h
index d1773b6b16b6a916b2b85a3a845800d51326bb60..bda1c7606de5480485fb77cd5dcd3bd056fe8435 100644
--- a/include/asterisk/acl.h
+++ b/include/asterisk/acl.h
@@ -141,6 +141,13 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
  */
 void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf);
 
+/*!
+ * \brief Convert HAs to a comma separated string value using CIDR notation
+ * \param ha the starting ha head
+ * \param buf string buffer to convert data to
+ */
+void ast_ha_join_cidr(const struct ast_ha *ha, struct ast_str **buf);
+
 /*!
  * \brief Add a rule to an ACL struct
  *
diff --git a/include/asterisk/netsock2.h b/include/asterisk/netsock2.h
index 2db8b80812ea4af46928b128558f16847a3195a5..3ede99087788a242e0c33c8cdfe02e51e821a913 100644
--- a/include/asterisk/netsock2.h
+++ b/include/asterisk/netsock2.h
@@ -262,6 +262,16 @@ static inline char *ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
 	return ast_sockaddr_stringify_fmt(addr, AST_SOCKADDR_STR_ADDR);
 }
 
+/*!
+ * \since 12.4
+ *
+ * \brief
+ * Count the 1 bits in a netmask
+ *
+ * \return number of 1 bits
+ */
+int ast_sockaddr_cidr_bits(const struct ast_sockaddr *sa);
+
 /*!
  * \since 1.8
  *
diff --git a/main/acl.c b/main/acl.c
index 213d6d8aa7c0aa66717a3248fcf804aff50043f7..5c3b633d70faf46de886820c4a0dc99f0ee79faf 100644
--- a/main/acl.c
+++ b/main/acl.c
@@ -677,6 +677,19 @@ void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf)
 	}
 }
 
+void ast_ha_join_cidr(const struct ast_ha *ha, struct ast_str **buf)
+{
+	for (; ha; ha = ha->next) {
+		const char *addr = ast_sockaddr_stringify_addr(&ha->addr);
+		ast_str_append(buf, 0, "%s%s/%d",
+			       ha->sense == AST_SENSE_ALLOW ? "!" : "",
+			       addr, ast_sockaddr_cidr_bits(&ha->netmask));
+		if (ha->next) {
+			ast_str_append(buf, 0, ",");
+		}
+	}
+}
+
 enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
 {
 	struct ast_acl *acl;
diff --git a/main/netsock2.c b/main/netsock2.c
index bd682b17d88734c5e8b6a194d35f44b4ce0e4918..0e83f27cf8effb60b8952cb6135b4e1aaeeacd5f 100644
--- a/main/netsock2.c
+++ b/main/netsock2.c
@@ -129,6 +129,40 @@ char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format)
 	return ast_str_buffer(str);
 }
 
+int ast_sockaddr_cidr_bits(const struct ast_sockaddr *sa)
+{
+	struct ast_sockaddr sa_ipv4;
+	const struct ast_sockaddr *sa_tmp;
+	int bits = 0;
+	int bytes;
+	int i;
+	int j;
+	char *addr;
+
+	if (ast_sockaddr_isnull(sa)) {
+		return 0;
+	}
+
+	if (ast_sockaddr_ipv4_mapped(sa, &sa_ipv4)) {
+		sa_tmp = &sa_ipv4;
+	} else {
+		sa_tmp = sa;
+	}
+
+	bytes = sa_tmp->len;
+	addr = ((struct sockaddr *)&sa_tmp->ss)->sa_data;
+
+	for (i = 0; i < bytes ; ++i) {
+		for (j = 0; j < 8; ++j) {
+			if ((addr[i] >> j) & 1) {
+				bits++;
+			}
+		}
+	}
+
+	return bits;
+}
+
 int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
 {
 	char *s = str;
diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c
index b4b7e9a9c21e00dae968d965a25ef8d9e3399de0..f52b4447d580bc0e7784f70a88626e2ace012ff6 100644
--- a/res/res_pjsip_endpoint_identifier_ip.c
+++ b/res/res_pjsip_endpoint_identifier_ip.c
@@ -372,7 +372,7 @@ static int cli_print_body(void *obj, void *arg, int flags)
 
 	ast_str_append(&context->output_buffer, 0, "%*s:  ",
 		CLI_INDENT_TO_SPACES(context->indent_level), "Identify");
-	ast_ha_join(ident->matches, &str);
+	ast_ha_join_cidr(ident->matches, &str);
 	ast_str_append(&context->output_buffer, 0, "%s\n", ast_str_buffer(str));
 
 	return 0;