/// Resolve a destination host and realm name to a list of IP addresses, /// transports and ports. HTTP is pretty simple - just look up the A records. void HttpResolver::resolve(const std::string& host, int port, int max_targets, std::vector<AddrInfo>& targets, SAS::TrailId trail) { AddrInfo ai; int dummy_ttl = 0; TRC_DEBUG("HttpResolver::resolve for host %s, port %d, family %d", host.c_str(), port, _address_family); port = (port != 0) ? port : DEFAULT_PORT; targets.clear(); if (parse_ip_target(host, ai.address)) { // The name is already an IP address, so no DNS resolution is possible. TRC_DEBUG("Target is an IP address"); ai.port = port; ai.transport = TRANSPORT; targets.push_back(ai); } else { a_resolve(host, _address_family, port, TRANSPORT, max_targets, targets, dummy_ttl, trail); } }
void SIPResolver::resolve(const std::string& name, int af, int port, int transport, int retries, std::vector<AddrInfo>& targets, SAS::TrailId trail) { int dummy_ttl = 0; targets.clear(); // First determine the transport following the process in RFC3263 section // 4.1. AddrInfo ai; TRC_DEBUG("SIPResolver::resolve for name %s, port %d, transport %d, family %d", name.c_str(), port, transport, af); if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_START, 0); event.add_var_param(name); std::string port_str = std::to_string(port); std::string transport_str = get_transport_str(transport); event.add_var_param(port_str); event.add_var_param(transport_str); SAS::report_event(event); } if (parse_ip_target(name, ai.address)) { // The name is already an IP address, so no DNS resolution is possible. // Use specified transport and port or defaults if not specified. TRC_DEBUG("Target is an IP address - default port/transport if required"); ai.transport = (transport != -1) ? transport : IPPROTO_UDP; ai.port = (port != 0) ? port : 5060; targets.push_back(ai); if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_IP_ADDRESS, 0); event.add_var_param(name); std::string port_str = std::to_string(ai.port); std::string transport_str = get_transport_str(ai.transport); event.add_var_param(transport_str); event.add_var_param(port_str); SAS::report_event(event); } } else { std::string srv_name; std::string a_name = name; if (port != 0) { // Port is specified, so don't do NAPTR or SRV look-ups. Default transport // if required and move straight to A record look-up. TRC_DEBUG("Port is specified"); transport = (transport != -1) ? transport : IPPROTO_UDP; if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_PORT_A_LOOKUP, 0); event.add_var_param(name); std::string port_str = std::to_string(port); std::string transport_str = get_transport_str(transport); event.add_var_param(transport_str); event.add_var_param(port_str); SAS::report_event(event); } } else if (transport == -1) { // Transport protocol isn't specified, so do a NAPTR lookup for the target. TRC_DEBUG("Do NAPTR look-up for %s", name.c_str()); if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_NAPTR_LOOKUP, 0); event.add_var_param(name); SAS::report_event(event); } NAPTRReplacement* naptr = _naptr_cache->get(name, dummy_ttl, trail); if (naptr != NULL) { // NAPTR resolved to a supported service TRC_DEBUG("NAPTR resolved to transport %d", naptr->transport); transport = naptr->transport; if (strcasecmp(naptr->flags.c_str(), "S") == 0) { // Do an SRV lookup with the replacement domain from the NAPTR lookup. srv_name = naptr->replacement; if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_NAPTR_SUCCESS_SRV, 0); event.add_var_param(name); event.add_var_param(srv_name); std::string transport_str = get_transport_str(naptr->transport); event.add_var_param(transport_str); SAS::report_event(event); } } else { // Move straight to A/AAAA lookup of the domain returned by NAPTR. a_name = naptr->replacement; if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_NAPTR_SUCCESS_A, 0); event.add_var_param(name); event.add_var_param(a_name); SAS::report_event(event); } } } else { // NAPTR resolution failed, so do SRV lookups for both UDP and TCP to // see which transports are supported. TRC_DEBUG("NAPTR lookup failed, so do SRV lookups for UDP and TCP"); if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_NAPTR_FAILURE, 0); event.add_var_param(name); SAS::report_event(event); } std::vector<std::string> domains; domains.push_back("_sip._udp." + name); domains.push_back("_sip._tcp." + name); std::vector<DnsResult> results; _dns_client->dns_query(domains, ns_t_srv, results, trail); DnsResult& udp_result = results[0]; TRC_DEBUG("UDP SRV record %s returned %d records", udp_result.domain().c_str(), udp_result.records().size()); DnsResult& tcp_result = results[1]; TRC_DEBUG("TCP SRV record %s returned %d records", tcp_result.domain().c_str(), tcp_result.records().size()); if (!udp_result.records().empty()) { // UDP SRV lookup returned some records, so use UDP transport. TRC_DEBUG("UDP SRV lookup successful, select UDP transport"); transport = IPPROTO_UDP; srv_name = udp_result.domain(); } else if (!tcp_result.records().empty()) { // TCP SRV lookup returned some records, so use TCP transport. TRC_DEBUG("TCP SRV lookup successful, select TCP transport"); transport = IPPROTO_TCP; srv_name = tcp_result.domain(); } else { // Neither UDP nor TCP SRV lookup returned any results, so default to // UDP transport and move straight to A/AAAA record lookups. TRC_DEBUG("UDP and TCP SRV queries unsuccessful, default to UDP"); transport = IPPROTO_UDP; } } _naptr_cache->dec_ref(name); } else if (transport == IPPROTO_UDP) { // Use specified transport and try an SRV lookup. if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_TRANSPORT_SRV_LOOKUP, 0); event.add_var_param(name); std::string transport_str = get_transport_str(transport); event.add_var_param(transport_str); SAS::report_event(event); } DnsResult result = _dns_client->dns_query("_sip._udp." + name, ns_t_srv, trail); if (!result.records().empty()) { srv_name = result.domain(); } } else if (transport == IPPROTO_TCP) { // Use specified transport and try an SRV lookup. if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_TRANSPORT_SRV_LOOKUP, 0); event.add_var_param(name); std::string transport_str = get_transport_str(transport); event.add_var_param(transport_str); SAS::report_event(event); } DnsResult result = _dns_client->dns_query("_sip._tcp." + name, ns_t_srv, trail); if (!result.records().empty()) { srv_name = result.domain(); } } if (srv_name != "") { TRC_DEBUG("Do SRV lookup for %s", srv_name.c_str()); if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_SRV_LOOKUP, 0); event.add_var_param(srv_name); std::string transport_str = get_transport_str(transport); event.add_var_param(transport_str); SAS::report_event(event); } srv_resolve(srv_name, af, transport, retries, targets, dummy_ttl, trail); } else { TRC_DEBUG("Perform A/AAAA record lookup only, name = %s", a_name.c_str()); port = (port != 0) ? port : 5060; if (trail != 0) { SAS::Event event(trail, SASEvent::SIPRESOLVE_A_LOOKUP, 0); event.add_var_param(a_name); std::string transport_str = get_transport_str(transport); std::string port_str = std::to_string(port); event.add_var_param(transport_str); event.add_var_param(port_str); SAS::report_event(event); } a_resolve(a_name, af, port, transport, retries, targets, dummy_ttl, trail); } } }
SOCKET #else int #endif udp_client(const char *ip, uint16_t port) { # if HAVE_WINSOCK2_H SOCKET sock; # else int sock; # endif struct sockaddr_in remote; struct sockaddr_in local; remote.sin_family = AF_INET; if(a_resolve(ip, &(remote.sin_addr))) { # if OS_TYPE_WIN32 && HAVE_WINSOCK2_H return INVALID_SOCKET; # else return -1; # endif } remote.sin_port = htons(port); local.sin_family = AF_INET; local.sin_addr.s_addr = INADDR_ANY; local.sin_port = htons(0); sock = socket(AF_INET, SOCK_DGRAM, 0); # ifdef __WIN32__ if(sock == INVALID_SOCKET) { a_flail_winsock_su(a_error_socket); return INVALID_SOCKET; } # else if(sock == -1) { a_flail_winsock_su(a_error_socket); return -1; } # endif if(bind(sock, (struct sockaddr *)(&local), sizeof(local))) # ifdef __WIN32__ { a_flail_winsock_su(a_error_bind); a_cleanup(A_CLEANUP_SOCK, sock); return INVALID_SOCKET; } # else { a_flail_posix_su(a_error_bind); a_cleanup(A_CLEANUP_SOCK, sock); return -1; } # endif if(connect(sock, (struct sockaddr *)(&remote), sizeof(remote))) # ifdef __WIN32__ { a_flail_winsock_su(a_error_connect_socket); a_cleanup(A_CLEANUP_SOCK, sock); return INVALID_SOCKET; } # else { a_flail_winsock_su(a_error_connect_socket); a_cleanup(A_CLEANUP_SOCK, sock); return -1; } # endif return sock; }