added plugin_fix_fbox_anoncall

This commit is contained in:
Thomas Ries
2016-01-31 14:00:27 +00:00
parent 35277fe024
commit 26fa103921
5 changed files with 275 additions and 3 deletions
+3
View File
@@ -1,5 +1,8 @@
0.8.2
=====
30-Jan-2016: - added plugin_fix_fbox_anoncall: a plugin to work around
some quirks from Fritzboxes when receiving anonymous calls
(calls with supressed CLID). Might also work for other UAs.
11-Oct-2015: - performance improvement in DNS lookup/caching
20-Sep-2015: - added plugin_siptrunk: a plugin to support SIP
trunks with multiple numbers within the same SIP account.
+13 -1
View File
@@ -338,7 +338,7 @@ load_plugin=plugin_logcall.la
#load_plugin=plugin_stripheader.la
#load_plugin=plugin_codecfilter.la
#load_plugin=plugin_siptrunk.la
#load_plugin=plugin_fix_fbox_anoncall.la
######################################################################
# Plugin_demo
@@ -490,3 +490,15 @@ plugin_codecfilter_blacklist = GSM
#plugin_siptrunk_name = Example Trunk, 555-123100 ... 555-123112
#plugin_siptrunk_account = sip:user@sip.example.org
#plugin_siptrunk_numbers_regex = ^555123(10[0-9]|11[012])$
######################################################################
# Plugin_fix_fbox_anoncall
#
# This plugin attempts to work-around some SIP issues with
# Fritzbox devices and anonymous calls. Fritzbox devices do change their
# Contact header when answering an anonymous call (supressed CLID) - this
# in turn confuses siproxd. This plugin attempts to work around this by
# sanitizing the Contact Header before processing.
# DTAG_networks: Local Networks where such Fritzboxes are located. Only SIP
# messages originating in those ranges will be sanitized.
plugin_fix_fbox_anoncall_networks = 217.0.23.100/32,91.121.209.194/32,81.221.125.10/32
+8 -2
View File
@@ -40,7 +40,9 @@ pkglib_LTLIBRARIES = plugin_demo.la \
plugin_regex.la \
plugin_codecfilter.la \
plugin_stripheader.la \
plugin_siptrunk.la
plugin_siptrunk.la \
plugin_fix_fbox_anoncall.la
DLOPENPLUGINS = -dlopen plugin_demo.la \
-dlopen plugin_shortdial.la \
-dlopen plugin_logcall.la \
@@ -52,7 +54,8 @@ DLOPENPLUGINS = -dlopen plugin_demo.la \
-dlopen plugin_regex.la \
-dlopen plugin_codecfilter.la \
-dlopen plugin_stripheader.la \
-dlopen plugin_siptrunk.la
-dlopen plugin_siptrunk.la \
-dlopen plugin_fix_fbox_anoncall.la
#
plugin_demo_la_SOURCES = plugin_demo.c
plugin_demo_la_LDFLAGS = -module -avoid-version -shrext '.so'
@@ -89,6 +92,9 @@ plugin_stripheader_la_LDFLAGS = -module -avoid-version -shrext '.so'
#
plugin_siptrunk_la_SOURCES = plugin_siptrunk.c
plugin_siptrunk_la_LDFLAGS = -module -avoid-version -shrext '.so'
#
plugin_fix_fbox_anoncall_la_SOURCES = plugin_fix_fbox_anoncall.c
plugin_fix_fbox_anoncall_la_LDFLAGS = -module -avoid-version -shrext '.so'
#
+241
View File
@@ -0,0 +1,241 @@
/*
Copyright (C) 2016 Thomas Ries <tries@gmx.net>
This file is part of Siproxd.
Siproxd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Siproxd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warrantry of
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 Siproxd; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* must be defined before including <plugin.h> */
#define PLUGIN_NAME plugin_fix_fbox_anoncall
#include "config.h"
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <osipparser2/osip_parser.h>
#include "siproxd.h"
#include "plugins.h"
#include "log.h"
static char const ident[]="$Id$";
/* Plug-in identification */
static char name[]="plugin_fix_fbox_anoncall";
static char desc[]="Fixes issues with incoming anonymous calls on Fritzbox UAs";
/* global configuration storage - required for config file location */
extern struct siproxd_config configuration;
/* global URL mapping table */
extern struct urlmap_s urlmap[];
/* plugin configuration storage */
static struct plugin_config {
char *networks; // networks where we shall fix Fritzbox behaviour
} plugin_cfg;
/* Instructions for config parser */
static cfgopts_t plugin_cfg_opts[] = {
{ "plugin_fix_fbox_anoncall_networks", TYP_STRING, &plugin_cfg.networks, {0, NULL} },
{0, 0, 0}
};
/* Prototypes */
//static int sip_fix_topvia(sip_ticket_t *ticket);
/*
* Initialization.
* Called once suring siproxd startup.
*/
int PLUGIN_INIT(plugin_def_t *plugin_def) {
/* API version number of siproxd that this plugin is built against.
* This constant will change whenever changes to the API are made
* that require adaptions in the plugin. */
plugin_def->api_version=SIPROXD_API_VERSION;
/* Name and descriptive text of the plugin */
plugin_def->name=name;
plugin_def->desc=desc;
/* Execution mask - during what stages of SIP processing shall
* the plugin be called. */
plugin_def->exe_mask=PLUGIN_PRE_PROXY;
/* read the config file */
if (read_config(configuration.configfile,
configuration.config_search,
plugin_cfg_opts, name) == STS_FAILURE) {
ERROR("Plugin '%s': could not load config file", name);
return STS_FAILURE;
}
INFO("plugin_fix_fbox_anoncall is initialized");
return STS_SUCCESS;
}
/*
* Processing.
*
*/
int PLUGIN_PROCESS(int stage, sip_ticket_t *ticket){
/* stage contains the PLUGIN_* value - the stage of SIP processing. */
int type;
osip_contact_t *contact;
int idx=0;
int param_match_idx=0;
int user_match=0;
int param_match=0;
type = ticket->direction;
DEBUGC(DBCLASS_PLUGIN, "plugin_fix_fbox_anoncall: type=%i", type);
/* Outgoing SIP response? - may also need to process outgoing SIP requests - */
if ((type == RESTYP_OUTGOING) || (type == REQTYP_OUTGOING)) {
/* a Contact header needs to be present in response */
osip_message_get_contact(ticket->sipmsg, 0, &contact);
if(contact == NULL) {
DEBUGC(DBCLASS_PLUGIN, "no Contact header found in outgoing SIP message");
return STS_SUCCESS;
}
if(contact->url == NULL) {
DEBUGC(DBCLASS_PLUGIN, "no Contact->Url header found in outgoing SIP message");
return STS_SUCCESS;
}
/*
loop through URLMAP table
compare IP, param, if match
set partial match
compare username, if match
all OK with this Contact header, return from plugin
if no math
probably broken username part in header (as rest matches)
remember urlmap index
end loop
if partial match == 0
unable to figure out how to fix contact header.
dump some info
if partial match == 1
replace username part from urlmap[saved_index].true_url
return from plugin
*/
/* check for sender IP is in configured range */
DEBUGC(DBCLASS_PLUGIN, "plugin_fix_fbox_anoncall: processing from host [%s]",
utils_inet_ntoa(ticket->from.sin_addr));
if ((plugin_cfg.networks != NULL) &&
(strcmp(plugin_cfg.networks, "") !=0) &&
(process_aclist(plugin_cfg.networks, ticket->from) == STS_SUCCESS)) {
/* Sender IP is in list, fix check and fix Contact header */
DEBUGC(DBCLASS_PLUGIN, "plugin_fix_fbox_anoncall: checking for bogus Contact header");
/* loop through urlmap table */
for (idx=0; idx<URLMAP_SIZE; idx++){
user_match=0;
param_match=0;
if (urlmap[idx].active == 0) continue;
/* outgoing response - only look for true_url */
/* 1) check host, skip of no match */
if (contact->url->host && urlmap[idx].true_url->host) {
if (osip_strcasecmp(contact->url->host, urlmap[idx].true_url->host) != 0) {
/* no IP match, continue */
continue;
}
}
/* 2) check username match */
if (contact->url->username && urlmap[idx].true_url->username) {
if (osip_strcasecmp(contact->url->username, urlmap[idx].true_url->username) == 0) {
/* MATCH, all OK - return */
user_match=1;
break;
}
}
/* 3) check param field ("uniq=" param)*/
if (contact->url && urlmap[idx].true_url) {
int sts1, sts2;
osip_uri_param_t *p1=NULL, *p2=NULL;
sts1=osip_uri_param_get_byname(&(contact->url->url_params), "uniq", &p1);
sts2=osip_uri_param_get_byname(&(urlmap[idx].true_url->url_params), "uniq", &p2);
if ( ((sts1 == OSIP_SUCCESS) && (sts2 == OSIP_SUCCESS)) &&
(p1 && p2) &&
(p1->gname && p2->gname && p1->gvalue && p2->gvalue) &&
(osip_strcasecmp(p1->gname, p2->gname) == 0) &&
(osip_strcasecmp(p1->gvalue, p2->gvalue) == 0) ) {
/* MATCH */
param_match=1;
param_match_idx=idx;
}
}
} // for
/* full match (host & user) */
if (user_match == 1) {
DEBUGC(DBCLASS_PLUGIN, "plugin_fix_fbox_anoncall: got a user@host match - OK");
return STS_SUCCESS;
}
/* no partial match (no host, or no user / no param match) */
if (param_match == 0) {
WARN("Bogus outgoing response Contact header from [%s], unable to sanitize!",
utils_inet_ntoa(ticket->from.sin_addr));
return STS_FAILURE;
}
/* param_match - replace the username part from [param_match_idx] -> Contact */
/* replace contact URI (username part) */
osip_free(contact->url->username);
osip_uri_set_username(contact->url,
osip_strdup(urlmap[param_match_idx].true_url->username));
DEBUGC(DBCLASS_PLUGIN, "plugin_fix_fbox_anoncall: sanitized Contact from [%s]",
utils_inet_ntoa(ticket->from.sin_addr));
} else {
DEBUGC(DBCLASS_PLUGIN, "plugin_fix_fbox_anoncall: no IP match, returning.");
}
DEBUGC(DBCLASS_PLUGIN, "plugin_fix_fbox_anoncall: done");
} // if (type == RESTYP_OUTGOING)
return STS_SUCCESS;
}
/*
* De-Initialization.
* Called during shutdown of siproxd. Gives the plugin the chance
* to clean up its mess (e.g. dynamic memory allocation, database
* connections, whatever the plugin messes around with)
*/
int PLUGIN_END(plugin_def_t *plugin_def){
INFO("plugin_fix_fbox_anoncall ends here");
return STS_SUCCESS;
}
+10
View File
@@ -670,6 +670,16 @@ int sip_rewrite_contact (sip_ticket_t *ticket, int direction) {
(compare_url(contact->url, urlmap[i].masq_url)==STS_SUCCESS)) break;
}
/* NOTE:
It has been observed with some UAs (e.g. Fritzbox) that when receiving
an anonymous call (call with supressed CLID) these UAs do send a *modified*
Contact header (compared to the Contact used in REGISTER).
This confuses siproxd as now masquerading cannot match the Contact Header
with the URLMAP table.
-> see plugin_fix_fbox_anoncall that tries to work around things by
detecting this and restoring the "sane" Contact header.
/*
/* found a mapping entry */
if (i<URLMAP_SIZE) {
char *tmp;