Example #1
0
/*
 * Replaces ip:port pair in the Contact: field with the source address
 * of the packet.
 */
static int
fix_nated_contact_f(struct sip_msg* msg, char* str1, char* str2)
{
	int offset, len, len1;
	char *cp, *buf, temp[2];
	contact_t *c;
	struct lump *anchor;
	struct sip_uri uri;
	str hostport;

	if (get_contact_uri(msg, &uri, &c) == -1)
		return -1;
	/* for UAs behind NAT we have to hope that they will reuse the
	 * TCP connection, otherwise they are lost any way. So this check
	 * does not make too much sense.
	if (uri.proto != PROTO_UDP && uri.proto != PROTO_NONE)
		return -1;
	*/
	if ((c->uri.s < msg->buf) || (c->uri.s > (msg->buf + msg->len))) {
		LOG(L_ERR, "ERROR: you can't call fix_nated_contact twice, "
		    "check your config!\n");
		return -1;
	}

	offset = c->uri.s - msg->buf;
	anchor = del_lump(msg, offset, c->uri.len, HDR_CONTACT_T);
	if (anchor == 0)
		return -1;

	hostport = uri.host;
	if (uri.port.len > 0)
		hostport.len = uri.port.s + uri.port.len - uri.host.s;

	cp = ip_addr2a(&msg->rcv.src_ip);
	len = c->uri.len + strlen(cp) + 6 /* :port */ - hostport.len + 1;
	buf = pkg_malloc(len);
	if (buf == NULL) {
		LOG(L_ERR, "ERROR: fix_nated_contact: out of memory\n");
		return -1;
	}
	temp[0] = hostport.s[0];
	temp[1] = c->uri.s[c->uri.len];
	c->uri.s[c->uri.len] = hostport.s[0] = '\0';
	len1 = snprintf(buf, len, "%s%s:%d%s", c->uri.s, cp, msg->rcv.src_port,
	    hostport.s + hostport.len);
	if (len1 < len)
		len = len1;
	hostport.s[0] = temp[0];
	c->uri.s[c->uri.len] = temp[1];
	if (insert_new_lump_after(anchor, buf, len, HDR_CONTACT_T) == 0) {
		pkg_free(buf);
		return -1;
	}
	c->uri.s = buf;
	c->uri.len = len;

	return 1;
}
Example #2
0
/*
 * Extract all information from a request 
 * and update a dialog structure
 */
static inline int request2dlg(struct sip_msg* _m, dlg_t* _d)
{
	str contact, rtag, callid;

	if (parse_headers(_m, HDR_EOH_F, 0) == -1) {
		LOG(L_ERR, "request2dlg(): Error while parsing headers");
		return -1;
	}

	if (get_contact_uri(_m, &contact) < 0) return -2;
	if (contact.len) {
		if (_d->rem_target.s) shm_free(_d->rem_target.s);
		if (_d->dst_uri.s) {
			shm_free(_d->dst_uri.s);
			_d->dst_uri.s = 0;
			_d->dst_uri.len = 0;
		}
		if (str_duplicate(&_d->rem_target, &contact) < 0) return -3;
	}
	
	if (get_from_tag(_m, &rtag) < 0) goto err1;
	if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1;

	if (get_callid(_m, &callid) < 0) goto err2;
	if (callid.len && str_duplicate(&_d->id.call_id, &callid) < 0) goto err2;

	if (get_cseq_value(_m, &_d->rem_seq.value) < 0) goto err3;
	_d->rem_seq.is_set = 1;

	if (get_dlg_uri(_m->from, &_d->rem_uri) < 0) goto err3;
	if (get_dlg_uri(_m->to, &_d->loc_uri) < 0) goto err4;

	if (get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0) goto err5;	

	return 0;
 err5:
	if (_d->loc_uri.s) shm_free(_d->loc_uri.s);
	_d->loc_uri.s = 0;
	_d->loc_uri.len = 0;
 err4:
	if (_d->rem_uri.s) shm_free(_d->rem_uri.s);
	_d->rem_uri.s = 0;
	_d->rem_uri.len = 0;
 err3:
	if (_d->id.call_id.s) shm_free(_d->id.call_id.s);
	_d->id.call_id.s = 0;
	_d->id.call_id.len = 0;
 err2:
	if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
	_d->id.rem_tag.s = 0;
	_d->id.rem_tag.len = 0;
 err1:
	if (_d->rem_target.s) shm_free(_d->rem_target.s);
	_d->rem_target.s = 0;
	_d->rem_target.len = 0;
	return -4;
}
Example #3
0
/*
 * Handle dialog in DLG_CONFIRMED state, we will be processing
 * a response to a request sent within a dialog
 */
