Example #1
0
int create_via(struct sip_msg* msg, char* s1, char* s2)
{
	char* via;
	unsigned int via_len;
	str ip, port;
	struct hostport hp;
	struct dest_info dst;

	ip.s = ip_addr2a(&msg->rcv.src_ip);
	ip.len = strlen(ip.s);

	port.s = int2str(msg->rcv.src_port, &port.len);

	hp.host = &ip;
	hp.port = &port;

	init_dst_from_rcv(&dst, &msg->rcv);
	via = via_builder(&via_len, &dst, 0, 0, &hp);
	if (!via) {
		ERR("Unable to build Via header field\n");
		return -1;
	}

	if (insert_fake_via(msg, via, via_len) < 0) {
		pkg_free(via);
		return -1;
	}

	if (insert_via_lump(msg, via, via_len - CRLF_LEN) < 0) {
		pkg_free(via);
		return -1;
	}

	return 1;
}
Example #2
0
/* 
 * process_stun_msg(): 
 * 			buf - incoming message
 * 			len - length of incoming message
 * 			ri  - information about socket that received a message and 
 *                also information about sender (its IP, port, protocol)
 * 
 * This function ensures processing of incoming message. It's common for both
 * TCP and UDP protocol. There is no other function as an interface.
 * 
 * Return value:	0	if there is no environment error
 * 					-1	if there is some enviroment error such as insufficiency
 * 						of memory
 * 
 */
