Exemple #1
0
static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent)
{
  union {
    struct sockaddr_storage storage;
    struct sockaddr addr;
  } addr;
  socklen_t addr_len;
  uint8_t buf[STUN_MAX_MESSAGE_SIZE];
  size_t buf_len = 0;
  size_t len = 0;
  StunMessage request;
  StunMessage response;
  StunValidationStatus validation;
  StunAgent *agent = NULL;

  addr_len = sizeof (struct sockaddr_in);
  len = recvfrom (sock, buf, sizeof(buf), 0, &addr.addr, &addr_len);
  if (len == (size_t)-1)
    return -1;

  validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0);

  if (validation == STUN_VALIDATION_SUCCESS) {
    agent = newagent;
  }
  else {
    validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0);
    agent = oldagent;
  }

  /* Unknown attributes */
  if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE)
  {
    buf_len = stun_agent_build_unknown_attributes_error (agent, &response, buf,
        sizeof (buf), &request);
    goto send_buf;
  }

  /* Mal-formatted packets */
  if (validation != STUN_VALIDATION_SUCCESS ||
      stun_message_get_class (&request) != STUN_REQUEST) {
    return -1;
  }

  switch (stun_message_get_method (&request))
  {
    case STUN_BINDING:
      stun_agent_init_response (agent, &response, buf, sizeof (buf), &request);
      if (stun_message_has_cookie (&request))
        stun_message_append_xor_addr (&response,
            STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &addr.addr, addr_len);
      else
         stun_message_append_addr (&response, STUN_ATTRIBUTE_MAPPED_ADDRESS,
             &addr.addr, addr_len);
      break;

    case STUN_SHARED_SECRET:
    case STUN_ALLOCATE:
    case STUN_SEND:
    case STUN_CONNECT:
    case STUN_IND_SEND:
    case STUN_IND_DATA:
    case STUN_CREATEPERMISSION:
    case STUN_CHANNELBIND:
    default:
      if (!stun_agent_init_error (agent, &response, buf, sizeof (buf),
              &request, STUN_ERROR_BAD_REQUEST))
        return -1;
  }

  buf_len = stun_agent_finish_message (agent, &response, NULL, 0);
send_buf:
  len = sendto (sock, buf, buf_len, 0, &addr.addr, addr_len);
  return (len < buf_len) ? -1 : 0;
}
Exemple #2
0
static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent)
{
  union {
    struct sockaddr_storage storage;
    struct sockaddr addr;
  } addr;
  socklen_t addr_len;
  uint8_t buf[STUN_MAX_MESSAGE_SIZE];
  size_t buf_len = 0;
  size_t len = 0;
  StunMessage request;
  StunMessage response;
  StunValidationStatus validation;
  StunAgent *agent = NULL;
  gint ret;

  addr_len = sizeof (struct sockaddr_in);

recv_packet:
  len = recvfrom (sock, buf, sizeof(buf), 0,
      &addr.addr, &addr_len);

  if (drop_stun_packets) {
    g_debug ("Dropping STUN packet as requested");
    return -1;
  }

  if (len == (size_t)-1) {
    return -1;
  }

  validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0);

  if (validation == STUN_VALIDATION_SUCCESS) {
    agent = newagent;
  } else {
    validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0);
    agent = oldagent;
  }

  /* Unknown attributes */
  if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE) {
    buf_len = stun_agent_build_unknown_attributes_error (agent, &response, buf,
        sizeof (buf), &request);
    goto send_buf;
  }

  /* Mal-formatted packets */
  if (validation != STUN_VALIDATION_SUCCESS ||
      stun_message_get_class (&request) != STUN_REQUEST) {
    goto recv_packet;
  }

  switch (stun_message_get_method (&request)) {
    case STUN_BINDING:
      stun_agent_init_response (agent, &response, buf, sizeof (buf), &request);
      if (stun_message_has_cookie (&request))
        stun_message_append_xor_addr (&response,
            STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
            &addr.storage, addr_len);
      else
         stun_message_append_addr (&response, STUN_ATTRIBUTE_MAPPED_ADDRESS,
             &addr.addr, addr_len);
      break;

    case STUN_SHARED_SECRET:
    case STUN_ALLOCATE:
    case STUN_SET_ACTIVE_DST:
    case STUN_CONNECT:
    case STUN_OLD_SET_ACTIVE_DST:
    case STUN_IND_DATA:
    case STUN_IND_CONNECT_STATUS:
    case STUN_CHANNELBIND:
    default:
      if (!stun_agent_init_error (agent, &response, buf, sizeof (buf),
              &request, STUN_ERROR_BAD_REQUEST)) {
        g_debug ("STUN error message not initialized properly");
        g_assert_not_reached();
      }
  }

  buf_len = stun_agent_finish_message (agent, &response, NULL, 0);

