123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725 |
- /*
- * ser osp module.
- *
- * This module enables ser 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 ser, a free SIP server.
- *
- * ser 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
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser 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/osp.h>
- #include <osp/ospb64.h>
- #include "../../trim.h"
- #include "../../forward.h"
- #include "../../parser/parse_from.h"
- #include "../../parser/parse_rpid.h"
- #include "../../parser/parse_rr.h"
- #include "../../parser/parse_uri.h"
- #include "../../data_lump.h"
- #include "../../mem/mem.h"
- #include "osp_mod.h"
- #include "sipheader.h"
- extern int _osp_use_rpid;
- static void ospSkipPlus(char* e164);
- static int ospAppendHeader(struct sip_msg* msg, str* header);
- /*
- * Copy str to buffer and check overflow
- * param source Str
- * param buffer Buffer
- * param buffersize Size of buffer
- */
- void ospCopyStrToBuffer(
- str* source,
- char* buffer,
- int buffersize)
- {
- int copybytes;
- LOG(L_DBG, "osp: ospCopyStrToBuffer\n");
- if (source->len > buffersize - 1) {
- LOG(L_ERR,
- "osp: ERROR: buffer for copying '%.*s' is too small, will copy the first '%d' bytes\n",
- source->len,
- source->s,
- buffersize);
- copybytes = buffersize - 1;
- } else {
- copybytes = source->len;
- }
- strncpy(buffer, source->s, copybytes);
- buffer[copybytes] = '\0';
- }
- /*
- * Remove '+' in E164 string
- * param e164 E164 string
- */
- static void ospSkipPlus(
- char* e164)
- {
- LOG(L_DBG, "osp: ospSkipPlus\n");
- if (*e164 == '+') {
- strncpy(e164, e164 + 1, strlen(e164) - 1);
- e164[strlen(e164) - 1] = '\0';
- }
- }
- /*
- * Get calling number from From header
- * param msg SIP message
- * param fromuser User part of From header
- * param buffersize Size of fromuser buffer
- * return 0 success, -1 failure
- */
- int ospGetFromUserpart(
- struct sip_msg* msg,
- char* fromuser,
- int buffersize)
- {
- struct to_body* from;
- struct sip_uri uri;
- int result = -1;
- LOG(L_DBG, "osp: ospGetFromUserpart\n");
- fromuser[0] = '\0';
- if (msg->from != NULL) {
- if (parse_from_header(msg) == 0) {
- from = get_from(msg);
- if (parse_uri(from->uri.s, from->uri.len, &uri) == 0) {
- ospCopyStrToBuffer(&uri.user, fromuser, buffersize);
- ospSkipPlus(fromuser);
- result = 0;
- } else {
- LOG(L_ERR, "osp: ERROR: failed to parse From uri\n");
- }
- } else {
- LOG(L_ERR, "osp: ERROR: failed to parse From header\n");
- }
- } else {
- LOG(L_ERR, "osp: ERROR: failed to find From header\n");
- }
- return result;
- }
- /*
- * Get calling number from Remote-Party-ID header
- * param msg SIP message
- * param rpiduser User part of Remote-Party-ID header
- * param buffersize Size of fromuser buffer
- * return 0 success, -1 failure
- */
- int ospGetRpidUserpart(
- struct sip_msg* msg,
- char* rpiduser,
- int buffersize)
- {
- struct to_body* rpid;
- struct sip_uri uri;
- int result = -1;
- LOG(L_DBG, "osp: ospGetRpidUserpart\n");
- rpiduser[0] = '\0';
- if (_osp_use_rpid != 0) {
- if (msg->rpid != NULL) {
- if (parse_rpid_header(msg) == 0) {
- rpid = get_rpid(msg);
- if (parse_uri(rpid->uri.s, rpid->uri.len, &uri) == 0) {
- ospCopyStrToBuffer(&uri.user, rpiduser, buffersize);
- ospSkipPlus(rpiduser);
- result = 0;
- } else {
- LOG(L_ERR, "osp: ERROR: failed to parse RPID uri\n");
- }
- } else {
- LOG(L_ERR, "osp: ERROR: failed to parse RPID header\n");
- }
- } else {
- LOG(L_DBG, "osp: without RPID header\n");
- }
- } else {
- LOG(L_DBG, "osp: do not use RPID header\n");
- }
- return result;
- }
- /*
- * Get called number from To header
- * param msg SIP message
- * param touser User part of To header
- * param buffersize Size of touser buffer
- * return 0 success, -1 failure
- */
- int ospGetToUserpart(
- struct sip_msg* msg,
- char* touser,
- int buffersize)
- {
- struct to_body* to;
- struct sip_uri uri;
- int result = -1;
- LOG(L_DBG, "osp: ospGetToUserpart\n");
- touser[0] = '\0';
- if (msg->to != NULL) {
- if (parse_headers(msg, HDR_TO_F, 0) == 0) {
- to = get_to(msg);
- if (parse_uri(to->uri.s, to->uri.len, &uri) == 0) {
- ospCopyStrToBuffer(&uri.user, touser, buffersize);
- ospSkipPlus(touser);
- result = 0;
- } else {
- LOG(L_ERR, "osp: ERROR: failed to parse To uri\n");
- }
- } else {
- LOG(L_ERR, "osp: ERROR: failed to parse To header\n");
- }
- } else {
- LOG(L_ERR, "osp: ERROR: failed to find To header\n");
- }
- return result;
- }
- /*
- * Get called number from Request-Line header
- * param msg SIP message
- * param touser User part of To header
- * param buffersize Size of touser buffer
- * return 0 success, -1 failure
- */
- int ospGetUriUserpart(
- struct sip_msg* msg,
- char* uriuser,
- int buffersize)
- {
- int result = -1;
- LOG(L_DBG, "osp: ospGetUriUserpart\n");
- uriuser[0] = '\0';
- if (parse_sip_msg_uri(msg) >= 0) {
- ospCopyStrToBuffer(&msg->parsed_uri.user, uriuser, buffersize);
- ospSkipPlus(uriuser);
- result = 0;
- } else {
- LOG(L_ERR, "osp: ERROR: failed to parse Request-Line URI\n");
- }
- return result;
- }
- /*
- * Append header to SIP message
- * param msg SIP message
- * param header Header to be appended
- * return 0 success, -1 failure
- */
- static int ospAppendHeader(
- struct sip_msg* msg,
- str* header)
- {
- char* s;
- struct lump* anchor;
-
- LOG(L_DBG, "osp: ospAppendHeader\n");
- if((msg == 0) || (header == 0) || (header->s == 0) || (header->len <= 0)) {
- LOG(L_ERR, "osp: ERROR: bad parameters for appending header\n");
- return -1;
- }
- if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
- LOG(L_ERR, "osp: ERROR: failed to parse message\n");
- return -1;
- }
- anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
- if (anchor == 0) {
- LOG(L_ERR, "osp: ERROR: failed to get anchor\n");
- return -1;
- }
- s = (char*)pkg_malloc(header->len);
- if (s == 0) {
- LOG(L_ERR, "osp: ERROR: no memory\n");
- return -1;
- }
- memcpy(s, header->s, header->len);
- if (insert_new_lump_before(anchor, s, header->len, 0) == 0) {
- LOG(L_ERR, "osp: ERROR: failed to insert lump\n");
- pkg_free(s);
- return -1;
- }
-
- return 0;
- }
- /*
- * Add OSP token header to SIP message
- * param msg SIP message
- * param token OSP authorization token
- * param tokensize Size of OSP authorization token
- * return 0 success, -1 failure
- */
- int ospAddOspHeader(
- struct sip_msg* msg,
- unsigned char* token,
- unsigned int tokensize)
- {
- str headerval;
- char buffer[OSP_HEADERBUF_SIZE];
- unsigned char encodedtoken[OSP_TOKENBUF_SIZE];
- unsigned int encodedtokensize = sizeof(encodedtoken);
- int result = -1;
- LOG(L_DBG, "osp: ospAddOspHeader\n");
- if (tokensize == 0) {
- LOG(L_DBG, "osp: destination is not OSP device\n");
- result = 0;
- } else {
- if (OSPPBase64Encode(token, tokensize, encodedtoken, &encodedtokensize) == 0) {
- snprintf(buffer,
- sizeof(buffer),
- "%s%.*s\r\n",
- OSP_TOKEN_HEADER,
- encodedtokensize,
- encodedtoken);
-
- headerval.s = buffer;
- headerval.len = strlen(buffer);
-
- LOG(L_DBG, "osp: setting osp token header field '%s'\n", buffer);
-
- if (ospAppendHeader(msg, &headerval) == 0) {
- result = 0;
- } else {
- LOG(L_ERR, "osp: ERROR: failed to append osp header\n");
- }
- } else {
- LOG(L_ERR, "osp: ERROR: failed to base64 encode token\n");
- }
- }
- return result;
- }
- /*
- * Get OSP token from SIP message
- * param msg SIP message
- * param token OSP authorization token
- * param tokensize Size of OSP authorization token
- * return 0 success, -1 failure
- */
- int ospGetOspHeader(
- struct sip_msg* msg,
- unsigned char* token,
- unsigned int* tokensize)
- {
- struct hdr_field* hf;
- int errorcode;
- int result = -1;
- LOG(L_DBG, "osp: ospGetOspHeader\n");
- if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
- LOG(L_ERR, "osp: ERROR: failed to parse headers\n");
- return result;
- }
- for (hf = msg->headers; hf; hf = hf->next) {
- if ((hf->type == HDR_OTHER_T) && (hf->name.len == OSP_HEADER_SIZE - 2)) {
- // possible hit
- if (strncasecmp(hf->name.s, OSP_TOKEN_HEADER, OSP_HEADER_SIZE) == 0) {
- if ((errorcode = OSPPBase64Decode(hf->body.s, hf->body.len, token, tokensize)) == 0) {
- result = 0;
- } else {
- LOG(L_ERR, "osp: ERROR: failed to base64 decode token (%d)\n", errorcode);
- LOG(L_ERR, "osp: ERROR: header '%.*s' length %d\n", hf->body.len, hf->body.s, hf->body.len);
- }
- break;
- }
- }
- }
- return result;
- }
- /*
- * Get first VIA header and use the IP or host name
- * param msg SIP message
- * param sourceaddress Source address
- * param buffersize Size of sourceaddress
- * return 0 success, -1 failure
- */
- int ospGetSourceAddress(
- struct sip_msg* msg,
- char* sourceaddress,
- int buffersize)
- {
- struct via_body* via;
- int result = -1;
- LOG(L_DBG, "osp: ospGetSourceAddress\n");
- if (msg->h_via1 || (parse_headers(msg, HDR_VIA_F, 0) == 0 && msg->h_via1)) {
- via = msg->h_via1->parsed;
- ospCopyStrToBuffer(&via->host, sourceaddress, buffersize);
- LOG(L_DBG, "osp: source address '%s'\n", sourceaddress);
- result = 0;
- }
- return result;
- }
- /*
- * Get Call-ID header from SIP message
- * param msg SIP message
- * param callid Call ID
- * return 0 success, -1 failure
- */
- int ospGetCallId(
- struct sip_msg* msg,
- OSPTCALLID** callid)
- {
- struct hdr_field* hf;
- int result = -1;
- LOG(L_DBG, "osp: ospGetCallId\n");
- if (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) == -1) {
- LOG(L_ERR, "osp: failed to parse Call-ID\n");
- return result;
- }
- hf = (struct hdr_field*)msg->callid;
- if (hf != NULL) {
- *callid = OSPPCallIdNew(hf->body.len, (unsigned char*)hf->body.s);
- if (*callid) {
- result = 0;
- } else {
- LOG(L_ERR, "osp: ERROR: failed to allocate OSPCALLID object for '%.*s'\n", hf->body.len, hf->body.s);
- }
- } else {
- LOG(L_ERR, "osp: ERROR: failed to find Call-ID header\n");
- }
- return result;
- }
- /*
- * Get route parameters from the 1st Route or Request-Line
- * param msg SIP message
- * param routeparameters Route parameters
- * param buffersize Size of routeparameters
- * return 0 success, -1 failure
- */
- int ospGetRouteParameters(
- struct sip_msg* msg,
- char* routeparameters,
- int buffersize)
- {
- struct hdr_field* hf;
- rr_t* rt;
- struct sip_uri uri;
- int result = -1;
- LOG(L_DBG, "osp: ospGetRouterParameters\n");
- LOG(L_DBG, "osp: parsed uri host '%.*s' port '%d' vars '%.*s'\n",
- msg->parsed_uri.host.len,
- msg->parsed_uri.host.s,
- msg->parsed_uri.port_no,
- msg->parsed_uri.params.len,
- msg->parsed_uri.params.s);
- if (!(hf = msg->route)) {
- LOG(L_DBG, "osp: there is no Route headers\n");
- } else if (!(rt = (rr_t*)hf->parsed)) {
- LOG(L_ERR, "osp: ERROR: route headers are not parsed\n");
- } else if (parse_uri(rt->nameaddr.uri.s, rt->nameaddr.uri.len, &uri) != 0) {
- LOG(L_ERR, "osp: ERROR: failed to parse the Route uri '%.*s'\n", rt->nameaddr.uri.len, rt->nameaddr.uri.s);
- } else if (check_self(&uri.host, uri.port_no ? uri.port_no : SIP_PORT, PROTO_NONE) != 1) {
- LOG(L_DBG, "osp: the Route uri is NOT mine\n");
- LOG(L_DBG, "osp: host '%.*s' port '%d'\n", uri.host.len, uri.host.s, uri.port_no);
- LOG(L_DBG, "osp: params '%.*s'\n", uri.params.len, uri.params.s);
- } else {
- LOG(L_DBG, "osp: the Route uri IS mine - '%.*s'\n", uri.params.len, uri.params.s);
- LOG(L_DBG, "osp: host '%.*s' port '%d'\n", uri.host.len, uri.host.s, uri.port_no);
- ospCopyStrToBuffer(&uri.params, routeparameters, buffersize);
- result = 0;
- }
- if ((result == -1) && (msg->parsed_uri.params.len > 0)) {
- LOG(L_DBG, "osp: using route parameters from Request-Line uri\n");
- ospCopyStrToBuffer(&msg->parsed_uri.params, routeparameters, buffersize);
- routeparameters[msg->parsed_uri.params.len] = '\0';
- result = 0;
- }
- return result;
- }
- /*
- * Rebuild URI using called number, destination IP, and port
- * param newuri URI to be built
- * param called Called number
- * param dest Destination IP
- * param port Destination port
- * param format URI format
- * return 0 success, -1 failure
- */
- int ospRebuildDestionationUri(
- str* newuri,
- char* called,
- char* dest,
- char* port,
- int format)
- {
- static const str TRANS = {";transport=tcp", 14};
- char* buffer;
- int calledsize;
- int destsize;
- int portsize;
- LOG(L_DBG, "osp: ospRebuildDestinationUri\n");
- calledsize = strlen(called);
- destsize = strlen(dest);
- portsize = strlen(port);
- LOG(L_DBG, "osp: '%s'(%i) '%s'(%i) '%s'(%i) '%d'\n",
- called,
- calledsize,
- dest,
- destsize,
- port,
- portsize,
- format);
- /* "sip:" + called + "@" + dest + : + port + " SIP/2.0" for URI format 0 */
- /* "<sip:" + called + "@" + dest + : + port> + " SIP/2.0" for URI format 1 */
- newuri->s = (char*)pkg_malloc(1 + 4 + calledsize + 1 + destsize + 1 + portsize + 1 + 1 + 16 + TRANS.len);
- if (newuri == NULL) {
- LOG(L_ERR, "osp: ERROR: no memory\n");
- return -1;
- }
- buffer = newuri->s;
- if (format == 1) {
- *buffer++ = '<';
- }
- *buffer++ = 's';
- *buffer++ = 'i';
- *buffer++ = 'p';
- *buffer++ = ':';
- memcpy(buffer, called, calledsize);
- buffer += calledsize;
- *buffer++ = '@';
-
- if (*dest == '[') {
- /* leave out annoying [] */
- memcpy(buffer, dest + 1, destsize - 2);
- buffer += destsize - 2;
- } else {
- memcpy(buffer, dest, destsize);
- buffer += destsize;
- }
-
- if (portsize > 0) {
- *buffer++ = ':';
- memcpy(buffer, port, portsize);
- buffer += portsize;
- }
- if (format == 1) {
- *buffer++ = '>';
- }
- /*
- *buffer++ = ' ';
- *buffer++ = 'S';
- *buffer++ = 'I';
- *buffer++ = 'P';
- *buffer++ = '/';
- *buffer++ = '2';
- *buffer++ = '.';
- *buffer++ = '0';
- memcpy(buffer, TRANS.s, TRANS.len);
- buffer += TRANS.len;
- *buffer = '\0';
- */
- newuri->len = buffer - newuri->s;
- LOG(L_DBG, "osp: new uri '%.*s'\n", newuri->len, newuri->s);
- return 0;
- }
- /*
- * Get next hop using the first Route not generated by this proxy or URI from the Request-Line
- * param msg SIP message
- * param nexthop Next hop IP
- * param buffersize Size of nexthop
- */
- void ospGetNextHop(
- struct sip_msg* msg,
- char* nexthop,
- int buffersize)
- {
- struct hdr_field* hf;
- struct sip_uri uri;
- rr_t* rt;
- int found = 0;
- LOG(L_DBG, "osp: ospGetNextHop\n");
- for (hf = msg->headers; hf; hf = hf->next) {
- if (hf->type == HDR_ROUTE_T) {
- for (rt = (rr_t*)hf->parsed; rt; rt = rt->next) {
- if (parse_uri(rt->nameaddr.uri.s, rt->nameaddr.uri.len, &uri) == 0) {
- LOG(L_DBG, "osp: host '%.*s' port '%d'\n", uri.host.len, uri.host.s, uri.port_no);
- if (check_self(&uri.host, uri.port_no ? uri.port_no : SIP_PORT, PROTO_NONE) != 1) {
- LOG(L_DBG, "osp: it is NOT me, FOUND!\n");
- ospCopyStrToBuffer(&uri.host, nexthop, buffersize);
- found = 1;
- break;
- } else {
- LOG(L_DBG, "osp: it IS me, keep looking\n");
- }
- } else {
- LOG(L_ERR,
- "osp: ERROR: failed to parsed route uri '%.*s'\n",
- rt->nameaddr.uri.len,
- rt->nameaddr.uri.s);
- }
- }
- if (found == 1) {
- break;
- }
- }
- }
- if (!found) {
- LOG(L_DBG, "osp: using the Request-Line instead host '%.*s' port '%d'\n",
- msg->parsed_uri.host.len,
- msg->parsed_uri.host.s,
- msg->parsed_uri.port_no);
- ospCopyStrToBuffer(&msg->parsed_uri.host, nexthop, buffersize);
- found = 1;
- }
- }
- /*
- * Get direction using the first Route not generated by this proxy or URI from the Request-Line
- * SER does not have is_direction as Kamailio. We have to write it.
- * The problem is we cannot check append_fromtag option before running. So, ftag may not exist.
- * param msg SIP message
- * return 0 originating, 1 terminating, -1 failed
- */
- int ospGetDirection(struct sip_msg* msg)
- {
- static const str FTAG = {"ftag", 4};
- char parameters[OSP_HEADERBUF_SIZE];
- char* tmp;
- char* token;
- str ftag;
- struct to_body* from;
- int result = -1;
- LOG(L_DBG, "osp: ospGetDirection\n");
- if (ospGetRouteParameters(msg, parameters, sizeof(parameters)) == 0) {
- for (token = strtok_r(parameters, ";", &tmp);
- token;
- token = strtok_r(NULL, ";", &tmp))
- {
- ftag.s = token;
- ftag.len = strlen(token);
- /* Remove leading white space char */
- trim_leading(&ftag);
- if (strncmp(ftag.s, FTAG.s, FTAG.len) == 0) {
- /* Remove "ftag" string */
- ftag.s += FTAG.len;
- ftag.len -= FTAG.len;
- /* Remove leading white space char */
- trim_leading(&ftag);
- /* Remove '=' char */
- ftag.s++;
- ftag.len--;
- /* Remove leading and tailing white space char */
- trim(&ftag);
- LOG(L_DBG, "osp: ftag '%s'\n", ftag.s);
- if ((parse_from_header(msg) == 0) && ((from = get_from(msg)) != 0)) {
- if ((ftag.len == from->tag_value.len) && !strncmp(ftag.s, from->tag_value.s, ftag.len)) {
- LOG(L_DBG, "osp: originating\n");
- result = 0;
- } else {
- LOG(L_DBG, "osp: terminating\n");
- result = 1;
- }
- }
- break;
- } else {
- LOG(L_DBG, "osp: ignoring parameter '%s'\n", token);
- }
- }
- }
- return result;
- }
|