int process_stun_msg(char* buf, unsigned len, struct receive_info* ri)
{
	struct stun_msg 			msg_req;
	struct stun_msg 			msg_res;
	struct dest_info			dst;
	struct stun_unknown_att*	unknown;
	USHORT_T					error_code;
	 
	memset(&msg_req, 0, sizeof(msg_req));
	memset(&msg_res, 0, sizeof(msg_res));
	
	msg_req.msg.buf.s = buf;
	msg_req.msg.buf.len = len;	
	unknown = NULL;
	error_code = RESPONSE_OK;
	
	if (stun_parse_header(&msg_req, &error_code) != 0) {
		goto error;
	}
	
	if (error_code == RESPONSE_OK) {
		if (stun_parse_body(&msg_req, &unknown, &error_code) != 0) {
			goto error;
		}
	}
	
	if (stun_create_response(&msg_req, &msg_res, ri,  
							unknown, error_code) != 0) {
		goto error;
	}
	
	init_dst_from_rcv(&dst, ri);

#ifdef EXTRA_DEBUG	
	struct ip_addr ip;
	su2ip_addr(&ip, &dst.to);
	LOG(L_DBG, "DEBUG: process_stun_msg: decoded request from (%s:%d)\n", ip_addr2a(&ip), 
		su_getport(&dst.to));
#endif
	
	/* send STUN response */
	if (msg_send(&dst, msg_res.msg.buf.s, msg_res.msg.buf.len) != 0) {
		goto error;
	}
	
#ifdef EXTRA_DEBUG
	LOG(L_DBG, "DEBUG: process_stun_msg: send response\n");
#endif
	clean_memory(&msg_req, &msg_res, unknown);
	return 0;
	
error:
#ifdef EXTRA_DEBUG
	LOG(L_DBG, "DEBUG: process_stun_msg: failed to decode request\n");
#endif
	clean_memory(&msg_req, &msg_res, unknown);
	return FATAL_ERROR;
}
Example #3
0
int tcp_http11_continue(struct tcp_connection *c)
{
	struct dest_info dst;
	char *p;
	struct msg_start fline;
	int ret;
	str msg;

	ret = 0;

	msg.s = c->req.start;
	msg.len = c->req.pos - c->req.start;
#ifdef READ_MSRP
	/* skip if MSRP message */
	if(c->req.flags&F_TCP_REQ_MSRP_FRAME)
		return 0;
#endif
	p = parse_first_line(msg.s, msg.len, &fline);
	if(p==NULL)
		return 0;

	if(fline.type!=SIP_REQUEST)
		return 0;

	/* check if http request */
	if(fline.u.request.version.len < HTTP_VERSION_LEN
			|| strncasecmp(fline.u.request.version.s,
				HTTP_VERSION, HTTP_VERSION_LEN))
		return 0;

	/* check for Expect header */
	if(strfindcasestrz(&msg, "Expect: 100-continue")!=NULL)
	{
		init_dst_from_rcv(&dst, &c->rcv);
		if (tcp_send(&dst, 0, HTTP11CONTINUE, HTTP11CONTINUE_LEN) < 0) {
			LM_ERR("HTTP/1.1 continue failed\n");
		}
	}
	/* check for Transfer-Encoding header */
	if(strfindcasestrz(&msg, "Transfer-Encoding: chunked")!=NULL)
	{
		c->req.flags |= F_TCP_REQ_BCHUNKED;
		ret = 1;
	}
	/* check for HTTP Via header
	 * - HTTP Via format is different that SIP Via
	 * - workaround: replace with Hia to be ignored by SIP parser
	 */
	if((p=strfindcasestrz(&msg, "\nVia:"))!=NULL)
	{
		p++;
		*p = 'H';
		LM_DBG("replaced HTTP Via with Hia [[\n%.*s]]\n", msg.len, msg.s);
	}
	return ret;
}
Example #4
0
static char* xhttp_to_sip(sip_msg_t* msg, int* new_msg_len)
{
	unsigned int len, via_len;
	char* via, *new_msg, *p;
	str ip, port;
	struct hostport hp;
	struct dest_info dst;
	
	ip.s = ip_addr2a(&msg->rcv.src_ip);
	ip.len = strlen(ip.s);
	port.s = int2str(msg->rcv.src_port, &port.len);
	hp.host = &ip;
	hp.port = &port;
	init_dst_from_rcv(&dst, &msg->rcv);
	via = via_builder(&via_len, &dst, 0, 0, &hp);
	if (via == 0)
	{
		LM_DBG("failed to build via\n");
		return 0;
	}
	len = via_len + msg->len;
	p = new_msg = pkg_malloc(len + 1);
	if (new_msg == 0)
	{
		LM_DBG("memory allocation failure (%d bytes)\n", len);
		pkg_free(via);
		return 0;
	}

	/* new message:
	 * <orig first line> 
	 * Via: <faked via>
	 * <orig http message w/o the first line>
	 */
	memcpy(p, msg->first_line.u.request.method.s, 
		   msg->first_line.len);
	p += msg->first_line.len;
	memcpy(p, via, via_len);
	p += via_len;
	memcpy(p,  SIP_MSG_START(msg) + msg->first_line.len, 
		   msg->len - msg->first_line.len);
	new_msg[len] = 0;
	pkg_free(via);
	*new_msg_len = len;
	return new_msg;
}
Example #5
0
/*
 * The function creates an ACK to 200 OK. Route set will be created
 * and parsed and the dst parameter will contain the destination to which
 * the request should be send. The function is used by tm when it
 * generates local ACK to 200 OK (on behalf of applications using uac)
 */
