- new plugin_regex: apply an extended regular expression

to the SIP 'To' URI and rewrite the target (outgoing
  calls only)
This commit is contained in:
Thomas Ries 2011-06-19 15:37:55 +00:00
parent dd94e02127
commit 08d3eabe7e
3 changed files with 92 additions and 49 deletions

View File

@ -1,5 +1,8 @@
0.8.1 0.8.1
===== =====
19-Jun-2011: - new plugin_regex: apply an extended regular expression
to the SIP 'To' URI and rewrite the target (outgoing
calls only)
17-Jun-2011: - plugin_prefix: correct handling of outgoing ACKs 17-Jun-2011: - plugin_prefix: correct handling of outgoing ACKs
(could lead to calls being aborted by one side) (could lead to calls being aborted by one side)
- generic set of "redirect cache" that can be used by - generic set of "redirect cache" that can be used by

View File

@ -91,8 +91,6 @@ user = nobody
# If you don't know what I'm saying above, do not enable this setting! # If you don't know what I'm saying above, do not enable this setting!
# USE AT YOUR OWN RISK! # USE AT YOUR OWN RISK!
# Too small stack size may lead to unexplainable crashes! # Too small stack size may lead to unexplainable crashes!
# Improper use may make siproxd eat your dog and vandalize
# your garden.
#thread_stack_size = 512 #thread_stack_size = 512
###################################################################### ######################################################################
@ -335,6 +333,7 @@ load_plugin=plugin_logcall.la
#load_plugin=plugin_fix_bogus_via.la #load_plugin=plugin_fix_bogus_via.la
#load_plugin=plugin_stun.la #load_plugin=plugin_stun.la
#load_plugin=plugin_prefix.la #load_plugin=plugin_prefix.la
#load_plugin=plugin_regex.la
###################################################################### ######################################################################
@ -394,10 +393,31 @@ plugin_stun_port = 3478
# period in seconds to request IP info from STUN server # period in seconds to request IP info from STUN server
plugin_stun_period = 300 plugin_stun_period = 300
###################################################################### ######################################################################
# Plugin_prefix # Plugin_prefix
# #
# unconditionally prefixes all outgoing calls with the # unconditionally prefixes all outgoing calls with the
# "akey" prefix specified below. # "akey" prefix specified below.
plugin_prefix_akey = 0 plugin_prefix_akey = 0
######################################################################
# Plugin_regex
#
# Applies an extended regular expression to the 'To' URI. A typical
# SIP URI looks like (port number is optional):
# sip:12345@some.provider.net
# sips:12345@some.provider.net:5061
#
# Backreferences \1 .. \9 are supported.
#
plugin_regex_desc = Test Regex 1
plugin_regex_pattern = ^sip:00
plugin_regex_replace = +
plugin_regex_desc = Test Regex 2
plugin_regex_pattern = ^sip:01
plugin_regex_replace = +a
plugin_regex_desc = Test Regex 3
plugin_regex_pattern = ^(sips?):01
plugin_regex_replace = \1:001

View File

