mirror of https://github.com/sipwise/kamailio.git
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.
199 lines
6.7 KiB
199 lines
6.7 KiB
/*
|
|
* Kamailio osp module.
|
|
*
|
|
* This module enables Kamailio to communicate with an Open Settlement
|
|
* Protocol (OSP) server. The Open Settlement Protocol is an ETSI
|
|
* defined standard for Inter-Domain VoIP pricing, authorization
|
|
* and usage exchange. The technical specifications for OSP
|
|
* (ETSI TS 101 321 V4.1.1) are available at www.etsi.org.
|
|
*
|
|
* Uli Abend was the original contributor to this module.
|
|
*
|
|
* Copyright (C) 2001-2005 Fhg Fokus
|
|
*
|
|
* This file is part of Kamailio, a free SIP server.
|
|
*
|
|
* Kamailio 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
|
|
*
|
|
* Kamailio is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "osp_mod.h"
|
|
#include "term_transaction.h"
|
|
#include "sipheader.h"
|
|
#include "destination.h"
|
|
#include "osptoolkit.h"
|
|
#include "usage.h"
|
|
|
|
extern char* _osp_device_ip;
|
|
extern int _osp_token_format;
|
|
extern int _osp_validate_callid;
|
|
extern OSPTPROVHANDLE _osp_provider;
|
|
|
|
/*
|
|
* Get OSP token
|
|
* param msg SIP message
|
|
* param ignore1
|
|
* param ignore2
|
|
* return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure
|
|
*/
|
|
int ospCheckHeader(
|
|
struct sip_msg* msg,
|
|
char* ignore1,
|
|
char* ignore2)
|
|
{
|
|
unsigned char buffer[OSP_TOKENBUF_SIZE];
|
|
unsigned int buffersize = sizeof(buffer);
|
|
|
|
if (ospGetOspHeader(msg, buffer, &buffersize) != 0) {
|
|
return MODULE_RETURNCODE_FALSE;
|
|
} else {
|
|
return MODULE_RETURNCODE_TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Validate OSP token
|
|
* param ignore1
|
|
* param ignore2
|
|
* return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure MODULE_RETURNCODE_ERROR error
|
|
*/
|
|
int ospValidateHeader (
|
|
struct sip_msg* msg,
|
|
char* ignore1,
|
|
char* ignore2)
|
|
{
|
|
int errorcode;
|
|
OSPTTRANHANDLE transaction = -1;
|
|
unsigned int authorized = 0;
|
|
unsigned int timelimit = 0;
|
|
void* detaillog = NULL;
|
|
unsigned int logsize = 0;
|
|
unsigned char* callidval = (unsigned char*)"";
|
|
OSPTCALLID* callid = NULL;
|
|
unsigned callidsize = 0;
|
|
unsigned char token[OSP_TOKENBUF_SIZE];
|
|
unsigned int tokensize = sizeof(token);
|
|
osp_dest dest;
|
|
int result = MODULE_RETURNCODE_FALSE;
|
|
|
|
ospInitDestination(&dest);
|
|
|
|
if ((errorcode = OSPPTransactionNew(_osp_provider, &transaction) != OSPC_ERR_NO_ERROR)) {
|
|
LM_ERR("failed to create a new OSP transaction handle (%d)\n", errorcode);
|
|
} else if ((ospGetRpidUserpart(msg, dest.calling, sizeof(dest.calling)) != 0) &&
|
|
(ospGetFromUserpart(msg, dest.calling, sizeof(dest.calling)) != 0))
|
|
{
|
|
LM_ERR("failed to extract calling number\n");
|
|
} else if ((ospGetUriUserpart(msg, dest.called, sizeof(dest.called)) != 0) &&
|
|
(ospGetToUserpart(msg, dest.called, sizeof(dest.called)) != 0))
|
|
{
|
|
LM_ERR("failed to extract called number\n");
|
|
} else if (ospGetCallId(msg, &callid) != 0) {
|
|
LM_ERR("failed to extract call id\n");
|
|
} else if (ospGetSourceAddress(msg, dest.source, sizeof(dest.source)) != 0) {
|
|
LM_ERR("failed to extract source address\n");
|
|
} else if (ospGetOspHeader(msg, token, &tokensize) != 0) {
|
|
LM_ERR("failed to extract OSP authorization token\n");
|
|
} else {
|
|
LM_INFO( "validate token for: "
|
|
"transaction_handle '%d' "
|
|
"e164_source '%s' "
|
|
"e164_dest '%s' "
|
|
"validate_call_id '%s' "
|
|
"call_id '%.*s'\n",
|
|
transaction,
|
|
dest.calling,
|
|
dest.called,
|
|
_osp_validate_callid == 0 ? "No" : "Yes",
|
|
callid->ospmCallIdLen,
|
|
callid->ospmCallIdVal);
|
|
|
|
if (_osp_validate_callid != 0) {
|
|
callidsize = callid->ospmCallIdLen;
|
|
callidval = callid->ospmCallIdVal;
|
|
}
|
|
|
|
errorcode = OSPPTransactionValidateAuthorisation(
|
|
transaction,
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
dest.calling,
|
|
OSPC_E164,
|
|
dest.called,
|
|
OSPC_E164,
|
|
callidsize,
|
|
callidval,
|
|
tokensize,
|
|
token,
|
|
&authorized,
|
|
&timelimit,
|
|
&logsize,
|
|
detaillog,
|
|
_osp_token_format);
|
|
|
|
if ((errorcode == OSPC_ERR_NO_ERROR) && (authorized == 1)) {
|
|
if (callid->ospmCallIdLen > sizeof(dest.callid) - 1) {
|
|
dest.callidsize = sizeof(dest.callid) - 1;
|
|
} else {
|
|
dest.callidsize = callid->ospmCallIdLen;
|
|
}
|
|
memcpy(dest.callid, callid->ospmCallIdVal, dest.callidsize);
|
|
dest.callid[dest.callidsize] = 0;
|
|
dest.transid = ospGetTransactionId(transaction);
|
|
dest.type = OSPC_DESTINATION;
|
|
dest.authtime = time(NULL);
|
|
strncpy(dest.host, _osp_device_ip, sizeof(dest.host) - 1);
|
|
strncpy(dest.origcalled, dest.called, sizeof(dest.origcalled) - 1);
|
|
|
|
if (ospSaveTermDestination(&dest) == -1) {
|
|
LM_ERR("failed to save terminate destination\n");
|
|
ospRecordEvent(0, 500);
|
|
result = MODULE_RETURNCODE_ERROR;
|
|
} else {
|
|
LM_DBG("call is authorized for %d seconds, call_id '%.*s' transaction_id '%llu'",
|
|
timelimit,
|
|
dest.callidsize,
|
|
dest.callid,
|
|
dest.transid);
|
|
ospRecordTermTransaction(msg, dest.transid, dest.source, dest.calling, dest.called, dest.authtime);
|
|
result = MODULE_RETURNCODE_TRUE;
|
|
}
|
|
} else {
|
|
LM_ERR("token is invalid (%d)\n", errorcode);
|
|
|
|
/*
|
|
* Update terminating status code to 401 and report terminating setup usage.
|
|
* We may need to make 401 configurable, just in case a user decides to reply with
|
|
* a different code. Other options - trigger call setup usage reporting from the cpl
|
|
* (after replying with an error code), or maybe use a different tm callback.
|
|
*/
|
|
ospRecordEvent(0, 401);
|
|
result = MODULE_RETURNCODE_FALSE;
|
|
}
|
|
}
|
|
|
|
if (transaction != -1) {
|
|
OSPPTransactionDelete(transaction);
|
|
}
|
|
|
|
if (callid != NULL) {
|
|
OSPPCallIdDelete(&callid);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|