Пример #1
0
/** 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);
}
Пример #2
0
/**@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;
}
Пример #3
0
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;
}