char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans,
					unsigned int branch, str *hdrs, str *body,
					unsigned int *len, struct dest_info* dst)
{
	char *req_buf, *p, *via;
	unsigned int via_len;
	char branch_buf[MAX_BRANCH_PARAM_LEN];
	int branch_len;
	str branch_str;
	struct hostport hp;
	struct rte* list;
	str contact, ruri, *cont;
	str next_hop;
	str body_len;
	str _to, *to = &_to;
#ifdef USE_DNS_FAILOVER
	struct dns_srv_handle dns_h;
#endif
#ifdef WITH_AS_SUPPORT
	/* With AS support, TM allows for external modules to generate building of
	 * the ACK; in this case, the ACK's retransmission buffer is built once
	 * and kept in memory (to help when retransmitted 2xx are received and ACK
	 * must be resent).
	 * Allocation of the string raw buffer that holds the ACK is piggy-backed
	 * with allocation of the retransmission buffer (since both have the same
	 * life-cycle): both the string buffer and retransm. buffer are placed
	 * into the same allocated chunk of memory (retr. buffer first, string
	 * buffer follows).In this case, the 'len' param is used as in-out
	 * parameter: 'in' to give the extra space needed by the retr. buffer,
	 * 'out' to return the lenght of the allocated string buffer.
	 */
	unsigned offset = *len;
#endif

	if (parse_headers(rpl, HDR_EOH_F, 0) == -1 || !rpl->to) {
		LM_ERR("Error while parsing headers.\n");
		return 0;
	} else {
		_to.s = rpl->to->name.s;
		_to.len = rpl->to->len;
	}

	if (get_contact_uri(rpl, &contact) < 0) {
		return 0;
	}

	if (eval_uac_routing(rpl, &Trans->uac[branch].request, &contact,
			&list, &ruri, &next_hop) < 0) {
		LM_ERR("failed to evaluate routing elements.\n");
		return 0;
	}
	LM_DBG("ACK RURI: `%.*s', NH: `%.*s'.\n", STR_FMT(&ruri),
			STR_FMT(&next_hop));

	if ((contact.s != ruri.s) || (contact.len != ruri.len)) {
		/* contact != ruri means that the next
		 * hop is a strict router, cont will be non-zero
		 * and print_routeset will append it at the end
		 * of the route set
		 */
		cont = &contact;
	} else {
		/* Next hop is a loose router, nothing to append */
		cont = 0;
	}

	/* method, separators, version: "ACK sip:[email protected] SIP/2.0" */
	*len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
	*len += ruri.len;

	/* dst */
	switch(cfg_get(tm, tm_cfg, local_ack_mode)){
		case 1:
			/* send the local 200 ack to the same dst as the corresp. invite*/
			*dst=Trans->uac[branch].request.dst;
			break;
		case 2:
			/* send the local 200 ack to the same dst as the 200 reply source*/
			init_dst_from_rcv(dst, &rpl->rcv);
			dst->send_flags=rpl->fwd_send_flags;
			break;
		case 0:
		default:
			/* rfc conformant behaviour: use the next_hop determined from the
			 * contact and the route set */
#ifdef USE_DNS_FAILOVER
		if (cfg_get(core, core_cfg, use_dns_failover)){
			dns_srv_handle_init(&dns_h);
			if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) ||
					(dst->send_sock==0)){
				dns_srv_handle_put(&dns_h);
				LM_ERR("no socket found\n");
				goto error;
			}
			dns_srv_handle_put(&dns_h); /* not needed any more */
		}else{
			if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) ||
					(dst->send_sock==0)){
				LM_ERR("no socket found\n");
				goto error;
			}
		}
#else /* USE_DNS_FAILOVER */
		if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) ||
				(dst->send_sock==0)){
			LM_ERR("no socket found\n");
			goto error;
		}
#endif /* USE_DNS_FAILOVER */
		break;
	}

	/* via */
	if (!t_calc_branch(Trans,  branch, branch_buf, &branch_len)) goto error;
	branch_str.s = branch_buf;
	branch_str.len = branch_len;
	set_hostport(&hp, 0);
	via = via_builder(&via_len, NULL, dst, &branch_str, 0, &hp);
	if (!via) {
		LM_ERR("No via header got from builder\n");
		goto error;
	}
	*len+= via_len;

	/* headers */
	*len += Trans->from.len + Trans->callid.len + to->len + Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN;

	/* copy'n'paste Route headers */

	*len += calc_routeset_len(list, cont);

	/* User Agent */
	if (server_signature) *len += user_agent_hdr.len + CRLF_LEN;
	/* extra headers */
	if (hdrs)
		*len += hdrs->len;
	/* body */
	if (body) {
		body_len.s = int2str(body->len, &body_len.len);
		*len += body->len;
	} else {
		body_len.len = 0;
		body_len.s = NULL; /*4gcc*/
		*len += 1; /* for the (Cont-Len:) `0' */
	}
	/* Content Length, EoM */
	*len += CONTENT_LENGTH_LEN + body_len.len + CRLF_LEN + CRLF_LEN;

#if WITH_AS_SUPPORT
	req_buf = shm_malloc(offset + *len + 1);
	req_buf += offset;
#else
	req_buf = shm_malloc(*len + 1);
