Ejemplo n.º 1
0
StunUsageIceReturn
stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req,
                                       StunMessage *msg, uint8_t *buf, size_t *plen,
                                       const struct sockaddr *src, socklen_t srclen,
                                       bool *control, uint64_t tie,
                                       StunUsageIceCompatibility compatibility)
{
    const char *username = NULL;
    uint16_t username_len;
    size_t len = *plen;
    uint64_t q;
    StunMessageReturn val = STUN_MESSAGE_RETURN_SUCCESS;
    StunUsageIceReturn ret = STUN_USAGE_ICE_RETURN_SUCCESS;
    
    
#define err( code ) \
stun_bind_error (agent, msg, buf, &len, req, code); \
*plen = len
    
    *plen = 0;
    stun_debug ("STUN Reply (buffer size = %u)...\n", (unsigned)len);
    
    if (stun_message_get_class (req) != STUN_REQUEST)
    {
        stun_debug (" Unhandled non-request (class %u) message.\n",
                    stun_message_get_class (req));
        return STUN_USAGE_ICE_RETURN_INVALID_REQUEST;
    }
    
    if (stun_message_get_method (req) != STUN_BINDING)
    {
        stun_debug (" Bad request (method %u) message.\n",
                    stun_message_get_method (req));
        err (STUN_ERROR_BAD_REQUEST);
        return STUN_USAGE_ICE_RETURN_INVALID_METHOD;
    }
    
    /* Role conflict handling */
    assert (control != NULL);
    if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLING
                             : STUN_ATTRIBUTE_ICE_CONTROLLED, &q) == STUN_MESSAGE_RETURN_SUCCESS)
    {
        stun_debug ("STUN Role Conflict detected:\n");
        
        if (tie < q)
        {
            stun_debug (" switching role from \"controll%s\" to \"controll%s\"\n",
                        *control ? "ing" : "ed", *control ? "ed" : "ing");
            *control = !*control;
            ret = STUN_USAGE_ICE_RETURN_ROLE_CONFLICT;
        }
        else
        {
            stun_debug (" staying \"controll%s\" (sending error)\n",
                        *control ? "ing" : "ed");
            err (STUN_ERROR_ROLE_CONFLICT);
            return STUN_USAGE_ICE_RETURN_SUCCESS;
        }
    } else {
        stun_debug ("STUN Role not specified by peer!\n");
    }
    
    if (stun_agent_init_response (agent, msg, buf, len, req) == FALSE) {
        stun_debug ("Unable to create response\n");
        goto failure;
    }
    if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) {
        StunTransactionId transid;
        uint32_t magic_cookie;
        stun_message_id (msg, transid);
        magic_cookie = *((uint32_t *) transid);
        
        val = stun_message_append_xor_addr_full (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
                                                 src, srclen, htonl (magic_cookie));
    } else if (stun_message_has_cookie (msg)) {
        val = stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
                                            src, srclen);
    } else {
        val = stun_message_append_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS,
                                        src, srclen);
    }
    
    if (val != STUN_MESSAGE_RETURN_SUCCESS) {
        stun_debug (" Mapped address problem: %d\n", val);
        goto failure;
    }
    
    username = (const char *)stun_message_find (req,
                                                STUN_ATTRIBUTE_USERNAME, &username_len);
    if (username) {
        val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
                                         username, username_len);
    }
    
    if (val != STUN_MESSAGE_RETURN_SUCCESS) {
        stun_debug ("Error appending username: %d\n", val);
        goto failure;
    }
    
    
    
    /* the stun agent will automatically use the password of the request */
    len = stun_agent_finish_message (agent, msg, NULL, 0);
    if (len == 0)
        goto failure;
    
    *plen = len;
    stun_debug (" All done (response size: %u)\n", (unsigned)len);
    return ret;
    