static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m, 
		target_refresh_t is_target_refresh)
{
	int code;
	str contact;

	code = _m->first_line.u.reply.statuscode;	

	     /* Dialog has been already confirmed, that means we received
	      * a response to a request sent within the dialog. We will
	      * update remote target URI if and only if the message sent was
	      * a target refresher. 
	      */

	     /* IF we receive a 481 response, terminate the dialog because
	      * the remote peer indicated that it didn't have the dialog
	      * state anymore, signal this termination with a positive return
	      * value
	      */
	if (code == 481) {
		_d->state = DLG_DESTROYED;
		return 1;
	}

	     /* Do nothing if not 2xx */
	if ((code < 200) || (code >= 300)) return 0;
	
	if (refresh_dialog_resp(_m, is_target_refresh)) {
		     /* Get contact if any and update remote target */
		if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
			LOG(L_ERR, "dlg_confirmed_resp_uac(): Error while parsing headers\n");
			return -2;
		}

		     /* Try to extract contact URI */
		if (get_contact_uri(_m, &contact) < 0) return -3;
		     /* If there is a contact URI */
		if (contact.len) {
			     /* Free old remote target and destination uri if any */
			if (_d->rem_target.s) shm_free(_d->rem_target.s);
			if (_d->dst_uri.s) {
				shm_free(_d->dst_uri.s);
				_d->dst_uri.s = 0;
				_d->dst_uri.len = 0;
			}
				
			     /* Duplicate new remote target */
			if (str_duplicate(&_d->rem_target, &contact) < 0) return -4;
		}

		if (calculate_hooks(_d) < 0)
			return -1;
	}

	return 0;
}
Example #4
0
/*
 * test for occurrence of RFC1918 IP address in Contact HF
 */
static int
contact_1918(struct sip_msg* msg)
{
	struct sip_uri uri;
	contact_t* c;

	if (get_contact_uri(msg, &uri, &c) == -1)
		return -1;

	return (is1918addr(&(uri.host)) == 1) ? 1 : 0;
}
Example #5
0
/*
 * UAS side - update a dialog from a request
 */
int dlg_request_uas(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_refresh)
{
	str contact;
	int cseq;

	if (!_d || !_m) {
		LOG(L_ERR, "dlg_request_uas(): Invalid parameter value\n");
		return -1;
	}

	     /* We must check if the request is not out of order or retransmission
	      * first, if so then we will not update anything
	      */
	if (parse_headers(_m, HDR_CSEQ_F, 0) == -1) {
		LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n");
		return -2;
	}
	if (get_cseq_value(_m, (unsigned int*)&cseq) < 0) return -3;
	if (_d->rem_seq.is_set && (cseq <= _d->rem_seq.value)) return 0;

	     /* Neither out of order nor retransmission -> update */
	_d->rem_seq.value = cseq;
	_d->rem_seq.is_set = 1;
	
	     /* We will als update remote target URI if the message 
	      * is target refresher
	      */
	if (refresh_dialog_req(_m, is_target_refresh)) { /* target refresher */
		if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) {
			LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n");
			return -4;
		}
		
		if (get_contact_uri(_m, &contact) < 0) return -5;
		if (contact.len) {
			if (_d->rem_target.s) shm_free(_d->rem_target.s);
			if (_d->dst_uri.s) {
				shm_free(_d->dst_uri.s);
				_d->dst_uri.s = 0;
				_d->dst_uri.len = 0;
			}
			if (str_duplicate(&_d->rem_target, &contact) < 0) return -6;
		}

		if (calculate_hooks(_d) < 0)
			return -1;
		
	}

	return 0;
}
Example #6
0
static int
contact_rport(struct sip_msg* msg)
{
	struct sip_uri uri;
	contact_t* c;

	if (get_contact_uri(msg, &uri, &c) == -1) {
		return -1;
	}

	if (msg->rcv.src_port != (uri.port_no ? uri.port_no : SIP_PORT)) {
		return 1;
	} else {
		return 0;
	}
}
Example #7
0
/*
 * Extract all necessary information from a response and put it
 * in a dialog structure
 */