@ -60,12 +60,14 @@ extern struct siproxd_config configuration;
/* plugin configuration storage */ /* plugin configuration storage */
static struct plugin_config { static struct plugin_config {
stringa_t regex_desc;
stringa_t regex_pattern; stringa_t regex_pattern;
stringa_t regex_replace; stringa_t regex_replace;
} plugin_cfg; } plugin_cfg;
/* Instructions for config parser */ /* Instructions for config parser */
static cfgopts_t plugin_cfg_opts[] = { static cfgopts_t plugin_cfg_opts[] = {
{ "plugin_regex_desc", TYP_STRINGA,&plugin_cfg.regex_desc, {0, NULL} },
{ "plugin_regex_pattern", TYP_STRINGA,&plugin_cfg.regex_pattern, {0, NULL} }, { "plugin_regex_pattern", TYP_STRINGA,&plugin_cfg.regex_pattern, {0, NULL} },
{ "plugin_regex_replace", TYP_STRINGA,&plugin_cfg.regex_replace, {0, NULL} }, { "plugin_regex_replace", TYP_STRINGA,&plugin_cfg.regex_replace, {0, NULL} },
{0, 0, 0} {0, 0, 0}
@ -103,7 +105,7 @@ int PLUGIN_INIT(plugin_def_t *plugin_def) {
return STS_FAILURE; return STS_FAILURE;
} }
return plugin_regex_init();; return plugin_regex_init();
} }
/* Processing */ /* Processing */
@ -138,11 +140,19 @@ int plugin_regex_init(void) {
return STS_FAILURE; return STS_FAILURE;
} }
if (plugin_cfg.regex_pattern.used != plugin_cfg.regex_desc.used) {
ERROR("Plugin '%s': number of search patterns (%i) and number of "
"descriptions (%i) differ!", name,
plugin_cfg.regex_pattern.used, plugin_cfg.regex_desc.used);
return STS_FAILURE;
}
/* allocate space for regexes and compile them */ /* allocate space for regexes and compile them */
num_entries = plugin_cfg.regex_pattern.used; num_entries = plugin_cfg.regex_pattern.used;
re = malloc(num_entries*sizeof(re[0])); re = malloc(num_entries*sizeof(re[0]));
for (i=0; i < num_entries; i++) { for (i=0; i < num_entries; i++) {
sts = regcomp (&re[i], plugin_cfg.regex_pattern.string[i], REG_ICASE); sts = regcomp (&re[i], plugin_cfg.regex_pattern.string[i],
REG_ICASE|REG_EXTENDED);
if (sts != 0) { if (sts != 0) {
regerror(sts, &re[i], errbuf, sizeof(errbuf)); regerror(sts, &re[i], errbuf, sizeof(errbuf));
ERROR("Regular expression [%s] failed to compile: %s", ERROR("Regular expression [%s] failed to compile: %s",
@ -240,56 +250,67 @@ static int plugin_regex_process(sip_ticket_t *ticket) {
/* private plugin code */ /* private plugin code */
static int plugin_regex_redirect(sip_ticket_t *ticket) { static int plugin_regex_redirect(sip_ticket_t *ticket) {
osip_uri_t *to_url=ticket->sipmsg->to->url; osip_uri_t *to_url=ticket->sipmsg->to->url;
char *to_user=to_url->username; char *url_string=NULL;
char *new_to_user=NULL; osip_uri_t *new_to_url;
int i, sts; int i, sts;
size_t username_len;
osip_contact_t *contact = NULL; osip_contact_t *contact = NULL;
/* character workspaces for regex */ /* character workspaces for regex */
#define WORKSPACE_SIZE 128 #define WORKSPACE_SIZE 128
static char in[WORKSPACE_SIZE+1], rp[WORKSPACE_SIZE+1]; static char in[WORKSPACE_SIZE+1], rp[WORKSPACE_SIZE+1];
/* perform search and replace of the regexes, first match hits */ /* do apply to full To URI... */
for (i = 0; i < plugin_cfg.regex_pattern.used; i++) { sts = osip_uri_to_str(to_url, &url_string);
regmatch_t *pmatch = NULL; if (sts != 0) {
pmatch = rmatch(to_user, WORKSPACE_SIZE, &re[i]); ERROR("osip_uri_to_str() failed");
if (pmatch == NULL) continue; /* no match, next */
/* have a match, do the replacement */
strncpy (in, to_user, WORKSPACE_SIZE);
in[WORKSPACE_SIZE]='\0';
strncpy (rp, plugin_cfg.regex_replace.string[i], WORKSPACE_SIZE);
rp[WORKSPACE_SIZE]='\0';
sts = rreplace(in, WORKSPACE_SIZE, &re[i], pmatch, rp);
if (sts != STS_SUCCESS) {
ERROR("regex replace failed: pattern:[%s] replace:[%s]",
plugin_cfg.regex_pattern.string[i],
plugin_cfg.regex_replace.string[i]);
return STS_FAILURE; return STS_FAILURE;
} }
break; DEBUGC(DBCLASS_BABBLE, "To URI string: [%s]", url_string);
}
if (i >= plugin_cfg.regex_pattern.used) {
// no match
return STS_SUCCESS;
}
// in: contains the new string /* perform search and replace of the regexes, first match hits */
for (i = 0; i < plugin_cfg.regex_pattern.used; i++) {
regmatch_t *pmatch = NULL;
pmatch = rmatch(url_string, WORKSPACE_SIZE, &re[i]);
if (pmatch == NULL) continue; /* no match, next */
/* including \0 + leading character(s) */ /* have a match, do the replacement */
username_len=strlen(in) + 1; INFO("Matched rexec rule: %s",plugin_cfg.regex_desc.string[i] );
strncpy (in, url_string, WORKSPACE_SIZE);
new_to_user = osip_malloc(username_len); /* *_len excluding \0 */ in[WORKSPACE_SIZE]='\0';
if (!new_to_user) return STS_SUCCESS; strncpy (rp, plugin_cfg.regex_replace.string[i], WORKSPACE_SIZE);
rp[WORKSPACE_SIZE]='\0';
/* only copy the part that really belongs to the username */
snprintf(new_to_user, username_len, "%s", in );
/* strncpy may not terminate - do it manually to be sure */
new_to_user[username_len-1]='\0';
sts = rreplace(in, WORKSPACE_SIZE, &re[i], pmatch, rp);
if (sts != STS_SUCCESS) {
ERROR("regex replace failed: pattern:[%s] replace:[%s]",
plugin_cfg.regex_pattern.string[i],
plugin_cfg.regex_replace.string[i]);
osip_free(url_string);
return STS_FAILURE;
}
/* only do first match */
break;
}
if (i >= plugin_cfg.regex_pattern.used) {
/* no match */
osip_free(url_string);
return STS_SUCCESS;
}
/* in: contains the new string */
sts = osip_uri_init(&new_to_url);
if (sts != 0) {
ERROR("Unable to initialize URI");
osip_free(url_string);
return STS_FAILURE;
}
sts = osip_uri_parse(new_to_url, in);
if (sts != 0) {
ERROR("Unable to parse To URI: %s", in);
osip_uri_free(new_to_url);
osip_free(url_string);
return STS_FAILURE;
}
/* use a "302 Moved temporarily" response back to the client */ /* use a "302 Moved temporarily" response back to the client */
/* new target is within the Contact Header */ /* new target is within the Contact Header */
@ -305,12 +326,11 @@ if (i >= plugin_cfg.regex_pattern.used) {
/* insert one new Contact header containing the new target address */ /* insert one new Contact header containing the new target address */
osip_contact_init(&contact); osip_contact_init(&contact);
osip_uri_clone(to_url, &contact->url);
osip_list_add(&(ticket->sipmsg->contacts),contact,0); osip_list_add(&(ticket->sipmsg->contacts),contact,0);
/* USER part is always present, put new_to_user in contact URL */ /* link the new_to_url into the Contact list */
osip_free(contact->url->username); contact->url = new_to_url;
contact->url->username=new_to_user; new_to_url = NULL;
/* /*
* Add the 'REDIRECTED_TAG=REDIRECTED_VAL' parameter to URI. Required to figure out * Add the 'REDIRECTED_TAG=REDIRECTED_VAL' parameter to URI. Required to figure out
@ -321,12 +341,14 @@ if (i >= plugin_cfg.regex_pattern.used) {
osip_uri_param_add(&(contact->url->url_params), osip_strdup(REDIRECTED_TAG), osip_uri_param_add(&(contact->url->url_params), osip_strdup(REDIRECTED_TAG),
osip_strdup(REDIRECTED_VAL)); osip_strdup(REDIRECTED_VAL));
INFO("redirecting %s -> %s", to_user, new_to_user); INFO("redirecting %s -> %s", url_string, in);
/* sent redirect message back to local client */ /* sent redirect message back to local client */
add_to_redirected_cache(&redirected_cache, ticket); add_to_redirected_cache(&redirected_cache, ticket);
sip_gen_response(ticket, 302 /*Moved temporarily*/); sip_gen_response(ticket, 302 /*Moved temporarily*/);
/* release resources and return */
osip_free(url_string);
return STS_SIP_SENT; return STS_SIP_SENT;
} }
@ -353,10 +375,8 @@ regmatch_t * rmatch (char *buf, int size, regex_t *re) {
/* perform the match */ /* perform the match */
if (regexec (re, buf, NMATCHES, pm, 0)) { if (regexec (re, buf, NMATCHES, pm, 0)) {
DEBUGC(DBCLASS_PLUGIN,"no match found.");
return NULL; return NULL;
} }
DEBUGC(DBCLASS_PLUGIN,"match found.");
return &pm[0]; return &pm[0];
} }