#endif
	if (!req_buf) {
		LM_ERR("Cannot allocate memory (%u+1)\n", *len);
		goto error01;
	}
	p = req_buf;

	append_str( p, ACK, ACK_LEN );
	append_str( p, " ", 1 );
	append_str(p, ruri.s, ruri.len);
	append_str( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);

	/* insert our via */
	append_str(p, via, via_len);

	/*other headers*/
	append_str(p, Trans->from.s, Trans->from.len);
	append_str(p, Trans->callid.s, Trans->callid.len);
	append_str(p, to->s, to->len);

	append_str(p, Trans->cseq_n.s, Trans->cseq_n.len);
	append_str( p, " ", 1 );
	append_str( p, ACK, ACK_LEN);
	append_str(p, CRLF, CRLF_LEN);

	/* Routeset */
	p = print_rs(p, list, cont);

	/* User Agent header */
	if (server_signature) {
		append_str(p, user_agent_hdr.s, user_agent_hdr.len);
		append_str(p, CRLF, CRLF_LEN);
	}

	/* extra headers */
	if (hdrs)
		append_str(p, hdrs->s, hdrs->len);

	/* Content Length, EoH, (body) */
	if (body) {
		append_str(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
		append_str(p, body_len.s, body_len.len);
		append_str(p, /*end crr. header*/CRLF /*EoH*/CRLF, CRLF_LEN +
				CRLF_LEN);
		append_str(p, body->s, body->len);
	} else {
		append_str(p, CONTENT_LENGTH "0" CRLF CRLF,
				CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
	}

	/* EoM */
	*p = 0;

	pkg_free(via);
	free_rte_list(list);
	return req_buf;

error01:
	pkg_free(via);
error:
	free_rte_list(list);
	return 0;
}
Example #6
0
int tcp_read_req(struct tcp_connection* con, int* bytes_read, int* read_flags)
{
	int bytes;
	int total_bytes;
	int resp;
	long size;
	struct tcp_req* req;
	struct dest_info dst;
	char c;
	int ret;
		
		bytes=-1;
		total_bytes=0;
		resp=CONN_RELEASE;
		req=&con->req;

again:
		if (likely(req->error==TCP_REQ_OK)){
#ifdef READ_WS
			if (unlikely(con->type == PROTO_WS || con->type == PROTO_WSS))
				bytes=tcp_read_ws(con, read_flags);
			else
#endif
				bytes=tcp_read_headers(con, read_flags);
#ifdef EXTRA_DEBUG
						/* if timeout state=0; goto end__req; */
			LM_DBG("read= %d bytes, parsed=%d, state=%d, error=%d\n",
					bytes, (int)(req->parsed-req->start), req->state,
					req->error );
			LM_DBG("last char=0x%02X, parsed msg=\n%.*s\n",
					*(req->parsed-1), (int)(req->parsed-req->start),
					req->start);
#endif
			if (unlikely(bytes==-1)){
				LOG(cfg_get(core, core_cfg, corelog),
						"ERROR: tcp_read_req: error reading \n");
				resp=CONN_ERROR;
				goto end_req;
			}
			total_bytes+=bytes;
			/* eof check:
			 * is EOF if eof on fd and req.  not complete yet,
			 * if req. is complete we might have a second unparsed
			 * request after it, so postpone release_with_eof
			 */
			if (unlikely((con->state==S_CONN_EOF) && 
						(! TCP_REQ_COMPLETE(req)))) {
				LM_DBG("EOF\n");
				resp=CONN_EOF;
				goto end_req;
			}
		}
		if (unlikely(req->error!=TCP_REQ_OK)){
			LM_ERR("bad request, state=%d, error=%d buf:\n%.*s\nparsed:\n%.*s\n",
					req->state, req->error,
					(int)(req->pos-req->buf), req->buf,
					(int)(req->parsed-req->start), req->start);
			LM_DBG("received from: port %d\n", con->rcv.src_port);
			print_ip("received from: ip", &con->rcv.src_ip, "\n");
			resp=CONN_ERROR;
			goto end_req;
		}
		if (likely(TCP_REQ_COMPLETE(req))){
#ifdef EXTRA_DEBUG
			LM_DBG("end of header part\n");
			LM_DBG("received from: port %d\n", con->rcv.src_port);
			print_ip("received from: ip", &con->rcv.src_ip, "\n");
			LM_DBG("headers:\n%.*s.\n",
					(int)(req->body-req->start), req->start);
#endif
			if (likely(TCP_REQ_HAS_CLEN(req))){
				LM_DBG("content-length=%d\n", req->content_len);
#ifdef EXTRA_DEBUG
				LM_DBG("body:\n%.*s\n", req->content_len,req->body);
#endif
			}else{
				if (cfg_get(tcp, tcp_cfg, accept_no_cl)==0) {
					req->error=TCP_REQ_BAD_LEN;
					LM_ERR("content length not present or unparsable\n");
					resp=CONN_ERROR;
					goto end_req;
				}
			}
			/* if we are here everything is nice and ok*/
			resp=CONN_RELEASE;
#ifdef EXTRA_DEBUG
			LM_DBG("receiving msg(%p, %d)\n",
					req->start, (int)(req->parsed-req->start));
#endif
			/* rcv.bind_address should always be !=0 */
			bind_address=con->rcv.bind_address;
			/* just for debugging use sendipv4 as receiving socket  FIXME*/
			/*
			if (con->rcv.dst_ip.af==AF_INET6){
				bind_address=sendipv6_tcp;
			}else{
				bind_address=sendipv4_tcp;
			}
			*/
			con->rcv.proto_reserved1=con->id; /* copy the id */
			c=*req->parsed; /* ugly hack: zero term the msg & save the
							   previous char, req->parsed should be ok
							   because we always alloc BUF_SIZE+1 */
			*req->parsed=0;

			if (req->state==H_PING_CRLF) {
				init_dst_from_rcv(&dst, &con->rcv);

				if (tcp_send(&dst, 0, CRLF, CRLF_LEN) < 0) {
					LM_ERR("CRLF ping: tcp_send() failed\n");
				}
				ret = 0;
			} else if (unlikely(req->state==H_STUN_END)) {
				/* stun request */
				ret = stun_process_msg(req->start, req->parsed-req->start,
									 &con->rcv);
			} else
#ifdef READ_MSRP
			// if (unlikely(req->flags&F_TCP_REQ_MSRP_FRAME)){
			if (unlikely(req->state==H_MSRP_FINISH)){
				/* msrp frame */
				ret = receive_tcp_msg(req->start, req->parsed-req->start,
									&con->rcv, con);
			}else
#endif
#ifdef READ_HTTP11
			if (unlikely(req->state==H_HTTP11_CHUNK_FINISH)){
				/* http chunked request */
				req->body[req->content_len] = 0;
				ret = receive_tcp_msg(req->start,
						req->body + req->content_len - req->start,
						&con->rcv, con);
			}else
#endif
#ifdef READ_WS
			if (unlikely(con->type == PROTO_WS || con->type == PROTO_WSS)){
				ret = receive_tcp_msg(req->start, req->parsed-req->start,
									&con->rcv, con);
			}else
#endif
				ret = receive_tcp_msg(req->start, req->parsed-req->start,
									&con->rcv, con);
				
			if (unlikely(ret < 0)) {
				*req->parsed=c;
				resp=CONN_ERROR;
				goto end_req;
			}
			*req->parsed=c;
			
			/* prepare for next request */
			size=req->pos-req->parsed;
			req->start=req->buf;
			req->body=0;
			req->error=TCP_REQ_OK;
			req->state=H_SKIP_EMPTY;
			req->flags=0;
			req->content_len=0;
			req->bytes_to_go=0;
			req->pos=req->buf+size;
			
			if (unlikely(size)){ 
				memmove(req->buf, req->parsed, size);
				req->parsed=req->buf; /* fix req->parsed after using it */
#ifdef EXTRA_DEBUG
				LM_DBG("preparing for new request, kept %ld bytes\n", size);
#endif
				/*if we still have some unparsed bytes, try to parse them too*/
				goto again;
			} else if (unlikely(con->state==S_CONN_EOF)){
				LM_DBG("EOF after reading complete request\n");
				resp=CONN_EOF;
			}
			req->parsed=req->buf; /* fix req->parsed */
		}
		
		
	end_req:
		if (likely(bytes_read)) *bytes_read=total_bytes;
		return resp;
}