📄 sip_utils.c
字号:
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <pwd.h>
#include <osipparser2/osip_parser.h>
#include <osipparser2/osip_md5.h>
#include "nsrsbc.h"
#include "regctl.h"
#include "sessctl.h"
#include "cmdline.h"
extern struct sip_reg_ctl_t sip_reg_ctl[REGNUM_SIZE];
extern struct gengetopt_args_info args_info;
#define HASHLEN 16
typedef char HASH[HASHLEN];
#define HASHHEXLEN 32
typedef char HASHHEX[HASHHEXLEN+1];
#define IN
#define OUT
void CvtHex(IN HASH Bin, OUT HASHHEX Hex) {
unsigned short i;
unsigned char j;
for (i = 0; i < HASHLEN; i++) {
j = (Bin[i] >> 4) & 0xf;
if (j <= 9)
Hex[i*2] = (j + '0');
else
Hex[i*2] = (j + 'a' - 10);
j = Bin[i] & 0xf;
if (j <= 9)
Hex[i*2+1] = (j + '0');
else
Hex[i*2+1] = (j + 'a' - 10);
};
Hex[HASHHEXLEN] = '\0';
}
/*
* Figures out if this is an outgoing or incoming request/response.
* The direction is stored in the ticket->direction property.
*
* RETURNS
* STS_SUCCESS on success
* STS_FAILURE if unable to determine
*/
int sip_find_direction(sip_ticket_t *ticket) {
int type;
int i, sts;
char* requ_client;
char *callid;
struct sockaddr_in *from;
osip_message_t *request;
osip_message_t *response;
from = &ticket->from;
request = ticket->sipmsg;
response = ticket->sipmsg;
type = 0;
ticket->direction = 0;
/* SIP Message from internal to external except REGISTER must
* use IP + Port in the sip_reg_ctl table.
*/
sts = regctl_find(sip_reg_ctl, from->sin_addr, from->sin_port, REGNUM_SIZE);
if (sts >= 0) {
/* find the host */
if (MSG_IS_REQUEST(ticket->sipmsg)) {
type=REQTYP_OUTGOING;
} else {
type=RESTYP_OUTGOING;
}
}
/*
* is the telegram directed to an internally registered host?
* -> it must be an INCOMING request
*/
if (type == 0) {
for (i=0; i < REGNUM_SIZE; i++) {
if (sip_reg_ctl[i].active == 0) continue;
if (MSG_IS_REQUEST(ticket->sipmsg)) {
/* need check the hostname is outaddr_arg?? and check To header or Request-uri?? */
requ_client = osip_uri_get_username(request->to->url);
sts = regctl_finduser(sip_reg_ctl, requ_client, REGNUM_SIZE);
if (sts >= 0) {
type = REQTYP_INCOMING;
break;
}
} else {
/* check call-id or From header?? */
// osip_call_id_to_str(request->call_id,&callid);
// sts = sessctl_find(sip_sess_ctl,callid,SESSNUM_SIZE);
requ_client = osip_uri_get_username(request->from->url);
sts = regctl_finduser(sip_reg_ctl, requ_client, REGNUM_SIZE);
if (sts >= 0) {
type=RESTYP_INCOMING;
break;
}
}
}
}
if (type == 0) {
printf("ERROR:sip_find_direction: unable to determine direction of SIP packet\n");
return STS_FAILURE;
}
ticket->direction = type;
return STS_SUCCESS;
}
/*
* SIP_CALCULATE_BRANCH
*
* Calculates a branch parameter according to RFC3261 section 16.11
*
* The returned 'id' will be HASHHEXLEN + strlen(magic_cookie)
* characters (32 + 7) long. The caller must supply at least this
* amount of space in 'id'.
*
* RETURNS
* STS_SUCCESS on success
* STS_FAILURE on error
*
* RFC3261 section 16.11 recommends the following procedure:
* The stateless proxy MAY use any technique it likes to guarantee
* uniqueness of its branch IDs across transactions. However, the
* following procedure is RECOMMENDED. The proxy examines the
* branch ID in the topmost Via header field of the received
* request. If it begins with the magic cookie, the first
* component of the branch ID of the outgoing request is computed
* as a hash of the received branch ID. Otherwise, the first
* component of the branch ID is computed as a hash of the topmost
* Via, the tag in the To header field, the tag in the From header
* field, the Call-ID header field, the CSeq number (but not
* method), and the Request-URI from the received request. One of
* these fields will always vary across two different
* transactions.
*
* The branch value will consist of:
* - magic cookie "z9hG4bK"
* - 1st part (unique calculated ID
* - 2nd part (value for loop detection) <<- not yet used by nsrsbc
*/
int sip_calculate_branch_id(sip_ticket_t *ticket, char *id) {
osip_message_t *sip_msg = ticket->sipmsg;
static char *magic_cookie = "z9hG4bK";
osip_via_t *via;
osip_uri_param_t *param = NULL;
osip_call_id_t *call_id = NULL;
HASHHEX hashstring;
hashstring[0]='\0';
/*
* Examine topmost via and look for a magic cookie.
* If it is there, I use THIS branch parameter as input for
* our hash calculation
*/
via = osip_list_get(sip_msg->vias, 0);
if (via == NULL) {
printf("ERROR:calculate branch id: have a SIP message without any via header\n");
return STS_FAILURE;
}
param = NULL;
osip_via_param_get_byname(via, "branch", ¶m);
if (param && param->gvalue) {
if (strncmp(param->gvalue, magic_cookie, strlen(magic_cookie))==0) {
/* calculate MD5 hash */
MD5_CTX Md5Ctx;
HASH HA1;
MD5Init(&Md5Ctx);
MD5Update(&Md5Ctx, param->gvalue, strlen(param->gvalue));
MD5Final(HA1, &Md5Ctx);
CvtHex(HA1, hashstring);
}
}
/*
* If I don't have a branch parameter in the existing topmost via,
* then I need:
* - the topmost via
* - the tag in the To header field
* - the tag in the From header field
* - the Call-ID header field
* - the CSeq number (but not method)
* - the Request-URI from the received request
*/
if (hashstring[0] == '\0') {
/* calculate MD5 hash */
MD5_CTX Md5Ctx;
HASH HA1;
char *tmp;
MD5Init(&Md5Ctx);
/* topmost via */
osip_via_to_str(via, &tmp);
if (tmp) {
MD5Update(&Md5Ctx, tmp, strlen(tmp));
osip_free(tmp);
}
/* Tag in To header */
osip_to_get_tag(sip_msg->to, ¶m);
if (param && param->gvalue) {
MD5Update(&Md5Ctx, param->gvalue, strlen(param->gvalue));
}
/* Tag in From header */
osip_from_get_tag(sip_msg->from, ¶m);
if (param && param->gvalue) {
MD5Update(&Md5Ctx, param->gvalue, strlen(param->gvalue));
}
/* Call-ID */
call_id = osip_message_get_call_id(sip_msg);
osip_call_id_to_str(call_id, &tmp);
if (tmp) {
MD5Update(&Md5Ctx, tmp, strlen(tmp));
osip_free(tmp);
}
/* CSeq number (but not method) */
tmp = osip_cseq_get_number(sip_msg->cseq);
if (tmp) {
MD5Update(&Md5Ctx, tmp, strlen(tmp));
osip_free(tmp);
}
/* Request URI */
osip_uri_to_str(sip_msg->req_uri, &tmp);
if (tmp) {
MD5Update(&Md5Ctx, tmp, strlen(tmp));
osip_free(tmp);
}
MD5Final(HA1, &Md5Ctx);
CvtHex(HA1, hashstring);
}
/* include the magic cookie */
sprintf(id, "%s%s", magic_cookie, hashstring);
return STS_SUCCESS;
}
/*
* check if a given osip_via_t is local. I.e. its address is owned
* by my inbound or outbound interface
*
* RETURNS
* STS_TRUE if the given VIA is one of my interfaces
* STS_FALSE otherwise
*/
int is_via_local(osip_via_t *via) {
int found = 0;
int port = 0;
if (via == NULL) {
printf("ERROR: called is_via_local with NULL via\n");
return STS_FALSE;
}
if (via->port) port = atoi(via->port);
if (!strcmp(via->host, args_info.inaddr_arg)) {
found = 1;
if ((port != 0) && (port != SIP_LISTENING_PORT))
found = 0;
}
return (found)? STS_TRUE : STS_FALSE;
}
/*
* SIP_ADD_MYVIA
*
* RETURNS
* STS_SUCCESS on success
* STS_FAILURE on error
*/
int sip_add_myvia(sip_ticket_t *ticket) {
char tmp[URL_STRING_SIZE];
char branch_id[VIA_BRANCH_SIZE];
osip_via_t *via;
int sts;
sts = sip_calculate_branch_id(ticket, branch_id);
/* my interface address:
* args_info.inaddr_arg
* args_info.outaddr_arg
*/
sprintf(tmp, "SIP/2.0/UDP %s:%d;branch=%s", args_info.inaddr_arg,
SIP_LISTENING_PORT, branch_id);
sts = osip_via_init(&via);
if (sts!=0) return STS_FAILURE;
sts = osip_via_parse(via, tmp);
if (sts!=0) return STS_FAILURE;
osip_list_add(ticket->sipmsg->vias, via, 0);
return STS_SUCCESS;
}
/*
* SIP_DEL_MYVIA
*
* RETURNS
* STS_SUCCESS on success
* STS_FAILURE on error
*/
int sip_del_myvia(sip_ticket_t *ticket) {
osip_via_t *via;
int sts;
int port = 0;
via = osip_list_get(ticket->sipmsg->vias, 0);
if ( via == NULL ) {
printf("ERROR: sip_del_via: Got empty VIA list!\n");
return STS_FAILURE;
}
if ( is_via_local(via) == STS_FALSE ) {
printf("ERROR: sip_del_myvia: the VIA is not mine! host = %s\n", via->host);
return STS_FAILURE;
}
sts = osip_list_remove(ticket->sipmsg->vias, 0);
osip_via_free(via);
return STS_SUCCESS;
}
/*
* SIP_REWRITE_VIA
*
* rewrite the VIA header
*
* RETURNS
* STS_SUCCESS on success
* STS_FAILURE on error
*/
int sip_rewrite_via(osip_message_t *mymsg, int type, int idx) {
/*
* Outgoing Request and Incoming Response need to do this
* eg: 10.0.0.5 <--> 192.168.0.5
* branch rewrite?? now do not rewrite
*/
osip_via_t *via;
osip_message_get_via(mymsg, 0, &via);
if ( via == NULL ) {
printf("ERROR: sip_rewrite_via: Can't rewrite via: no via header!\n");
return STS_FAILURE;
}
if (type == REQTYP_OUTGOING) {
char via_port[5];
sprintf(via_port, "%d", SIP_LISTENING_PORT);
osip_list_remove(mymsg->vias, 0);
if (via->host) {
osip_free(via->host);
via->host = NULL;
}
osip_via_set_host(via, osip_strdup(args_info.outaddr_arg));
if (via->port) {
osip_free(via->port);
via->port = NULL;
osip_via_set_port(via, osip_strdup(via_port));
}
osip_list_add(mymsg->vias, via, 0);
} else if (type == RESTYP_INCOMING) {
if ((idx >= SESSNUM_SIZE) || (idx < 0)) return STS_FAILURE;
osip_list_remove(mymsg->vias, 0);
if (via->host) {
osip_free(via->host);
via->host = NULL;
}
osip_via_set_host(via, osip_strdup(sip_sess_ctl[idx].from_host));
if (via->port) {
osip_free(via->port);
via->port = NULL;
osip_via_set_port(via, osip_strdup(sip_sess_ctl[idx].from_port));
}
osip_list_add(mymsg->vias, via, 0);
}
return STS_SUCCESS;
}
/*
* SIP_REWRITE_CONTACT
*
* rewrite the Contact header
*
* RETURNS
* STS_SUCCESS on success
* STS_FAILURE on error
*/
int sip_rewrite_contact(osip_message_t *mymsg) {
/* Outgoing Request and Outgoing Response need to do this
* 10.0.0.5 --> 192.168.0.5
*/
osip_contact_t *contact;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -