Пример #1
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;
}
Пример #2
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);
}