Merge pull request #840 from Ansuel/pcre-kamailio
[feed/telephony.git] / net / kamailio / patches / 022-lcr-pcre2-migration.patch
diff --git a/net/kamailio/patches/022-lcr-pcre2-migration.patch b/net/kamailio/patches/022-lcr-pcre2-migration.patch
new file mode 100644 (file)
index 0000000..c894e3a
--- /dev/null
@@ -0,0 +1,508 @@
+From e3e2c41e8c46a13bad18dd40fd9e3540020dd5eb Mon Sep 17 00:00:00 2001
+From: Victor Seva <linuxmaniac@torreviejawireless.org>
+Date: Mon, 21 Aug 2023 13:30:36 +0200
+Subject: [PATCH] lcr: pcre2 migration
+
+---
+ src/modules/lcr/Makefile  |  12 +--
+ src/modules/lcr/hash.c    |  24 ++---
+ src/modules/lcr/hash.h    |  10 +-
+ src/modules/lcr/lcr_mod.c | 187 +++++++++++++++++++++++++-------------
+ src/modules/lcr/lcr_mod.h |   8 +-
+ 5 files changed, 150 insertions(+), 91 deletions(-)
+
+--- a/src/modules/lcr/Makefile
++++ b/src/modules/lcr/Makefile
+@@ -9,20 +9,15 @@ auto_gen=
+ NAME=lcr.so
+ ifeq ($(CROSS_COMPILE),)
+-PCRE_BUILDER = $(shell \
+-      if pkg-config --exists libcre; then \
+-              echo 'pkg-config libpcre'; \
+-      else \
+-              which pcre-config; \
+-      fi)
++PCRE_BUILDER = $(shell command -v pcre2-config)
+ endif
+ ifeq ($(PCRE_BUILDER),)
+       PCREDEFS=-I$(LOCALBASE)/include
+-      PCRELIBS=-L$(LOCALBASE)/lib -lpcre
++      PCRELIBS=-L$(LOCALBASE)/lib -lpcre2-8
+ else
+       PCREDEFS = $(shell $(PCRE_BUILDER) --cflags)
+-      PCRELIBS = $(shell $(PCRE_BUILDER) --libs)
++      PCRELIBS = $(shell $(PCRE_BUILDER) --libs8)
+ endif
+ DEFS+=$(PCREDEFS)
+@@ -31,4 +26,3 @@ LIBS+=$(PCRELIBS)
+ SERLIBPATH=../../lib
+ SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
+ include ../../Makefile.modules
+-
+--- a/src/modules/lcr/hash.c
++++ b/src/modules/lcr/hash.c
+@@ -15,8 +15,8 @@
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+- * You should have received a copy of the GNU General Public License 
+- * along with this program; if not, write to the Free Software 
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+  */
+@@ -36,10 +36,10 @@
+ /* Add lcr entry into hash table */
+ int rule_hash_table_insert(struct rule_info **hash_table, unsigned int lcr_id,
+               unsigned int rule_id, unsigned short prefix_len, char *prefix,
+-              unsigned short from_uri_len, char *from_uri, pcre *from_uri_re,
++              unsigned short from_uri_len, char *from_uri, pcre2_code *from_uri_re,
+               unsigned short mt_tvalue_len, char *mt_tvalue,
+-              unsigned short request_uri_len, char *request_uri, pcre *request_uri_re,
+-              unsigned short stopper)
++              unsigned short request_uri_len, char *request_uri,
++              pcre2_code *request_uri_re, unsigned short stopper)
+ {
+       struct rule_info *rule;
+       str prefix_str;
+@@ -50,9 +50,9 @@ int rule_hash_table_insert(struct rule_i
+       if(rule == NULL) {
+               SHM_MEM_ERROR_FMT("for rule hash table entry\n");
+               if(from_uri_re)
+-                      shm_free(from_uri_re);
++                      pcre2_code_free(from_uri_re);
+               if(request_uri_re)
+-                      shm_free(request_uri_re);
++                      pcre2_code_free(request_uri_re);
+               return 0;
+       }
+       memset(rule, 0, sizeof(struct rule_info));
+@@ -99,9 +99,9 @@ int rule_hash_table_insert(struct rule_i
+       if(rid == NULL) {
+               PKG_MEM_ERROR_FMT("for rule_id hash table entry\n");
+               if(from_uri_re)
+-                      shm_free(from_uri_re);
++                      pcre2_code_free(from_uri_re);
+               if(request_uri_re)
+-                      shm_free(request_uri_re);
++                      pcre2_code_free(request_uri_re);
+               shm_free(rule);
+               return 0;
+       }
+@@ -180,7 +180,7 @@ int rule_hash_table_insert_target(struct
+ }
+-/* 
++/*
+  * Return pointer to lcr hash table entry to which given prefix hashes to.
+  */
+ struct rule_info *rule_hash_table_lookup(
+@@ -209,10 +209,10 @@ void rule_hash_table_contents_free(struc
+               r = hash_table[i];
+               while(r) {
+                       if(r->from_uri_re) {
+-                              shm_free(r->from_uri_re);
++                              pcre2_code_free(r->from_uri_re);
+                       }
+                       if(r->request_uri_re)
+-                              shm_free(r->request_uri_re);
++                              pcre2_code_free(r->request_uri_re);
+                       t = r->targets;
+                       while(t) {
+                               next_t = t->next;
+--- a/src/modules/lcr/hash.h
++++ b/src/modules/lcr/hash.h
+@@ -15,8 +15,8 @@
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+- * You should have received a copy of the GNU General Public License 
+- * along with this program; if not, write to the Free Software 
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+  */
+@@ -34,10 +34,10 @@
+ int rule_hash_table_insert(struct rule_info **hash_table, unsigned int lcr_id,
+               unsigned int rule_id, unsigned short prefix_len, char *prefix,
+-              unsigned short from_uri_len, char *from_uri, pcre *from_uri_re,
++              unsigned short from_uri_len, char *from_uri, pcre2_code *from_uri_re,
+               unsigned short mt_tvalue_len, char *mt_tvalue,
+-              unsigned short request_uri_len, char *request_uri, pcre *request_uri_re,
+-              unsigned short stopper);
++              unsigned short request_uri_len, char *request_uri,
++              pcre2_code *request_uri_re, unsigned short stopper);
+ int rule_hash_table_insert_target(struct rule_info **hash_table,
+               struct gw_info *gws, unsigned int rule_id, unsigned int gw_id,
+--- a/src/modules/lcr/lcr_mod.c
++++ b/src/modules/lcr/lcr_mod.c
+@@ -16,8 +16,8 @@
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+- * You should have received a copy of the GNU General Public License 
+- * along with this program; if not, write to the Free Software 
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+  *
+  */
+@@ -43,7 +43,8 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <arpa/inet.h>
+-#include <pcre.h>
++#define PCRE2_CODE_UNIT_WIDTH 8
++#include <pcre2.h>
+ #include "../../core/locking.h"
+ #include "../../core/sr_module.h"
+ #include "../../core/dprint.h"
+@@ -204,6 +205,9 @@ static unsigned int priority_ordering_pa
+ /* mtree tree name */
+ str mtree_param = {"lcr", 3};
++static pcre2_general_context *lcr_gctx = NULL;
++static pcre2_compile_context *lcr_ctx = NULL;
++
+ /*
+  * Other module types and variables
+  */
+@@ -364,7 +368,7 @@ static param_export_t params[] = {
+  * Module interface
+  */
+ struct module_exports exports = {
+-      "lcr", 
++      "lcr",
+       DEFAULT_DLFLAGS, /* dlopen flags */
+       cmds,            /* Exported functions */
+       params,          /* Exported parameters */
+@@ -422,6 +426,16 @@ static void lcr_db_close(void)
+       }
+ }
++static void *pcre2_malloc(size_t size, void *ext)
++{
++      return shm_malloc(size);
++}
++
++static void pcre2_free(void *ptr, void *ext)
++{
++      shm_free(ptr);
++      ptr = NULL;
++}
+ /*
+  * Module initialization function that is called before the main process forks
+@@ -703,7 +717,15 @@ static int mod_init(void)
+       lcr_db_close();
+       /* rule shared memory */
+-
++      if((lcr_gctx = pcre2_general_context_create(pcre2_malloc, pcre2_free, NULL))
++                      == NULL) {
++              LM_ERR("pcre2 general context creation failed\n");
++              goto err;
++      }
++      if((lcr_ctx = pcre2_compile_context_create(lcr_gctx)) == NULL) {
++              LM_ERR("pcre2 compile context creation failed\n");
++              goto err;
++      }
+       /* rule hash table pointer table */
+       /* pointer at index 0 points to temp rule hash table */
+       rule_pt = (struct rule_info ***)shm_malloc(
+@@ -779,6 +801,12 @@ dberror:
+       lcr_db_close();
+ err:
++      if(lcr_ctx) {
++              pcre2_compile_context_free(lcr_ctx);
++      }
++      if(lcr_gctx) {
++              pcre2_general_context_free(lcr_gctx);
++      }
+       free_shared_memory();
+       return -1;
+ }
+@@ -794,7 +822,12 @@ static int child_init(int rank)
+ static void destroy(void)
+ {
+       lcr_db_close();
+-
++      if(lcr_ctx) {
++              pcre2_compile_context_free(lcr_ctx);
++      }
++      if(lcr_gctx) {
++              pcre2_general_context_free(lcr_gctx);
++      }
+       free_shared_memory();
+ }
+@@ -875,33 +908,32 @@ static int comp_matched(const void *m1,
+ /* Compile pattern into shared memory and return pointer to it. */
+-static pcre *reg_ex_comp(const char *pattern)
++static pcre2_code *reg_ex_comp(const char *pattern)
+ {
+-      pcre *re, *result;
+-      const char *error;
+-      int rc, err_offset;
+-      size_t size;
+-
+-      re = pcre_compile(pattern, 0, &error, &err_offset, NULL);
+-      if(re == NULL) {
+-              LM_ERR("pcre compilation of '%s' failed at offset %d: %s\n", pattern,
+-                              err_offset, error);
+-              return (pcre *)0;
+-      }
+-      rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size);
+-      if(rc != 0) {
+-              LM_ERR("pcre_fullinfo on compiled pattern '%s' yielded error: %d\n",
+-                              pattern, rc);
+-              return (pcre *)0;
+-      }
+-      result = (pcre *)shm_malloc(size);
++      pcre2_code *result;
++      int pcre_error_num = 0;
++      char pcre_error[128];
++      size_t pcre_erroffset;
++
++      result = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, 0,
++                      &pcre_error_num, &pcre_erroffset, lcr_ctx);
+       if(result == NULL) {
+-              pcre_free(re);
+-              SHM_MEM_ERROR_FMT("for compiled PCRE pattern\n");
+-              return (pcre *)0;
++              switch(pcre2_get_error_message(
++                              pcre_error_num, (PCRE2_UCHAR *)pcre_error, 128)) {
++                      case PCRE2_ERROR_NOMEMORY:
++                              snprintf(pcre_error, 128,
++                                              "unknown error[%d]: pcre2 error buffer too small",
++                                              pcre_error_num);
++                              break;
++                      case PCRE2_ERROR_BADDATA:
++                              snprintf(pcre_error, 128, "unknown pcre2 error[%d]",
++                                              pcre_error_num);
++                              break;
++              }
++              LM_ERR("pcre compilation of '%s' failed at offset %zu: %s\n", pattern,
++                              pcre_erroffset, pcre_error);
++              return NULL;
+       }
+-      memcpy(result, re, size);
+-      pcre_free(re);
+       return result;
+ }
+@@ -950,7 +982,7 @@ static struct gw_info *find_gateway_by_i
+       return NULL;
+ }
+-/* 
++/*
+  * Insert gw info into index i or gws table
+  */
+ static int insert_gw(struct gw_info *gws, unsigned int i, unsigned int gw_id,
+@@ -1024,7 +1056,7 @@ static int insert_gw(struct gw_info *gws
+ /*
+- * Insert prefix_len into list pointed by last rule hash table entry 
++ * Insert prefix_len into list pointed by last rule hash table entry
+  * if not there already. Keep list in decending prefix_len order.
+  */
+ static int prefix_len_insert(
+@@ -1414,7 +1446,7 @@ int reload_tables()
+       db_key_t gw_cols[13];
+       db_key_t rule_cols[7];
+       db_key_t target_cols[4];
+-      pcre *from_uri_re, *request_uri_re;
++      pcre2_code *from_uri_re, *request_uri_re;
+       struct gw_info *gws, *gw_pt_tmp;
+       struct rule_info **rules, **rule_pt_tmp;
+@@ -2129,11 +2161,12 @@ void add_gws_into_avps(struct gw_info *g
+ int load_gws_dummy(int lcr_id, str *ruri_user, str *from_uri, str *request_uri,
+               unsigned int *gw_indexes)
+ {
+-      int i, j;
++      int i, j, rc;
+       unsigned int gw_index, now, dex;
+       struct rule_info **rules, *rule, *pl;
+       struct gw_info *gws;
+       struct target *t;
++      pcre2_match_data *pcre_md = NULL;
+       struct matched_gw_info matched_gws[MAX_NO_OF_GWS + 1];
+       struct sip_uri furi;
+       struct usr_avp *avp;
+@@ -2178,12 +2211,18 @@ int load_gws_dummy(int lcr_id, str *ruri
+                                       || strncmp(rule->prefix, ruri_user->s, pl->prefix_len))
+                               goto next;
+-                      if((rule->from_uri_len != 0)
+-                                      && (pcre_exec(rule->from_uri_re, NULL, from_uri->s,
+-                                                              from_uri->len, 0, 0, NULL, 0)
+-                                                      < 0))
+-                              goto next;
+-
++                      if(rule->from_uri_len != 0) {
++                              pcre_md = pcre2_match_data_create_from_pattern(
++                                              rule->from_uri_re, NULL);
++                              rc = pcre2_match(rule->from_uri_re, (PCRE2_SPTR)from_uri->s,
++                                              (PCRE2_SIZE)from_uri->len, 0, 0, pcre_md, NULL);
++                              if(pcre_md) {
++                                      pcre2_match_data_free(pcre_md);
++                                      pcre_md = NULL;
++                              }
++                              if(rc < 0)
++                                      goto next;
++                      }
+                       if((from_uri->len > 0) && (rule->mt_tvalue_len > 0)) {
+                               if(mtree_api.mt_match(&msg, &mtree_param, &(furi.user), 2)
+                                               == -1) {
+@@ -2216,9 +2255,16 @@ int load_gws_dummy(int lcr_id, str *ruri
+                                                  "param has not been given.\n");
+                                       return -1;
+                               }
+-                              if(pcre_exec(rule->request_uri_re, NULL, request_uri->s,
+-                                                 request_uri->len, 0, 0, NULL, 0)
+-                                              < 0)
++                              pcre_md = pcre2_match_data_create_from_pattern(
++                                              rule->request_uri_re, NULL);
++                              rc = pcre2_match(rule->request_uri_re,
++                                              (PCRE2_SPTR)request_uri->s,
++                                              (PCRE2_SIZE)request_uri->len, 0, 0, pcre_md, NULL);
++                              if(pcre_md) {
++                                      pcre2_match_data_free(pcre_md);
++                                      pcre_md = NULL;
++                              }
++                              if(rc < 0)
+                                       goto next;
+                       }
+@@ -2282,9 +2328,10 @@ static int ki_load_gws_furi(
+               sip_msg_t *_m, int lcr_id, str *ruri_user, str *from_uri)
+ {
+       str *request_uri;
+-      int i, j;
++      int i, j, rc;
+       unsigned int gw_index, now, dex;
+       int_str val;
++      pcre2_match_data *pcre_md = NULL;
+       struct matched_gw_info matched_gws[MAX_NO_OF_GWS + 1];
+       struct rule_info **rules, *rule, *pl;
+       struct gw_info *gws;
+@@ -2343,14 +2390,22 @@ static int ki_load_gws_furi(
+                               goto next;
+                       /* Match from uri */
+-                      if((rule->from_uri_len != 0)
+-                                      && (pcre_exec(rule->from_uri_re, NULL, from_uri->s,
+-                                                              from_uri->len, 0, 0, NULL, 0)
+-                                                      < 0)) {
+-                              LM_DBG("from uri <%.*s> did not match to from regex <%.*s>\n",
+-                                              from_uri->len, from_uri->s, rule->from_uri_len,
+-                                              rule->from_uri);
+-                              goto next;
++                      if(rule->from_uri_len != 0) {
++                              pcre_md = pcre2_match_data_create_from_pattern(
++                                              rule->from_uri_re, NULL);
++                              rc = pcre2_match(rule->from_uri_re, (PCRE2_SPTR)from_uri->s,
++                                              (PCRE2_SIZE)from_uri->len, 0, 0, pcre_md, NULL);
++                              if(pcre_md) {
++                                      pcre2_match_data_free(pcre_md);
++                                      pcre_md = NULL;
++                              }
++                              if(rc < 0) {
++                                      LM_DBG("from uri <%.*s> did not match to from regex "
++                                                 "<%.*s>\n",
++                                                      from_uri->len, from_uri->s, rule->from_uri_len,
++                                                      rule->from_uri);
++                                      goto next;
++                              }
+                       }
+                       /* Match from uri user */
+@@ -2379,15 +2434,23 @@ static int ki_load_gws_furi(
+                       }
+                       /* Match request uri */
+-                      if((rule->request_uri_len != 0)
+-                                      && (pcre_exec(rule->request_uri_re, NULL, request_uri->s,
+-                                                              request_uri->len, 0, 0, NULL, 0)
+-                                                      < 0)) {
+-                              LM_DBG("request uri <%.*s> did not match to request regex "
+-                                         "<%.*s>\n",
+-                                              request_uri->len, request_uri->s, rule->request_uri_len,
+-                                              rule->request_uri);
+-                              goto next;
++                      if(rule->request_uri_len != 0) {
++                              pcre_md = pcre2_match_data_create_from_pattern(
++                                              rule->request_uri_re, NULL);
++                              rc = pcre2_match(rule->request_uri_re,
++                                              (PCRE2_SPTR)request_uri->s,
++                                              (PCRE2_SIZE)request_uri->len, 0, 0, pcre_md, NULL);
++                              if(pcre_md) {
++                                      pcre2_match_data_free(pcre_md);
++                                      pcre_md = NULL;
++                              }
++                              if(rc < 0) {
++                                      LM_DBG("request uri <%.*s> did not match to request regex "
++                                                 "<%.*s>\n",
++                                                      request_uri->len, request_uri->s,
++                                                      rule->request_uri_len, rule->request_uri);
++                                      goto next;
++                              }
+                       }
+                       /* Load gws associated with this rule */
+@@ -3015,7 +3078,7 @@ static int ki_next_gw(sip_msg_t *_m)
+ }
+ /**
+- * 
++ *
+  */
+ static int next_gw(struct sip_msg *_m, char *_s1, char *_s2)
+ {
+--- a/src/modules/lcr/lcr_mod.h
++++ b/src/modules/lcr/lcr_mod.h
+@@ -2,6 +2,7 @@
+  * Various lcr related constant, types, and external variables
+  *
+  * Copyright (C) 2005-2014 Juha Heinanen
++ * Copyright (C) 2023 Victor Seva
+  *
+  * This file is part of Kamailio, a free SIP server.
+  *
+@@ -33,7 +34,8 @@
+ #define LCR_MOD_H
+ #include <stdio.h>
+-#include <pcre.h>
++#define PCRE2_CODE_UNIT_WIDTH 8
++#include <pcre2.h>
+ #include "../../core/locking.h"
+ #include "../../core/parser/parse_uri.h"
+ #include "../../core/ip_addr.h"
+@@ -60,10 +62,10 @@ struct rule_info
+       unsigned short from_uri_len;
+       char mt_tvalue[MAX_MT_TVALUE_LEN + 1];
+       unsigned short mt_tvalue_len;
+-      pcre *from_uri_re;
++      pcre2_code *from_uri_re;
+       char request_uri[MAX_URI_LEN + 1];
+       unsigned short request_uri_len;
+-      pcre *request_uri_re;
++      pcre2_code *request_uri_re;
+       unsigned short stopper;
+       unsigned int enabled;
+       struct target *targets;