static inline int response2dlg(struct sip_msg* _m, dlg_t* _d)
{
	str contact, rtag;
	rtag.s=0;

	     /* Parse the whole message, we will need all Record-Route headers */
	if (parse_headers(_m, HDR_EOH_F, 0) == -1) {
		LOG(L_ERR, "response2dlg(): Error while parsing headers\n");
		return -1;
	}
	
	if (get_contact_uri(_m, &contact) < 0) return -2;
	if (_d->rem_target.s) {
		shm_free(_d->rem_target.s);
		_d->rem_target.s = 0; 
		_d->rem_target.len = 0;
	}
	if (_d->dst_uri.s) {
		shm_free(_d->dst_uri.s);
		_d->dst_uri.s = 0; 
		_d->dst_uri.len = 0;
	}
	if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3;
	
	if (get_to_tag(_m, &rtag) < 0) goto err1;
	//Its unlikely needed to update the tag with responses but for some reason i do it
	if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s); 
	
	if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1;
	
	if (_d->route_set) shm_free_rr(&_d->route_set);
	if (get_route_set(_m, &_d->route_set, REVERSE_ORDER) < 0) goto err2;

	return 0;
 err2:
	if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s);
	_d->id.rem_tag.s = 0;
	_d->id.rem_tag.len = 0;

 err1:
	if (_d->rem_target.s) shm_free(_d->rem_target.s);
	_d->rem_target.s = 0;
	_d->rem_target.len = 0;
	return -4;
}
Example #8
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 #9
0
/*
 * The function creates an ACK for a local INVITE. If 200 OK, route set 
 * will be created and parsed
 */
char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans,
							unsigned int branch, str* to, unsigned int *len)
{
	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;
	struct socket_info* send_sock;
	str next_hop;


	if (rpl->first_line.u.reply.statuscode < 300 ) {
		/* build e2e ack for 2xx reply -> we need the route set */
		if (get_contact_uri(rpl, &contact) < 0) {
			return 0;
		}

		if (process_routeset(rpl, &contact, &list, &ruri, &next_hop) < 0) {
			return 0;
		}

		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;
		}
	} else {
		/* build hop-by-hop ack for negative reply ->
		 * ruri is the same as in INVITE; no route set */
		ruri = Trans->uac[branch].uri;
		cont = 0;
		list = 0;
	}

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

	/* use same socket as for INVITE -bogdan */
	send_sock = Trans->uac[branch].request.dst.send_sock;

	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);

	/* build via */
	via = via_builder(&via_len, send_sock, &branch_str, 0, 
			send_sock->proto, &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_header.len + CRLF_LEN;

	/* Content Length, EoM */
	*len += CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN;

	req_buf = shm_malloc(*len + 1);
	if (!req_buf) {
		LM_ERR("no more share memory\n");
		goto error01;
	}
	p = req_buf;

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

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

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

	append_string(p, Trans->cseq_n.s, Trans->cseq_n.len);
	*(p++) = ' ';
	append_string(p, ACK CRLF, ACK_LEN+CRLF_LEN);

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

	/* User Agent header, Content Length, EoM */
	if (server_signature) {
		append_string(p, user_agent_header.s, user_agent_header.len);
		append_string(p, CRLF CONTENT_LENGTH "0" CRLF CRLF,
			CRLF_LEN+CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
	} else {
		append_string(p, CONTENT_LENGTH "0" CRLF CRLF,
			CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
	}
	*p = 0;

	pkg_free(via);
	free_rte_list(list);
	return req_buf;
error01:
	pkg_free(via);
error:
	free_rte_list(list);
	return 0;
}