/*! \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; }
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; }
/*! \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); } }
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; }
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; }
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; }
/*! \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; }
/* \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; }