⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_utils.c

📁 简单的基于SIP的会话边界控制器
💻 C
📖 第 1 页 / 共 2 页
字号:
#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", &param);
	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, &param);
		if (param && param->gvalue) {
			MD5Update(&Md5Ctx, param->gvalue, strlen(param->gvalue));
		}

		/* Tag in From header */
		osip_from_get_tag(sip_msg->from, &param);
		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 + -