/* * Report OSP usage from OSP cookie * SER checks ftag by itself, without release parameter * param msg SIP message * param cookie OSP cookie * param callid Call ID * param type Usage type * return */ static int ospReportUsageFromCookie( struct sip_msg* msg, char* cookie, OSPTCALLID* callid, OSPE_MSG_ROLETYPES type) { int release; char* tmp; char* token; char tag; char* value; unsigned long long transid = 0; time_t authtime = 0; unsigned destinationCount = 0; time_t endtime = time(NULL); char firstvia[OSP_STRBUF_SIZE]; char from[OSP_STRBUF_SIZE]; char to[OSP_STRBUF_SIZE]; char nexthop[OSP_STRBUF_SIZE]; char* calling; char* called; char* originator = NULL; char* terminator; char* source; char srcbuf[OSP_STRBUF_SIZE]; char* destination; char dstbuf[OSP_STRBUF_SIZE]; char* srcdev; char devbuf[OSP_STRBUF_SIZE]; OSPTTRANHANDLE transaction = -1; int errorcode; LOG(L_DBG, "osp: ospReportUsageFromCookie\n"); LOG(L_DBG, "osp: '%s' type '%d'\n", cookie, type); if (cookie != NULL) { for (token = strtok_r(cookie, "_", &tmp); token; token = strtok_r(NULL, "_", &tmp)) { tag = *token; value= token + 1; switch (tag) { case OSP_COOKIE_TRANSID: case OSP_COOKIE_TRANSIDUP: transid = atoll(value); break; case OSP_COOKIE_AUTHTIME: case OSP_COOKIE_AUTHTIMEUP: authtime = atoi(value); break; case OSP_COOKIE_SRCIP: case OSP_COOKIE_SRCIPUP: originator = value; break; case OSP_COOKIE_DSTCOUNT: case OSP_COOKIE_DSTCOUNTUP: destinationCount = (unsigned)atoi(value); break; default: LOG(L_ERR, "osp: ERROR: unexpected tag '%c' / value '%s'\n", tag, value); break; } } } ospGetSourceAddress(msg, firstvia, sizeof(firstvia)); ospGetFromUserpart(msg, from, sizeof(from)); ospGetToUserpart(msg, to, sizeof(to)); ospGetNextHop(msg, nexthop, sizeof(nexthop)); LOG(L_DBG, "osp: first via '%s' from '%s' to '%s' next hop '%s'\n", firstvia, from, to, nexthop); /* SER checks ftag by itself */ errorcode = ospGetDirection(msg); switch (errorcode) { case 0: release = OSP_RELEASE_ORIG; break; case 1: release = OSP_RELEASE_TERM; break; default: /* This approach has a problem of flipping called/calling number */ if (strcmp(firstvia, originator) == 0) { release = OSP_RELEASE_ORIG; } else { release = OSP_RELEASE_TERM; } } if (release == OSP_RELEASE_ORIG) { LOG(L_DBG, "osp: orig '%s' released the call, call_id '%.*s' transaction_id '%llu'\n", firstvia, callid->ospmCallIdLen, callid->ospmCallIdVal, transid); if (originator == NULL) { originator = firstvia; } calling = from; called = to; terminator = nexthop; } else { release = OSP_RELEASE_TERM; LOG(L_DBG, "osp: term '%s' released the call, call_id '%.*s' transaction_id '%llu'\n", firstvia, callid->ospmCallIdLen, callid->ospmCallIdVal, transid); if (originator == NULL) { originator = nexthop; } calling = to; called = from; terminator = firstvia; } errorcode = OSPPTransactionNew(_osp_provider, &transaction); LOG(L_DBG, "osp: created transaction handle '%d' (%d)\n", transaction, errorcode); switch (type) { case OSPC_DESTINATION: ospConvertAddress(originator, srcbuf, sizeof(srcbuf)); source = srcbuf; destination = _osp_device_ip; srcdev = ""; break; case OSPC_SOURCE: case OSPC_OTHER: case OSPC_UNDEFINED_ROLE: default: source = _osp_device_ip; ospConvertAddress(terminator, dstbuf, sizeof(dstbuf)); destination = dstbuf; ospConvertAddress(originator, devbuf, sizeof(devbuf)); srcdev = devbuf; break; } errorcode = OSPPTransactionBuildUsageFromScratch( transaction, transid, type, source, destination, srcdev, "", calling, OSPC_E164, called, OSPC_E164, callid->ospmCallIdLen, callid->ospmCallIdVal, (enum OSPEFAILREASON)0, NULL, NULL); LOG(L_DBG, "osp: built usage handle '%d' (%d)\n", transaction, errorcode); if ((errorcode == OSPC_ERR_NO_ERROR) && (destinationCount > 0)) { errorcode = OSPPTransactionSetDestinationCount( transaction, destinationCount); } ospReportUsageWrapper( transaction, cookie == NULL ? 9016 : 10016, cookie == NULL ? 0 : endtime - authtime, authtime, endtime, 0,0, 0,0, release); return errorcode; }
/* * Validate OSP token * param ignore1 * param ignore2 * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure */ 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; LOG(L_DBG, "osp: ospValidateHeader\n"); ospInitDestination(&dest); if ((errorcode = OSPPTransactionNew(_osp_provider, &transaction) != 0)) { LOG(L_ERR, "osp: ERROR: 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)) { LOG(L_ERR, "osp: ERROR: failed to extract calling number\n"); } else if ((ospGetUriUserpart(msg, dest.called, sizeof(dest.called)) != 0) && (ospGetToUserpart(msg, dest.called, sizeof(dest.called)) != 0)) { LOG(L_ERR, "osp: ERROR: failed to extract called number\n"); } else if (ospGetCallId(msg, &callid) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract call id\n"); } else if (ospGetSourceAddress(msg, dest.source, sizeof(dest.source)) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract source address\n"); } else if (ospGetOspHeader(msg, token, &tokensize) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract OSP authorization token\n"); } else { LOG(L_INFO, "osp: validate token for: " "transaction_handle '%i' " "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 (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.tid = ospGetTransactionId(transaction); dest.type = OSPC_DESTINATION; dest.authtime = time(NULL); strcpy(dest.host, _osp_device_ip); ospSaveTermDestination(&dest); if ((errorcode == 0) && (authorized == 1)) { LOG(L_DBG, "osp: call is authorized for %d seconds, call_id '%.*s' transaction_id '%lld'", timelimit, dest.callidsize, dest.callid, dest.tid); ospRecordTermTransaction(msg, transaction, dest.source, dest.calling, dest.called, dest.authtime); result = MODULE_RETURNCODE_TRUE; } else { LOG(L_ERR, "osp: ERROR: token is invalid (%i)\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); } } if (transaction != -1) { OSPPTransactionDelete(transaction); } if (callid != NULL) { OSPPCallIdDelete(&callid); } return result; }
/* * Report OSP usage from OSP cookie * param msg SIP message * param cookie OSP cookie (buffer owned by ospReportUsage, can be modified) * param callid Call ID * param release Who releases the call first. 0 orig, 1 term * param type Usage type * return */ static int ospReportUsageFromCookie( struct sip_msg* msg, char* cookie, OSPTCALLID* callid, int release, OSPE_MSG_ROLETYPES type) { char* tmp; char* token; char tag; char* value; unsigned long long transid = 0; time_t authtime = 0; unsigned destinationCount = 0; time_t duration = 0; time_t endtime = time(NULL); int cookieflags = 0; unsigned releasecode; char firstvia[OSP_STRBUF_SIZE]; char from[OSP_STRBUF_SIZE]; char to[OSP_STRBUF_SIZE]; char nexthop[OSP_STRBUF_SIZE]; char* calling; char* called; char* originator = NULL; char* terminator; char* source; char srcbuf[OSP_STRBUF_SIZE]; char* destination; char dstbuf[OSP_STRBUF_SIZE]; char* srcdev; char devbuf[OSP_STRBUF_SIZE]; OSPTTRANHANDLE transaction = -1; int errorcode; LM_DBG("'%s' type '%d'\n", cookie, type); if (cookie != NULL) { for (token = strtok_r(cookie, "_", &tmp); token; token = strtok_r(NULL, "_", &tmp)) { tag = *token; value= token + 1; switch (tag) { case OSP_COOKIE_TRANSID: case OSP_COOKIE_TRANSIDUP: transid = atoll(value); cookieflags |= OSP_COOKIEHAS_TRANSID; break; case OSP_COOKIE_AUTHTIME: case OSP_COOKIE_AUTHTIMEUP: authtime = atoi(value); duration = endtime - authtime; cookieflags |= OSP_COOKIEHAS_AUTHTIME; break; case OSP_COOKIE_SRCIP: case OSP_COOKIE_SRCIPUP: originator = value; cookieflags |= OSP_COOKIEHAS_SRCIP; break; case OSP_COOKIE_DSTCOUNT: case OSP_COOKIE_DSTCOUNTUP: destinationCount = (unsigned)atoi(value); cookieflags |= OSP_COOKIEHAS_DSTCOUNT; break; default: LM_ERR("unexpected tag '%c' / value '%s'\n", tag, value); break; } } } switch (type) { case OSPC_DESTINATION: if (cookieflags == OSP_COOKIEHAS_TERMALL) { releasecode = 10016; } else { releasecode = 9016; } break; case OSPC_SOURCE: case OSPC_OTHER: case OSPC_UNDEFINED_ROLE: default: if (cookieflags == OSP_COOKIEHAS_ORIGALL) { releasecode = 10016; } else { releasecode = 9016; } break; } if (releasecode == 9016) { transid = 0; originator = NULL; authtime = 0; duration = 0; destinationCount = 0; } ospGetSourceAddress(msg, firstvia, sizeof(firstvia)); ospGetFromUserpart(msg, from, sizeof(from)); ospGetToUserpart(msg, to, sizeof(to)); ospGetNextHop(msg, nexthop, sizeof(nexthop)); LM_DBG("first via '%s' from '%s' to '%s' next hop '%s'\n", firstvia, from, to, nexthop); if (release == OSP_RELEASE_ORIG) { LM_DBG("orig '%s' released the call, call_id '%.*s' transaction_id '%llu'\n", firstvia, callid->ospmCallIdLen, callid->ospmCallIdVal, transid); if (originator == NULL) { originator = firstvia; } calling = from; called = to; terminator = nexthop; } else { release = OSP_RELEASE_TERM; LM_DBG("term '%s' released the call, call_id '%.*s' transaction_id '%llu'\n", firstvia, callid->ospmCallIdLen, callid->ospmCallIdVal, transid); if (originator == NULL) { originator = nexthop; } calling = to; called = from; terminator = firstvia; } errorcode = OSPPTransactionNew(_osp_provider, &transaction); LM_DBG("created transaction handle '%d' (%d)\n", transaction, errorcode); switch (type) { case OSPC_DESTINATION: ospConvertAddress(originator, srcbuf, sizeof(srcbuf)); source = srcbuf; destination = _osp_device_ip; srcdev = ""; break; case OSPC_SOURCE: case OSPC_OTHER: case OSPC_UNDEFINED_ROLE: default: source = _osp_device_ip; ospConvertAddress(terminator, dstbuf, sizeof(dstbuf)); destination = dstbuf; ospConvertAddress(originator, devbuf, sizeof(devbuf)); srcdev = devbuf; break; } errorcode = OSPPTransactionBuildUsageFromScratch( transaction, transid, type, source, destination, srcdev, "", calling, OSPC_E164, called, OSPC_E164, callid->ospmCallIdLen, callid->ospmCallIdVal, (enum OSPEFAILREASON)0, NULL, NULL); LM_DBG("built usage handle '%d' (%d)\n", transaction, errorcode); if ((errorcode == OSPC_ERR_NO_ERROR) && (destinationCount > 0)) { errorcode = OSPPTransactionSetDestinationCount( transaction, destinationCount); } ospReportUsageWrapper( transaction, releasecode, duration, authtime, endtime, 0, 0, 0, 0, release); return errorcode; }
/* * Request OSP authorization and routeing * param msg SIP message * param ignore1 * param ignore2 * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure */ int ospRequestRouting( struct sip_msg* msg, char* ignore1, char* ignore2) { int errorcode; time_t authtime; char source[OSP_E164BUF_SIZE]; char sourcedev[OSP_STRBUF_SIZE]; char src[OSP_STRBUF_SIZE]; char destination[OSP_E164BUF_SIZE]; unsigned int callidnumber = 1; OSPTCALLID* callids[callidnumber]; unsigned int logsize = 0; char* detaillog = NULL; const char** preferred = NULL; unsigned int destcount; OSPTTRANHANDLE transaction = -1; int result = MODULE_RETURNCODE_FALSE; LOG(L_DBG, "osp: ospRequestRouting\n"); authtime = time(NULL); destcount = _osp_max_dests; if ((errorcode = OSPPTransactionNew(_osp_provider, &transaction)) != OSPC_ERR_NO_ERROR) { LOG(L_ERR, "osp: ERROR: failed to create new OSP transaction (%d)\n", errorcode); } else if ((ospGetRpidUserpart(msg, source, sizeof(source)) != 0) && (ospGetFromUserpart(msg, source, sizeof(source)) != 0)) { LOG(L_ERR, "osp: ERROR: failed to extract calling number\n"); } else if ((ospGetUriUserpart(msg, destination, sizeof(destination)) != 0) && (ospGetToUserpart(msg, destination, sizeof(destination)) != 0)) { LOG(L_ERR, "osp: ERROR: failed to extract called number\n"); } else if (ospGetCallId(msg, &(callids[0])) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract call id\n"); } else if (ospGetSourceAddress(msg, sourcedev, sizeof(sourcedev)) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract source address\n"); } else { ospConvertAddress(sourcedev, src, sizeof(src)); LOG(L_INFO, "osp: request auth and routing for: " "source '%s' " "source_port '%s' " "source_dev '%s' " "e164_source '%s' " "e164_dest '%s' " "call_id '%.*s' " "dest_count '%i'\n", _osp_device_ip, _osp_device_port, src, /* sourcedev in "[x.x.x.x]" or host.domain format */ source, destination, callids[0]->ospmCallIdLen, callids[0]->ospmCallIdVal, destcount ); /* try to request authorization */ errorcode = OSPPTransactionRequestAuthorisation( transaction, /* transaction handle */ _osp_device_ip, /* from the configuration file */ src, /* source of call, protocol specific, in OSP format */ source, /* calling number in nodotted e164 notation */ OSPC_E164, /* calling number format */ destination, /* called number */ OSPC_E164, /* called number format */ "", /* optional username string, used if no number */ callidnumber, /* number of call ids, here always 1 */ callids, /* sized-1 array of call ids */ preferred, /* preferred destinations, here always NULL */ &destcount, /* max destinations, after call dest_count */ &logsize, /* size allocated for detaillog (next param) 0=no log */ detaillog); /* memory location for detaillog to be stored */ if ((errorcode == OSPC_ERR_NO_ERROR) && (ospLoadRoutes(transaction, destcount, _osp_device_ip, sourcedev, destination, authtime) == 0)) { LOG(L_INFO, "osp: there are '%d' OSP routes, call_id '%.*s'\n", destcount, callids[0]->ospmCallIdLen, callids[0]->ospmCallIdVal); result = MODULE_RETURNCODE_TRUE; } else { LOG(L_ERR, "osp: ERROR: failed to request auth and routing (%i), call_id '%.*s\n", errorcode, callids[0]->ospmCallIdLen, callids[0]->ospmCallIdVal); switch (errorcode) { case OSPC_ERR_TRAN_ROUTE_BLOCKED: result = -403; break; case OSPC_ERR_TRAN_ROUTE_NOT_FOUND: result = -404; break; case OSPC_ERR_NO_ERROR: /* AuthRsp ok but ospLoadRoutes fails */ result = -500; break; default: result = MODULE_RETURNCODE_FALSE; break; } } } if (callids[0] != NULL) { OSPPCallIdDelete(&(callids[0])); } if (transaction != -1) { OSPPTransactionDelete(transaction); } return result; }