send_buf:
  g_cancellable_cancel (global_cancellable);
  g_debug ("Ready to send a STUN response");
  g_assert (g_mutex_trylock (stun_mutex_ptr));
  got_stun_packet = TRUE;
  while (send_stun) {
    g_debug ("Waiting for signal. State is %d", global_lagent_state);
    g_cond_wait (stun_signal_ptr, stun_mutex_ptr);
  }
  g_mutex_unlock (stun_mutex_ptr);
  len = sendto (sock, buf, buf_len, 0,
      &addr.addr, addr_len);
  g_debug ("STUN response sent");
  drop_stun_packets = TRUE;
  ret = (len < buf_len) ? -1 : 0;
  return ret;
}
Exemple #3
0
static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent)
{
  struct sockaddr_storage addr;
  uint8_t buf[STUN_MAX_MESSAGE_SIZE];
  char ctlbuf[CMSG_SPACE (sizeof (struct in6_pktinfo))];
  struct iovec iov = { buf, sizeof (buf) };
  StunMessage request;
  StunMessage response;
  StunValidationStatus validation;
  StunAgent *agent = NULL;

  struct msghdr mh =
  {
    .msg_name = (struct sockaddr *)&addr,
    .msg_namelen = sizeof (addr),
    .msg_iov = &iov,
    .msg_iovlen = 1,
    .msg_control = ctlbuf,
    .msg_controllen = sizeof (ctlbuf)
  };

  size_t len = recv_safe (sock, &mh);
  if (len == (size_t)-1)
    return -1;

  validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0);

  if (validation == STUN_VALIDATION_SUCCESS) {
    agent = newagent;
  }
  else {
    validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0);
    agent = oldagent;
  }

  /* Unknown attributes */
  if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE)
  {
    stun_agent_build_unknown_attributes_error (agent, &response, buf,
        sizeof (buf), &request);
    goto send_buf;
  }

  /* Mal-formatted packets */
  if (validation != STUN_VALIDATION_SUCCESS ||
      stun_message_get_class (&request) != STUN_REQUEST) {
    return -1;
  }

  switch (stun_message_get_method (&request))
  {
    case STUN_BINDING:
      stun_agent_init_response (agent, &response, buf, sizeof (buf), &request);
      if (stun_message_has_cookie (&request))
        stun_message_append_xor_addr (&response,
                              STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
                              mh.msg_name, mh.msg_namelen);
      else
         stun_message_append_addr (&response, STUN_ATTRIBUTE_MAPPED_ADDRESS,
                          mh.msg_name, mh.msg_namelen);
      break;

    default:
      stun_agent_init_error (agent, &response, buf, sizeof (buf),
          &request, STUN_ERROR_BAD_REQUEST);
  }

  iov.iov_len = stun_agent_finish_message (agent, &response, NULL, 0);
send_buf:

  len = send_safe (sock, &mh);
  return (len < iov.iov_len) ? -1 : 0;
}


static int run (int family, int protocol, unsigned port)
{
  StunAgent oldagent;
  StunAgent newagent;
  int sock = listen_socket (family, SOCK_DGRAM, protocol, port);
  if (sock == -1)
    return -1;

  stun_agent_init (&oldagent, known_attributes,
      STUN_COMPATIBILITY_RFC3489, 0);
  stun_agent_init (&newagent, known_attributes,
      STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT);

  for (;;)
    dgram_process (sock, &oldagent, &newagent);
}