You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/debian/patches/sipwise/add_tcap_module.patch

450 lines
11 KiB

From: Sipwise Development Team <support@sipwise.com>
Date: Thu, 26 Mar 2020 10:06:46 +0100
Subject: add_tcap_module
---
src/Makefile.groups | 6 +
src/modules/tcap/Makefile | 9 +
src/modules/tcap/tcap_mod.c | 392 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 407 insertions(+)
create mode 100644 src/modules/tcap/Makefile
create mode 100644 src/modules/tcap/tcap_mod.c
diff --git a/src/Makefile.groups b/src/Makefile.groups
index 955fbec..912f126 100644
--- a/src/Makefile.groups
+++ b/src/Makefile.groups
@@ -214,6 +214,9 @@ mod_list_erlang=erlang
# - modules depending on systemd library
mod_list_systemd=log_systemd systemdops
+# - modules depending on libtcap library
+mod_list_tcap=tcap
+
# - modules depending on libnsq (+libev libevbuffsock libcurl libjson-c) library
mod_list_nsq=nsq
@@ -353,6 +356,9 @@ module_group_ignore= $(sort $(filter-out $(module_group_default), $(mod_list_all
# pkg lcrrate module
module_group_klcrrate=$(mod_list_lcrrate)
+# pkg tap module
+module_group_ktcap=$(mod_list_tcap)
+
### --- Groups defined for pacKaging ###
# Standard modules in main pkg
diff --git a/src/modules/tcap/Makefile b/src/modules/tcap/Makefile
new file mode 100644
index 0000000..d1e7b4d
--- /dev/null
+++ b/src/modules/tcap/Makefile
@@ -0,0 +1,9 @@
+include ../../Makefile.defs
+auto_gen=
+NAME=tcap.so
+
+DEFS+=-D_GNU_SOURCE
+DEFS+=-I/usr/include/tcap
+LIBS+=-ltcap
+
+include ../../Makefile.modules
diff --git a/src/modules/tcap/tcap_mod.c b/src/modules/tcap/tcap_mod.c
new file mode 100644
index 0000000..79e736d
--- /dev/null
+++ b/src/modules/tcap/tcap_mod.c
@@ -0,0 +1,392 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <tcap/libtcap.h>
+#include "../../core/sr_module.h"
+#include "../../core/mod_fix.h"
+#include "../../core/pvar.h"
+#include "../../core/parser/parse_content.h"
+#include "../../core/lvalue.h"
+
+MODULE_VERSION
+
+
+
+static str content_type;
+static int strip_trailing_crlf;
+
+
+
+static int mod_init(void);
+static int tcap_extract_f(sip_msg_t *msg, char *su, char *sq);
+static int tcap_extract_var_f(sip_msg_t *msg, char *o, char *f, char *d);
+static int inap_extract_f(sip_msg_t *msg, char *su, char *sq);
+static int inap_extract_var_f(sip_msg_t *msg, char *o, char *f, char *d);
+static int isup_decode_number_f(sip_msg_t *msg, char *su, char *sq);
+static int isup_decode_number_hex_f(sip_msg_t *msg, char *su, char *sq);
+
+
+
+static cmd_export_t cmds[] = {
+ {"tcap_extract", (cmd_function)tcap_extract_f, 2,
+ fixup_spve_str, 0, ANY_ROUTE},
+ {"tcap_extract_var", (cmd_function)tcap_extract_var_f, 3,
+ fixup_pvar_pvar_pvar, fixup_free_pvar_pvar_pvar, ANY_ROUTE},
+ {"inap_extract", (cmd_function)inap_extract_f, 2,
+ fixup_spve_str, 0, ANY_ROUTE},
+ {"inap_extract_var", (cmd_function)inap_extract_var_f, 3,
+ fixup_pvar_pvar_pvar, fixup_free_pvar_pvar_pvar, ANY_ROUTE},
+ {"isup_decode_number", (cmd_function)isup_decode_number_f, 2,
+ fixup_spve_str, 0, ANY_ROUTE},
+ {"isup_decode_number_hex", (cmd_function)isup_decode_number_hex_f, 2,
+ fixup_spve_str, 0, ANY_ROUTE},
+ {0,}
+};
+
+
+
+static param_export_t params[] = {
+ { "content_type", STR_PARAM, &content_type.s },
+ { "strip_trailing_crlf", INT_PARAM, &strip_trailing_crlf },
+ { 0, }
+};
+
+
+struct module_exports exports = {
+ "tcap", /* module name */
+ DEFAULT_DLFLAGS, /* dlopen flags */
+ cmds, /* exported functions */
+ params, /* exported parameters */
+ 0, /* RPC method exports */
+ 0, /* exported pseudo-variables */
+ 0, /* response handling function */
+ mod_init, /* module initialization function */
+ 0, /* per-child init function */
+ 0 /* module destroy function */
+};
+
+
+
+static int mod_init(void) {
+ if (!content_type.s)
+ content_type.s = "application/tcap";
+ content_type.len = strlen(content_type.s);
+
+ return 0;
+}
+
+
+
+static int prepare_extract(sip_msg_t *msg, char *su, str *body, str *spec) {
+ const char *err;
+
+ err = "Error fixing up first parameter";
+ if (fixup_get_svalue(msg, (gparam_p) su, spec))
+ goto error;
+
+ err = "No SIP body found";
+ body->s = get_body(msg);
+ if (!body->s)
+ goto error;
+ err = "No Content-Length found or zero length body";
+ body->len = get_content_length(msg);
+ if (!body->len)
+ goto error;
+
+ if (strip_trailing_crlf
+ && body->len >= 2
+ && body->s[body->len - 1] == '\n'
+ && body->s[body->len - 2] == '\r')
+ body->len -= 2;
+
+ err = "No Content-Type found";
+ if (!msg->content_type)
+ goto error;
+ err = "Content-Type mismatch";
+ if (msg->content_type->body.len < content_type.len)
+ goto error;
+ if (strncasecmp(msg->content_type->body.s, content_type.s, content_type.len))
+ goto error;
+
+ return 0;
+error:
+ LM_ERR("%s\n", err);
+ return -1;
+}
+
+static int copy_output(sip_msg_t *msg, char *sq, char *outbuf, int outlen) {
+ const char *err;
+ pv_spec_t *avp_spec = NULL;
+ str *s;
+ pv_value_t avp_val;
+
+ s = (str *) sq;
+ err = "Malformed AVP definition";
+ if (!(avp_spec = pv_cache_get(s)))
+ goto error;
+ switch (avp_spec->type) {
+ case PVT_AVP:
+ case PVT_XAVP:
+ case PVT_SCRIPTVAR:
+ break;
+ default:
+ goto error;
+ }
+
+ memset(&avp_val, 0, sizeof(avp_val));
+ avp_val.flags = PV_VAL_STR;
+ avp_val.rs.s = outbuf;
+ avp_val.rs.len = outlen;
+ err = "Failed to set return AVP";
+ if (avp_spec->setf(msg, &avp_spec->pvp, EQ_T, &avp_val) < 0)
+ goto error;
+
+ return 0;
+error:
+ LM_ERR("%s\n", err);
+ return -1;
+
+}
+
+static int tcap_extract_f(sip_msg_t *msg, char *su, char *sq) {
+ const char *err;
+ static char buf[1024];
+ struct output_buffer out;
+ str body, spec;
+
+ if (prepare_extract(msg, su, &body, &spec))
+ return -1;
+
+ OUTPUT_BUFFER_INIT(&out, buf);
+ err = "Error parsing TCAP body";
+ if (tcap_extract(body.s, body.len, spec.s, &out))
+ goto error;
+
+ if (copy_output(msg, sq, out.buf, out.used))
+ return -1;
+
+ return 1;
+error:
+ LM_ERR("%s\n", err);
+ return -1;
+}
+
+static int inap_extract_f(sip_msg_t *msg, char *su, char *sq) {
+ const char *err;
+ static char buf[1024];
+ struct output_buffer out;
+ str body, spec;
+
+ if (prepare_extract(msg, su, &body, &spec))
+ return -1;
+
+ OUTPUT_BUFFER_INIT(&out, buf);
+ err = "Error parsing TCAP body";
+ if (inap_extract(body.s, body.len, spec.s, &out))
+ goto error;
+
+ if (copy_output(msg, sq, out.buf, out.used))
+ return -1;
+
+ return 1;
+error:
+ LM_ERR("%s\n", err);
+ return -1;
+}
+
+/**
+ * our own decode.hexa
+ * We had problems passing binary string through pvars after
+ * string transformation s.decode.hexa
+ */
+static int _tcap_decode_hexa(str *in, char **out)
+{
+ int i;
+ static char buf[1024];
+ if(in->len/2>1024){
+ LM_ERR("bin string greater than max buffer\n");
+ return -1;
+ }
+ if(!out) return -1;
+ *out = NULL;
+
+ for(i=0; i<in->len/2; i++)
+ {
+ if(in->s[2*i]>='0'&&in->s[2*i]<='9')
+ buf[i] = (in->s[2*i]-'0') << 4;
+ else if(in->s[2*i]>='a'&&in->s[2*i]<='f')
+ buf[i] = (in->s[2*i]-'a'+10) << 4;
+ else if(in->s[2*i]>='A'&&in->s[2*i]<='F')
+ buf[i] = (in->s[2*i]-'A'+10) << 4;
+ else return -1;
+
+ if(in->s[2*i+1]>='0'&&in->s[2*i+1]<='9')
+ buf[i] += in->s[2*i+1]-'0';
+ else if(in->s[2*i+1]>='a'&&in->s[2*i+1]<='f')
+ buf[i] += in->s[2*i+1]-'a'+10;
+ else if(in->s[2*i+1]>='A'&&in->s[2*i+1]<='F')
+ buf[i] += in->s[2*i+1]-'A'+10;
+ else return -1;
+ }
+ buf[i] = '\0';
+ *out = buf;
+ return i;
+}
+
+static int tcap_extract_var_f(sip_msg_t *msg, char *pv_orig, char *pv_field,
+ char *pv_dest)
+{
+ const char *err;
+ char *bin;
+ int bin_len;
+ static char buf[1024];
+ static char cfield[512];
+ struct output_buffer out;
+ pv_spec_p orig_spec = (pv_spec_t *) pv_orig;
+ pv_spec_p field_spec = (pv_spec_t *) pv_field;
+ pv_spec_p dest_spec = (pv_spec_t *) pv_dest;
+ pv_value_t tcap, field, dest;
+
+ err = "Can't get tcap PV value";
+ if (pv_get_spec_value(msg, orig_spec, &tcap) != 0)
+ goto error;
+
+ err = "orig has to be a string";
+ if(!(tcap.flags&PV_VAL_STR))
+ goto error;
+
+ err = "Can't get field PV value";
+ if (pv_get_spec_value(msg, field_spec, &field) != 0)
+ goto error;
+
+ err = "field has to be a string";
+ if (!(field.flags&PV_VAL_STR))
+ goto error;
+
+ err = "field is too big for internal buffer";
+ if (field.rs.len > 512)
+ goto error;
+ strncpy(cfield, field.rs.s, field.rs.len);
+ cfield[field.rs.len] = '\0';
+
+ err = "Can't decode.hexa";
+ bin_len = _tcap_decode_hexa(&(tcap.rs), &bin);
+ if(bin<=0)
+ goto error;
+
+ OUTPUT_BUFFER_INIT(&out, buf);
+ LM_DBG("tcap:[%.*s][%d] bin:[%.*s] field:[%s]\n", tcap.rs.len, tcap.rs.s,
+ tcap.rs.len, bin_len, bin, cfield);
+
+ err = "Error parsing TCAP body";
+ if (tcap_extract(bin, bin_len, cfield, &out)<0)
+ goto error;
+
+ memset(&dest, 0, sizeof(pv_value_t));
+ dest.flags = PV_VAL_STR;
+ dest.rs.s = out.buf;
+ dest.rs.len = out.used;
+ err = "Failed to set return value";
+ if(pv_set_spec_value(msg, dest_spec, 0, &dest)<0)
+ goto error;
+
+ return 1;
+error:
+ LM_ERR("%s\n", err);
+ return -1;
+}
+
+static int inap_extract_var_f(sip_msg_t *msg, char *pv_orig, char *pv_field,
+ char *pv_dest)
+{
+ const char *err;
+ char *bin;
+ int bin_len;
+ static char buf[1024];
+ static char cfield[512];
+ struct output_buffer out;
+ pv_spec_p orig_spec = (pv_spec_t *) pv_orig;
+ pv_spec_p field_spec = (pv_spec_t *) pv_field;
+ pv_spec_p dest_spec = (pv_spec_t *) pv_dest;
+ pv_value_t tcap, field, dest;
+
+ err = "Can't get tcap PV value";
+ if (pv_get_spec_value(msg, orig_spec, &tcap) != 0)
+ goto error;
+
+ err = "orig has to be a string";
+ if(!(tcap.flags&PV_VAL_STR))
+ goto error;
+
+ err = "Can't get field PV value";
+ if (pv_get_spec_value(msg, field_spec, &field) != 0)
+ goto error;
+
+ err = "field has to be a string";
+ if (!(field.flags&PV_VAL_STR))
+ goto error;
+
+ err = "field is too big for internal buffer";
+ if (field.rs.len > 512)
+ goto error;
+ strncpy(cfield, field.rs.s, field.rs.len);
+ cfield[field.rs.len] = '\0';
+
+ err = "Can't decode.hexa";
+ bin_len = _tcap_decode_hexa(&(tcap.rs), &bin);
+ if(bin<=0)
+ goto error;
+
+ OUTPUT_BUFFER_INIT(&out, buf);
+ LM_DBG("tcap:[%.*s][%d] bin:[%.*s] field:[%s]\n", tcap.rs.len, tcap.rs.s,
+ tcap.rs.len, bin_len, bin, cfield);
+
+ err = "Error parsing TCAP body";
+ if (inap_extract(bin, bin_len, cfield, &out)<0)
+ goto error;
+
+ memset(&dest, 0, sizeof(pv_value_t));
+ dest.flags = PV_VAL_STR;
+ dest.rs.s = out.buf;
+ dest.rs.len = out.used;
+ err = "Failed to set return value";
+ if(pv_set_spec_value(msg, dest_spec, 0, &dest)<0)
+ goto error;
+
+ return 1;
+error:
+ LM_ERR("%s\n", err);
+ return -1;
+}
+
+static int isup_decode_number_common_f(sip_msg_t *msg, char *su, char *sq,
+ int (*func)(const char *, int, char *))
+{
+ const char *err;
+ str inp;
+ char num[64];
+
+ err = "Error fixing up first parameter";
+ if (fixup_get_svalue(msg, (gparam_p) su, &inp))
+ goto error;
+ err = "Invalid encoded number";
+ if (func(inp.s, inp.len, num))
+ goto error;
+
+ if (copy_output(msg, sq, num, strlen(num)))
+ return -1;
+
+ return 1;
+
+error:
+ LM_ERR("%s\n", err);
+ return -1;
+}
+
+static int isup_decode_number_f(sip_msg_t *msg, char *su, char *sq) {
+ return isup_decode_number_common_f(msg, su, sq, isup_convert_number);
+}
+static int isup_decode_number_hex_f(sip_msg_t *msg, char *su, char *sq) {
+ return isup_decode_number_common_f(msg, su, sq, isup_convert_number_hex);
+}