failure:
    assert (*plen == 0);
    stun_debug (" Fatal error formatting Response: %d\n", val);
    
    switch (val)
    {
        case STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE:
            return STUN_USAGE_ICE_RETURN_MEMORY_ERROR;
        case STUN_MESSAGE_RETURN_INVALID:
        case STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS:
            return STUN_USAGE_ICE_RETURN_INVALID_ADDRESS;
        default:
            return STUN_USAGE_ICE_RETURN_ERROR;
    }
}
Ejemplo n.º 2
0
StunUsageIceReturn
stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req,
    StunMessage *msg, uint8_t *buf, size_t *plen,
    const struct sockaddr_storage *src, socklen_t srclen,
    bool *control, uint64_t tie,
    StunUsageIceCompatibility compatibility)
{
  const char *username = NULL;
  uint16_t username_len;
  size_t len = *plen;
  uint64_t q;
  StunMessageReturn val = STUN_MESSAGE_RETURN_SUCCESS;
  StunUsageIceReturn ret = STUN_USAGE_ICE_RETURN_SUCCESS;


#define err( code ) \
  stun_bind_error (agent, msg, buf, &len, req, code); \
  *plen = len

  *plen = 0;
  stun_debug ("STUN Reply (buffer size = %u)...", (unsigned)len);

  if (stun_message_get_class (req) != STUN_REQUEST)
  {
    stun_debug (" Unhandled non-request (class %u) message.",
         stun_message_get_class (req));
    return STUN_USAGE_ICE_RETURN_INVALID_REQUEST;
  }

  if (stun_message_get_method (req) != STUN_BINDING)
  {
    stun_debug (" Bad request (method %u) message.",
         stun_message_get_method (req));
    err (STUN_ERROR_BAD_REQUEST);
    return STUN_USAGE_ICE_RETURN_INVALID_METHOD;
  }

  /* Role conflict handling */
  assert (control != NULL);
  if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLING
          : STUN_ATTRIBUTE_ICE_CONTROLLED, &q) == STUN_MESSAGE_RETURN_SUCCESS)
  {
    /* we have the ice-controlling/controlled attribute,
     * and there's a role conflict
     */
    stun_debug ("STUN Role Conflict detected:");

    /* According to ICE RFC 5245, section 7.2.1.1, we consider the four
     * possible cases when a role conflict is detected: two cases are
     * resolved by switching role locally, and the two other cases are
     * handled by responding with a STUN error.
     */
    if ((tie < q && *control) || (tie >= q && !*control))
    {
      stun_debug (" switching role from \"controll%s\" to \"controll%s\"",
           *control ? "ing" : "ed", *control ? "ed" : "ing");
      *control = !*control;
      ret = STUN_USAGE_ICE_RETURN_ROLE_CONFLICT;
    }
    else
    {
      stun_debug (" staying \"controll%s\" (sending error)",
           *control ? "ing" : "ed");
      err (STUN_ERROR_ROLE_CONFLICT);
      return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT;
    }
  } else {
    if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLED
            : STUN_ATTRIBUTE_ICE_CONTROLLING, &q) != STUN_MESSAGE_RETURN_SUCCESS)
    {
      /* we don't have the expected ice-controlling/controlled
       * attribute
       */
      if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 ||
          compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2)
      {
        stun_debug ("STUN Role not specified by peer!");
      }
    }
  }

  if (stun_agent_init_response (agent, msg, buf, len, req) == FALSE) {
    stun_debug ("Unable to create response");
    goto failure;
  }
  if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) {
    union {
      StunTransactionId transid;
      uint32_t magic_cookie;
    } conv;

    stun_message_id (msg, conv.transid);

    val = stun_message_append_xor_addr_full (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
        src, srclen, htonl (conv.magic_cookie));
  } else if (stun_message_has_cookie (msg) &&
      compatibility != STUN_USAGE_ICE_COMPATIBILITY_GOOGLE) {
    val = stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
        src, srclen);
  } else {
    val = stun_message_append_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS,
        (struct sockaddr *) src, srclen);
  }

  if (val != STUN_MESSAGE_RETURN_SUCCESS) {
    stun_debug (" Mapped address problem: %d", val);
    goto failure;
  }

  username = (const char *)stun_message_find (req,
      STUN_ATTRIBUTE_USERNAME, &username_len);
  if (username) {
    val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
        username, username_len);
  }

  if (val != STUN_MESSAGE_RETURN_SUCCESS) {
    stun_debug ("Error appending username: %d", val);
    goto failure;
  }

  if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) {
    val = stun_message_append32 (msg,
        STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, 2);

    if (val != STUN_MESSAGE_RETURN_SUCCESS) {
      stun_debug ("Error appending implementation version: %d", val);
      goto failure;
    }
  }

  /* the stun agent will automatically use the password of the request */
  len = stun_agent_finish_message (agent, msg, NULL, 0);
  if (len == 0)
    goto failure;

  *plen = len;
  stun_debug (" All done (response size: %u)", (unsigned)len);
  return ret;

failure:
  assert (*plen == 0);
  stun_debug (" Fatal error formatting Response: %d", val);

  switch (val)
  {
    case STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE:
      return STUN_USAGE_ICE_RETURN_MEMORY_ERROR;
    case STUN_MESSAGE_RETURN_INVALID:
    case STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS:
      return STUN_USAGE_ICE_RETURN_INVALID_ADDRESS;
    case STUN_MESSAGE_RETURN_SUCCESS:
      assert (0);  /* shouldn’t be reached */
    case STUN_MESSAGE_RETURN_NOT_FOUND:
    default:
      return STUN_USAGE_ICE_RETURN_ERROR;
  }
}