Example #1
0
/*! \brief Function which applies a negotiated stream */
static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
				       const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
				       const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
{
	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
	char host[NI_MAXHOST];
	struct t38_state *state;

	if (!session_media->udptl) {
		return 0;
	}

	if (!(state = t38_state_get_or_alloc(session))) {
		return -1;
	}

	ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));

	/* Ensure that the address provided is valid */
	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
		/* The provided host was actually invalid so we error out this negotiation */
		return -1;
	}

	ast_sockaddr_set_port(addrs, remote_stream->desc.port);
	ast_udptl_set_peer(session_media->udptl, addrs);

	t38_interpret_sdp(state, session, session_media, remote_stream);

	return 0;
}
Example #2
0
int ooSocketBind (OOSOCKET socket, OOIPADDR addr, int port) 
{
   struct ast_sockaddr m_addr;

   memset(&m_addr, 0, sizeof(m_addr));


   if (socket == OOSOCKET_INVALID)
   { 
      OOTRACEERR1("Error:Invalid socket passed to bind\n");
      return ASN_E_INVSOCKET;
   }

   ast_sockaddr_copy(&m_addr, &addr);
   ast_sockaddr_set_port(&m_addr, port);

   if (ast_bind(socket, &m_addr) < 0) {
      if (errno != EADDRINUSE) {
      	perror ("bind");
      	OOTRACEERR2("Error:Bind failed, error: %d\n", errno);
      }
      return ASN_E_INVSOCKET;
   }

   return ASN_OK;
}
Example #3
0
/*! \brief See if we pass debug IP filter */
static inline int pjsip_log_test_addr(const char *address, int port)
{
	struct ast_sockaddr test_addr;
	if (logging_mode == LOGGING_MODE_DISABLED) {
		return 0;
	}

	/* A null logging address means we'll debug any address */
	if (ast_sockaddr_isnull(&log_addr)) {
		return 1;
	}

	/* A null address was passed in. Just reject it. */
	if (ast_strlen_zero(address)) {
		return 0;
	}

	ast_sockaddr_parse(&test_addr, address, PARSE_PORT_IGNORE);
	ast_sockaddr_set_port(&test_addr, port);

	/* If no port was specified for a debug address, just compare the
	 * addresses, otherwise compare the address and port
	 */
	if (ast_sockaddr_port(&log_addr)) {
		return !ast_sockaddr_cmp(&log_addr, &test_addr);
	} else {
		return !ast_sockaddr_cmp_addr(&log_addr, &test_addr);
	}
}
Example #4
0
static int apply_acl(pjsip_rx_data *rdata, struct ast_acl_list *acl)
{
	struct ast_sockaddr addr;

	if (ast_acl_list_is_empty(acl)) {
		return 0;
	}

	memset(&addr, 0, sizeof(addr));
	ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
	ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);

	if (ast_apply_acl(acl, &addr, "SIP ACL: ") != AST_SENSE_ALLOW) {
		ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&addr));
		return 1;
	}
	return 0;
}
Example #5
0
int ooSocketConnect (OOSOCKET socket, const char* host, int port) 
{
   struct ast_sockaddr m_addr;

   if (socket == OOSOCKET_INVALID)
   { 
      return ASN_E_INVSOCKET;
   }
   
   memset (&m_addr, 0, sizeof (m_addr));
   ast_parse_arg(host, PARSE_ADDR, &m_addr);
   ast_sockaddr_set_port(&m_addr, port);

   if (ast_connect(socket, &m_addr))
   {
      return ASN_E_INVSOCKET;
   }
   return ASN_OK;
}
Example #6
0
static int apply_endpoint_acl(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint)
{
	struct ast_sockaddr addr;

	if (ast_acl_list_is_empty(endpoint->acl)) {
		return 0;
	}

	memset(&addr, 0, sizeof(addr));
	ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
	ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);

	if (ast_apply_acl(endpoint->acl, &addr, "SIP ACL: ") != AST_SENSE_ALLOW) {
		log_failed_request(rdata, "Not match Endpoint ACL", 0, 0);
		ast_sip_report_failed_acl(endpoint, rdata, "not_match_endpoint_acl");
		return 1;
	}
	return 0;
}
Example #7
0
/*! \brief Function which processes ICE attributes in an audio stream */
static void process_ice_attributes(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
				   const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
{
	struct ast_rtp_engine_ice *ice;
	const pjmedia_sdp_attr *attr;
	char attr_value[256];
	unsigned int attr_i;

	/* If ICE support is not enabled or available exit early */
	if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) {
		return;
	}

	attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL);
	if (!attr) {
		attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-ufrag", NULL);
	}
	if (attr) {
		ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
		ice->set_authentication(session_media->rtp, attr_value, NULL);
	} else {
		return;
	}

	attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL);
	if (!attr) {
		attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-pwd", NULL);
	}
	if (attr) {
		ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
		ice->set_authentication(session_media->rtp, NULL, attr_value);
	} else {
		return;
	}

	if (pjmedia_sdp_media_find_attr2(remote_stream, "ice-lite", NULL)) {
		ice->ice_lite(session_media->rtp);
	}

	/* Find all of the candidates */
	for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) {
		char foundation[32], transport[32], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[PJ_INET6_ADDRSTRLEN + 1] = "";
		unsigned int port, relay_port = 0;
		struct ast_rtp_engine_ice_candidate candidate = { 0, };

		attr = remote_stream->attr[attr_i];

		/* If this is not a candidate line skip it */
		if (pj_strcmp2(&attr->name, "candidate")) {
			continue;
		}

		ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));

		if (sscanf(attr_value, "%31s %30u %31s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport,
			(unsigned *)&candidate.priority, address, &port, cand_type, relay_address, &relay_port) < 7) {
			/* Candidate did not parse properly */
			continue;
		}

		candidate.foundation = foundation;
		candidate.transport = transport;

		ast_sockaddr_parse(&candidate.address, address, PARSE_PORT_FORBID);
		ast_sockaddr_set_port(&candidate.address, port);

		if (!strcasecmp(cand_type, "host")) {
			candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
		} else if (!strcasecmp(cand_type, "srflx")) {
			candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
		} else if (!strcasecmp(cand_type, "relay")) {
			candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
		} else {
			continue;
		}

		if (!ast_strlen_zero(relay_address)) {
			ast_sockaddr_parse(&candidate.relay_address, relay_address, PARSE_PORT_FORBID);
		}

		if (relay_port) {
			ast_sockaddr_set_port(&candidate.relay_address, relay_port);
		}

		ice->add_remote_candidate(session_media->rtp, &candidate);
	}

	ice->set_role(session_media->rtp, pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_TRUE ?
		AST_RTP_ICE_ROLE_CONTROLLING : AST_RTP_ICE_ROLE_CONTROLLED);
	ice->start(session_media->rtp);
}
static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
{
	RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
	struct request_transport_details details = { 0, };
	pjsip_via_hdr *via = NULL;
	struct ast_sockaddr addr = { { 0, } };
	pjsip_sip_uri *uri = NULL;
	RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);

	/* If a transport selector is in use we know the transport or factory, so explicitly find it */
	if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
		details.transport = tdata->tp_sel.u.transport;
	} else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER) {
		details.factory = tdata->tp_sel.u.listener;
	} else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
		/* Connectionless uses the same transport for all requests */
		details.type = AST_TRANSPORT_UDP;
		details.transport = tdata->tp_info.transport;
	} else {
		if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP) {
			details.type = AST_TRANSPORT_TCP;
		} else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS) {
			details.type = AST_TRANSPORT_TLS;
		} else {
			/* Unknown transport type, we can't map and thus can't apply NAT changes */
			return PJ_SUCCESS;
		}

		if ((uri = nat_get_contact_sip_uri(tdata))) {
			details.local_address = uri->host;
			details.local_port = uri->port;
		} else if ((tdata->msg->type == PJSIP_REQUEST_MSG) &&
			(via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) {
			details.local_address = via->sent_by.host;
			details.local_port = via->sent_by.port;
		} else {
			return PJ_SUCCESS;
		}

		if (!details.local_port) {
			details.local_port = (details.type == AST_TRANSPORT_TLS) ? 5061 : 5060;
		}
	}

	if (!(transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
		!(transport = ao2_callback(transports, 0, find_transport_in_use, &details)) || !transport->localnet ||
		ast_sockaddr_isnull(&transport->external_address)) {
		return PJ_SUCCESS;
	}

	ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
	ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);

	/* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
	if (ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) {
		return PJ_SUCCESS;
	}

	/* Update the contact header with the external address */
	if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
		pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport->external_address));
		if (transport->external_signaling_port) {
			uri->port = transport->external_signaling_port;
			ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
		}
	}

	/* Update the via header if relevant */
	if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
		pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport->external_address));
		if (transport->external_signaling_port) {
			via->sent_by.port = transport->external_signaling_port;
		}
	}

	/* Invoke any additional hooks that may be registered */
	if ((hooks = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "nat_hook", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
		struct nat_hook_details hook_details = {
			.tdata = tdata,
			.transport = transport,
		};
		ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
	}

	return PJ_SUCCESS;
}
Example #9
0
/* \brief called by scheduler to send STUN request */
static int stun_monitor_request(const void *blarg)
{
	int res;
	struct sockaddr_in answer;
	static const struct sockaddr_in no_addr = { 0, };

	ast_mutex_lock(&args.lock);
	if (!args.monitor_enabled) {
		goto monitor_request_cleanup;
	}

	if (args.stun_sock < 0) {
		struct ast_sockaddr stun_addr;

		/* STUN socket not open.  Refresh the server DNS address resolution. */
		if (!args.server_hostname) {
			/* No STUN hostname? */
			goto monitor_request_cleanup;
		}

		/* Lookup STUN address. */
		memset(&stun_addr, 0, sizeof(stun_addr));
		stun_addr.ss.ss_family = AF_INET;
		if (ast_get_ip(&stun_addr, args.server_hostname)) {
			/* Lookup failed. */
			ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n",
				args.server_hostname);
			goto monitor_request_cleanup;
		}
		ast_sockaddr_set_port(&stun_addr, args.stun_port);

		/* open socket binding */
		args.stun_sock = socket(AF_INET, SOCK_DGRAM, 0);
		if (args.stun_sock < 0) {
			ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
			goto monitor_request_cleanup;
		}
		if (ast_connect(args.stun_sock, &stun_addr)) {
			ast_log(LOG_WARNING, "STUN Failed to connect to %s: %s\n",
				ast_sockaddr_stringify(&stun_addr), strerror(errno));
			stun_close_sock();
			goto monitor_request_cleanup;
		}
	}

	res = ast_stun_request(args.stun_sock, NULL, NULL, &answer);
	if (res) {
		/*
		 * STUN request timed out or errored.
		 *
		 * Refresh the server DNS address resolution next time around.
		 */
		if (!args.stun_poll_failed_gripe) {
			args.stun_poll_failed_gripe = 1;
			ast_log(LOG_WARNING, "STUN poll %s. Re-evaluating STUN server address.\n",
				res < 0 ? "failed" : "got no response");
		}
		stun_close_sock();
	} else {
		args.stun_poll_failed_gripe = 0;
		if (memcmp(&no_addr, &answer, sizeof(no_addr))
			&& memcmp(&args.external_addr, &answer, sizeof(args.external_addr))) {
			const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
			int newport = ntohs(answer.sin_port);

			ast_log(LOG_NOTICE, "Old external address/port %s:%d now seen as %s:%d.\n",
				ast_inet_ntoa(args.external_addr.sin_addr),
				ntohs(args.external_addr.sin_port), newaddr, newport);

			args.external_addr = answer;

			if (args.external_addr_known) {
				struct ast_event *event;

				/*
				 * The external address was already known, and has changed...
				 * generate event.
				 */
				event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
				if (!event) {
					ast_log(LOG_ERROR, "Could not create AST_EVENT_NETWORK_CHANGE event.\n");
				} else if (ast_event_queue(event)) {
					ast_event_destroy(event);
					ast_log(LOG_ERROR, "Could not queue AST_EVENT_NETWORK_CHANGE event.\n");
				}
			} else {
				/* this was the first external address we found, do not alert listeners
				 * until this address changes to something else. */
				args.external_addr_known = 1;
			}
		}
	}

monitor_request_cleanup:
	/* always refresh this scheduler item.  It will be removed elsewhere when
	 * it is supposed to go away */
	res = args.refresh * 1000;
	ast_mutex_unlock(&args.lock);

	return res;
}