/** Convert a @Via header to @Contact URL string. * * The @Contact URI will contain the port number and transport parameters if * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema * is used. * * The contact URI string returned will always have angle brackets ("<" and * ">") around it. * * @param home memory home * @param v @Via header field structure * (with <sent-by> parameter containing host and port) * @param user username for @Contact URI (may be NULL) * @param transport transport name for @Contact URI (may be NULL) * * @retval string containing Contact URI with angle brackets * @retval NULL upon an error */ char * sip_contact_string_from_via(su_home_t *home, sip_via_t const *v, char const *user, char const *transport) { const char *host, *port, *maddr, *comp; char const *scheme = "sip:"; int one = 1; char _transport[16]; if (!v) return NULL; host = v->v_host; if (v->v_received) host = v->v_received; port = sip_via_port(v, &one); maddr = v->v_maddr; comp = v->v_comp; if (host == NULL) return NULL; if (sip_transport_has_tls(v->v_protocol) || sip_transport_has_tls(transport)) { scheme = "sips:"; if (port && strcmp(port, SIPS_DEFAULT_SERV) == 0) port = NULL; if (port || host_is_ip_address(host)) transport = NULL; } else if (port && strcmp(port, SIP_DEFAULT_SERV) == 0 && (host_is_ip_address(host) || host_has_domain_invalid(host))) { port = NULL; } if (su_casenmatch(transport, "SIP/2.0/", 8)) transport += 8; /* Make transport parameter lowercase */ if (transport && strlen(transport) < (sizeof _transport)) { char *s = strcpy(_transport, transport); short c; for (s = _transport; (c = *s) && c != ';'; s++) if (isupper(c)) *s = tolower(c); transport = _transport; } return su_strcat_all(home, "<", scheme, user ? user : "", user ? "@" : "", host, SIP_STRLOG(":", port), SIP_STRLOG(";transport=", transport), SIP_STRLOG(";maddr=", maddr), SIP_STRLOG(";comp=", comp), ">", NULL); }
/**@internal * * Detect NAT. * * Based on "received" and possible "rport" parameters in the top-most Via, * check and update our NAT status. * * @retval ob_nat_changed (2) change in public NAT binding detected * @retval ob_nat_detected (1) NAT binding detected * @retval ob_no_nat (0) no NAT binding detected * @retval -1 an error occurred */ static int outbound_nat_detect(outbound_t *ob, sip_t const *request, sip_t const *response) { sip_via_t const *v; int one = 1; char const *received, *rport; char *nat_detected, *nat_port; char *new_detected, *new_port; assert(request && request->sip_request); assert(response && response->sip_status); if (!ob || !response || !response->sip_via || !request->sip_via) return -1; v = response->sip_via; received = v->v_received; if (!received || !strcmp(received, request->sip_via->v_host)) return 0; if (!host_is_ip_address(received)) { if (received[0]) SU_DEBUG_3(("outbound(%p): Via with invalid received=%s\n", (void *)ob->ob_owner, received)); return 0; } rport = sip_via_port(v, &one); assert(rport); nat_detected = ob->ob_nat_detected; nat_port = ob->ob_nat_port; if (nat_detected && host_cmp(received, nat_detected) == 0) { if (nat_port && su_casematch(rport, nat_port)) return 1; if (!v->v_rport || !v->v_rport[0]) return 1; } if (!nat_detected) { SU_DEBUG_5(("outbound(%p): detected NAT: %s != %s\n", (void *)ob->ob_owner, v->v_host, received)); if (ob->ob_oo && ob->ob_oo->oo_status) ob->ob_oo->oo_status(ob->ob_owner, ob, 101, "NAT detected", TAG_END()); } else { SU_DEBUG_5(("outbound(%p): NAT binding changed: " "[%s]:%s != [%s]:%s\n", (void *)ob->ob_owner, nat_detected, nat_port, received, rport)); if (ob->ob_oo && ob->ob_oo->oo_status) ob->ob_oo->oo_status(ob->ob_owner, ob, 102, "NAT binding changed", TAG_END()); } /* Save our nat binding */ new_detected = su_strdup(ob->ob_home, received); new_port = su_strdup(ob->ob_home, rport); if (!new_detected || !new_port) { su_free(ob->ob_home, new_detected); su_free(ob->ob_home, new_port); return -1; } ob->ob_nat_detected = new_detected; ob->ob_nat_port = new_port; su_free(ob->ob_home, nat_detected); su_free(ob->ob_home, nat_port); return 2; }
switch_status_t sip_dig_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream) { int exitcode = 0; int o_sctp = 1, o_tls_sctp = 1, o_verbatim = 1; int family = 0, multiple = 0; char const *dnsserver = NULL; char const *string; url_t *uri = NULL; char const *host; char const *port; char *transport = NULL, tport[32]; int argc; char *argv_[25] = { 0 }; char *mycmd = NULL; char **argv; struct dig dig[1] = {{ NULL }}; su_home_t *home = NULL; int xml = 0; home = su_home_new(sizeof(*home)); argv = argv_; argv++; if (!cmd) { {usage(1);} } mycmd = strdup(cmd); argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv_) / sizeof(argv_[0])) - 1); argv = argv_; if (!argv[1]) { {usage(1);} } if (!strcasecmp(argv[1], "xml")) { switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "xml", "true"); argv++; xml++; } argv[0] = "sofia_dig"; //if (su_init() != 0) //return -1; while (argv[1] && argv[1][0] == '-') { if (strcmp(argv[1], "-v") == 0) o_verbatim++; else if (strcmp(argv[1], "-6") == 0) dig->ip6 = ++family; else if (strcmp(argv[1], "-4") == 0) dig->ip4 = ++family; else if (strncmp(argv[1], "-p", 2) == 0) { char const *proto; if (argv[1][2] == '=') proto = argv[1] + 3; else if (argv[1][2]) proto = argv[1] + 2; else proto = argv++[2]; if (proto == NULL) {usage(2);} if (prepare_transport(dig, proto) < 0) { goto fail; } } else if (strcmp(argv[1], "--udp") == 0) prepare_transport(dig, "udp"); else if (strcmp(argv[1], "--tcp") == 0) prepare_transport(dig, "tcp"); else if (strcmp(argv[1], "--tls") == 0) prepare_transport(dig, "tls"); else if (strcmp(argv[1], "--sctp") == 0) prepare_transport(dig, "sctp"); else if (strcmp(argv[1], "--tls-sctp") == 0) prepare_transport(dig, "tls-sctp"); else if (strcmp(argv[1], "--tls-udp") == 0) prepare_transport(dig, "tls-udp"); else if (strcmp(argv[1], "--no-sctp") == 0) o_sctp = 0, o_tls_sctp = 0; else if (strcmp(argv[1], "--help") == 0) {usage(0);} else if (strcmp(argv[1], "-h") == 0) {usage(0);} else if (strcmp(argv[1], "-?") == 0) {usage(0);} else if (strcmp(argv++[1], "-") == 0) break; else {usage(2);} argv++; } if (xml) { stream->write_function(stream, "%s", "<routes>\n"); } else { stream->write_function(stream, "%10s\t%10s\t%10s\t%10s\t%10s\n", "Preference", "Weight", "Transport", "Port", "Address"); stream->write_function(stream, "================================================================================\n"); } if (!family) dig->ip4 = 1, dig->ip6 = 2; if (argv[1] && argv[1][0] == '@') dnsserver = argv++[1] + 1; if (!argv[1]) {usage(2);} multiple = argv[1] && argv[2]; if (!count_transports(dig, NULL, NULL)) { prepare_transport(dig, "udp"); prepare_transport(dig, "tcp"); if (o_sctp) prepare_transport(dig, "sctp"); prepare_transport(dig, "tls"); if (o_tls_sctp) prepare_transport(dig, "tls-sctp"); } dig->sres = sres_resolver_new(getenv("SRESOLV_CONF")); if (!dig->sres) {usage(1);} for (; (string = argv[1]); argv++) { if (multiple) stream->write_function(stream, "%s", string); uri = url_hdup(home, (void *)string); if (uri && uri->url_type == url_unknown) url_sanitize(uri); if (uri && uri->url_type == url_any) continue; if (!uri || (uri->url_type != url_sip && uri->url_type != url_sips)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: invalid uri\n", string); exitcode = 1; continue; } port = url_port(uri); if (port && !port[0]) port = NULL; if (url_param(uri->url_params, "transport=", tport, sizeof tport) > 0) transport = tport; host = uri->url_host; if (host_is_ip_address(host)) { if (transport) { print_result(host, port, transport, 1.0, 1, stream); } else if (uri->url_type == url_sips) { print_result(host, port, "tls", 1.0, 1, stream); } else { print_result(host, port, "udp", 1.0, 1, stream); print_result(host, port, "tcp", 1.0, 2, stream); } continue; } if (!host_is_domain(host)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: invalid host\n", string); exitcode = 1; continue; } dig->sips = uri->url_type == url_sips; dig->preference = 1; if (!port && !transport && dig_naptr(dig, host, 1.0, stream)) continue /* resolved naptr */; else if (!port && dig_all_srvs(dig, transport, host, 1.0, stream)) continue /* resolved srv */; else if (dig_addr(dig, transport, host, port, 1.0, stream)) continue /* resolved a/aaaa */; stream->write_function(stream, "-ERR: %s: not found\n", string); exitcode = 1; } if (xml) { stream->write_function(stream, "%s", "</routes>\n"); } fail: su_home_unref(home); sres_resolver_unref(dig->sres); switch_safe_free(mycmd); return SWITCH_STATUS_SUCCESS; }