Commit 959e3c67 authored by Pekka Pessi's avatar Pekka Pessi
Browse files

Bugs in stun client code leading to failures in the discovery process. (kv)

* stun.h (stun_set_uname_pwd): Changed from unsigned to signed
  char pointers for passing username and password.
* stun.c: Print the error state code if discovery process fails.
* stunc.c (stun_bind_test): The fd_set was not properly reset between calls to select().

darcs-hash:20051128172432-65a35-71519257e0fe9bb246c2d7dc0d642e9da45da09c.gz
parent a305baa9
......@@ -47,15 +47,18 @@
#include <su.h>
#include <su_localinfo.h>
#ifndef SU_DEBUG
#define SU_DEBUG 3
#endif
#define SU_LOG (stun_log)
#include <su_debug.h>
#include <openssl/opensslv.h>
#define STUN_DEBUG 5 /* default log level */
extern char const STUN_DEBUG[]; /* dummy declaration for Doxygen */
/** STUN log. */
su_log_t stun_log[] = { SU_LOG_INIT("stun", "STUN_DEBUG", STUN_DEBUG) };
#define SU_LOG (stun_log)
#include <su_debug.h>
su_log_t stun_log[] = { SU_LOG_INIT("stun", "STUN_DEBUG", SU_DEBUG) };
char const stun_nat_unknown[] = "NAT type undetermined",
stun_open_internet[] = "Open Internet",
......@@ -152,9 +155,6 @@ stun_engine_t *stun_engine_tcreate(tag_type_t tag, tag_value_t value, ...)
ta_list ta;
su_sockaddr_t su[1];
SU_DEBUG_5(("%s(\"%s\"): called\n",
"stun_engine_tcreate", server));
ta_start(ta, tag, value);
tl_gets(ta_args(ta),
......@@ -168,6 +168,9 @@ stun_engine_t *stun_engine_tcreate(tag_type_t tag, tag_value_t value, ...)
SU_DEBUG_5(("stun: using STUN_SERVER=%s\n", server));
}
SU_DEBUG_5(("%s(\"%s\"): called\n",
"stun_engine_tcreate", server));
memset(su, 0, (sizeof su));
if (server) {
......@@ -335,7 +338,7 @@ int stun_bind(stun_socket_t *ss,
clnt_addr, 0, 0);
if (ss->ss_state != stun_cstate_done) {
SU_DEBUG_3(("stun: Error in STUN discovery process.\n"));
SU_DEBUG_3(("stun: Error in STUN discovery process (error state: %d).\n", (int)ss->ss_state));
/* make sure the returned clnt_addr matches the local socket */
if (*addrlen < bind_len)
return errno = EFAULT, -1;
......@@ -629,7 +632,7 @@ int stun_make_sharedsecret_req(stun_msg_t *msg)
int stun_bind_test(stun_socket_t *ss, struct sockaddr_in *srvr_addr, struct sockaddr_in *clnt_addr,
int chg_ip, int chg_port)
{
int retval = -1, sockfd, z, clnt_addr_len;
int retval = -1, sockfd, z = 0, clnt_addr_len;
stun_msg_t bind_req, bind_resp;
unsigned char dgram[512];
stun_attr_t *mapped_addr, *chg_addr;
......@@ -649,6 +652,10 @@ int stun_bind_test(stun_socket_t *ss, struct sockaddr_in *srvr_addr, struct sock
/* run protocol here... */
sockfd = ss->ss_sockfd;
SU_DEBUG_3(("stun: sending to %s:%u (req-flags: msgint=%d, ch-addr=%d, chh-port=%d)\n",
inet_ntoa(srvr_addr->sin_addr), ntohs(srvr_addr->sin_port),
ss->ss_engine->use_msgint, chg_ip, chg_port));
/* compose binding request */
if(stun_make_binding_req(ss, &bind_req, chg_ip, chg_port)<0)
return retval;
......@@ -660,10 +667,10 @@ int stun_bind_test(stun_socket_t *ss, struct sockaddr_in *srvr_addr, struct sock
return retval;
}
FD_ZERO(&rfds);
FD_SET(sockfd, &rfds); /* Set sockfd for read monitoring */
z = 0;
while(num_retrx < STUN_MAX_RETRX && z <= 0) {
FD_ZERO(&rfds);
FD_SET(sockfd, &rfds); /* Set sockfd for read monitoring */
if(retrx_int < 1000000) {
tv.tv_sec = 0;
tv.tv_usec = retrx_int;
......@@ -673,6 +680,7 @@ int stun_bind_test(stun_socket_t *ss, struct sockaddr_in *srvr_addr, struct sock
tv.tv_sec = 1;
tv.tv_usec = retrx_int - 1000000;
}
if(select(sockfd+1, &rfds, NULL, NULL, &tv)) {
/* response received */
recv_addr_len = sizeof(recv_addr);
......@@ -685,15 +693,16 @@ int stun_bind_test(stun_socket_t *ss, struct sockaddr_in *srvr_addr, struct sock
bind_resp.enc_buf.data = (unsigned char *)malloc(z);
bind_resp.enc_buf.size = z;
memcpy(bind_resp.enc_buf.data, dgram, z);
SU_DEBUG_5(("response from server %s:%u\n", inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port)));
SU_DEBUG_3(("stun: response from server %s:%u\n", inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port)));
debug_print(&bind_resp.enc_buf);
}
else {
SU_DEBUG_3(("Time out no. %d, retransmitting.\n", ++num_retrx));
SU_DEBUG_3(("stun: Time out no. %d, retransmitting.\n", ++num_retrx));
if(stun_send_message(sockfd, srvr_addr, &bind_req, &(ss->ss_engine->password))<0) {
stun_free_message(&bind_req);
return retval;
}
z = 0;
}
}
......@@ -706,7 +715,7 @@ int stun_bind_test(stun_socket_t *ss, struct sockaddr_in *srvr_addr, struct sock
/* process response */
if(stun_parse_message(&bind_resp) < 0) {
SU_DEBUG_5(("Error parsing response.\n"));
SU_DEBUG_5(("stun: Error parsing response.\n"));
stun_free_message(&bind_req);
stun_free_message(&bind_req);
return retval;
......@@ -740,7 +749,7 @@ int stun_bind_test(stun_socket_t *ss, struct sockaddr_in *srvr_addr, struct sock
break;
case BINDING_ERROR_RESPONSE:
if(stun_process_error_response(&bind_resp)<0) {
SU_DEBUG_3(("Error in Binding Error Response.\n"));
SU_DEBUG_3(("stun: Error in Binding Error Response.\n"));
}
break;
default:
......@@ -757,7 +766,8 @@ int stun_bind_test(stun_socket_t *ss, struct sockaddr_in *srvr_addr, struct sock
}
/** Compose a STUN message of the format defined by stun_msg_t */
int stun_make_binding_req(stun_socket_t *ss, stun_msg_t *msg, int chg_ip, int chg_port) {
int stun_make_binding_req(stun_socket_t *ss, stun_msg_t *msg, int chg_ip, int chg_port)
{
int i;
stun_attr_t *tmp, **p;
......@@ -813,11 +823,12 @@ int stun_make_binding_req(stun_socket_t *ss, stun_msg_t *msg, int chg_ip, int ch
return 0;
}
int stun_process_response(stun_msg_t *msg) {
int stun_process_response(stun_msg_t *msg)
{
/* parse msg first */
if(stun_parse_message(msg)<0) {
SU_DEBUG_3(("Error parsing response.\n"));
SU_DEBUG_3(("stun: Error parsing response.\n"));
return -1;
}
......@@ -848,7 +859,8 @@ int stun_process_binding_response(stun_msg_t *msg) {
/** process binding error response
* Report error and return
*/
int stun_process_error_response(stun_msg_t *msg) {
int stun_process_error_response(stun_msg_t *msg)
{
stun_attr_t *attr;
stun_attr_errorcode_t *ec;
......@@ -857,14 +869,14 @@ int stun_process_error_response(stun_msg_t *msg) {
ec = (stun_attr_errorcode_t *)attr->pattr;
SU_DEBUG_5(("Received Binding Error Response:\n"));
SU_DEBUG_5(("Error: %d %s\n", ec->code, ec->phrase));
SU_DEBUG_5(("stun: Received Binding Error Response:\n"));
SU_DEBUG_5(("stun: Error: %d %s\n", ec->code, ec->phrase));
return 0;
}
int stun_set_uname_pwd(stun_engine_t *se, const unsigned char *uname, int len_uname,
const unsigned char *pwd, int len_pwd) {
int stun_set_uname_pwd(stun_engine_t *se, const char *uname, int len_uname, const char *pwd, int len_pwd)
{
se->username.data = (unsigned char *) malloc(len_uname);
memcpy(se->username.data, uname, len_uname);
se->username.size = len_uname;
......@@ -989,28 +1001,28 @@ int stun_get_lifetime(stun_socket_t *ss, struct sockaddr *my_addr, int *addrlen,
clnt_addr->sin_port = 0;
/* initialize socket x */
if(bind(sockfdx, (struct sockaddr *)clnt_addr, *addrlen)<0) {
SU_DEBUG_3(("Error binding to %s:%u\n", inet_ntoa(clnt_addr->sin_addr), (unsigned)ntohs(clnt_addr->sin_port)));
SU_DEBUG_3(("stun: Error binding to %s:%u\n", inet_ntoa(clnt_addr->sin_addr), (unsigned)ntohs(clnt_addr->sin_port)));
return retval;
}
x_len = sizeof(x_addr);
getsockname(sockfdx, (struct sockaddr *)&x_addr, &x_len);
SU_DEBUG_3(("Local socket x bound to: %s:%u\n", inet_ntoa(x_addr.sin_addr),
SU_DEBUG_3(("stun: Local socket x bound to: %s:%u\n", inet_ntoa(x_addr.sin_addr),
(unsigned)ntohs(x_addr.sin_port)));
/* initialize socket y */
sockfdy = socket(AF_INET, SOCK_DGRAM, 0);
if(bind(sockfdy, (struct sockaddr *)clnt_addr, *addrlen)<0) {
SU_DEBUG_3(("Error binding to %s:%u\n", inet_ntoa(clnt_addr->sin_addr), (unsigned)ntohs(clnt_addr->sin_port)));
SU_DEBUG_3(("stun: Error binding to %s:%u\n", inet_ntoa(clnt_addr->sin_addr), (unsigned)ntohs(clnt_addr->sin_port)));
return retval;
}
y_len = sizeof(y_addr);
getsockname(sockfdy, (struct sockaddr *)&y_addr, &y_len);
SU_DEBUG_3(("Local socket y bound to: %s:%u\n", inet_ntoa(y_addr.sin_addr),
SU_DEBUG_3(("stun: Local socket y bound to: %s:%u\n", inet_ntoa(y_addr.sin_addr),
(unsigned)ntohs(y_addr.sin_port)));
i=1;
while(abs(lt_cur-lt) > STUN_LIFETIME_CI) {
SU_DEBUG_3(("STUN Lifetime determination round %d, testing lifetime of %d sec.\n", i++, lt));
SU_DEBUG_3(("stun: Lifetime determination round %d, testing lifetime of %d sec.\n", i++, lt));
/* send request from X */
if(stun_make_binding_req(ss, &bind_req, 0, 0) <0)
return retval;
......@@ -1033,16 +1045,16 @@ int stun_get_lifetime(stun_socket_t *ss, struct sockaddr *my_addr, int *addrlen,
bind_resp.enc_buf.data = (unsigned char *)malloc(z);
bind_resp.enc_buf.size = z;
memcpy(bind_resp.enc_buf.data, dgram, z);
SU_DEBUG_3(("response from server %s:%u\n", inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port)));
SU_DEBUG_3(("stun: response from server %s:%u\n", inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port)));
debug_print(&bind_resp.enc_buf);
}
else {
SU_DEBUG_3(("No response from server. Check configuration.\n"));
SU_DEBUG_3(("stun: No response from server. Check configuration.\n"));
return retval;
}
/* process response */
if(stun_parse_message(&bind_resp) < 0) {
SU_DEBUG_5(("Error parsing response.\n"));
SU_DEBUG_5(("stun: Error parsing response.\n"));
return retval;
}
if(bind_resp.stun_hdr.msg_type==BINDING_RESPONSE) {
......@@ -1081,14 +1093,14 @@ int stun_get_lifetime(stun_socket_t *ss, struct sockaddr *my_addr, int *addrlen,
/* mapping with X still valid */
lt_cur = lt;
lt = (int) (lt+lt_max)/2;
SU_DEBUG_3(("Response received from socket X, lifetime at least %d sec, next trial: %d sec\n\n",
SU_DEBUG_3(("stun: Response received from socket X, lifetime at least %d sec, next trial: %d sec\n\n",
lt_cur, lt));
}
else {
/* no response */
lt_max = lt;
lt = (int) (lt+lt_cur)/2;
SU_DEBUG_3(("No response received from socket X, lifetime at most %d sec, next trial: %d sec\n\n",
SU_DEBUG_3(("stun: No response received from socket X, lifetime at most %d sec, next trial: %d sec\n\n",
lt_max, lt));
}
}
......
......@@ -13,6 +13,17 @@ client library.
@section stun_usage Using Sofia STUN Library
<i>To be written.</i>
To be written.
@section todo Todo
- merge NAT-type check and stun_bind_tests (no
use in using STUN if the NAT type is symmetric) (added 20051118)
- output a summary of results at the end of
stund_bind_test() (added 20051118)
- stun_bind_test does not detect, if the server does
_not_ honor the change-{address,port} requests (i.e. that
response should be send from a different port/address),
which leads to incorrect analysis of NAT behaviour (added 20051119)
*/
......@@ -74,8 +74,8 @@ int stun_get_lifetime(stun_socket_t *ss,
int *lifetime);
/** other functions */
int stun_set_uname_pwd(stun_engine_t *se, const unsigned char *uname, int len_uname,
const unsigned char *pwd, int len_pwd);
int stun_set_uname_pwd(stun_engine_t *se, const char *uname, int len_uname,
const char *pwd, int len_pwd);
/* internal functions declaration */
......
......@@ -44,7 +44,13 @@
#define LARGEST_ATTRIBUTE TURN_LARGEST_ATTRIBUTE
#endif
#ifndef SU_DEBUG
#define SU_DEBUG 3
#endif
#define SU_LOG (stun_log)
#include <su_debug.h>
#include "stun_common.h"
const char stun_400_Bad_request[] = "Bad Request",
......@@ -77,11 +83,13 @@ int stun_parse_message(stun_msg_t *msg) {
msg->stun_hdr.msg_type = ntohs(tmp16);
memcpy(&tmp16, p, 2); p+=2;
msg->stun_hdr.msg_len = ntohs(tmp16);
for(i=0; i<8; i++) {
memcpy(&tmp16, p, 2); p+=2;
msg->stun_hdr.tran_id[i] = ntohs(tmp16);
}
fprintf(stderr, "Parse STUN message: Length = %d\n", msg->stun_hdr.msg_len);
SU_DEBUG_5(("stun: Parse STUN message: Length = %d\n", msg->stun_hdr.msg_len));
/* parse attributes */
len = msg->stun_hdr.msg_len;
......@@ -90,7 +98,7 @@ int stun_parse_message(stun_msg_t *msg) {
while(len > 0) {
i = stun_parse_attribute(msg, p);
if(i <= 0) {
fprintf(stderr, "Error parsing attribute.\n");
SU_DEBUG_0(("stun: Error parsing attribute.\n"));
return -1;
}
p += i;
......@@ -120,8 +128,8 @@ int stun_parse_attribute(stun_msg_t *msg, unsigned char *p) {
p+=2;
len = ntohs(tmp16);
fprintf(stderr, "Parsing attribute: Type %02X, Length %d - %s\n",
attr->attr_type, len, stun_attr_phrase(attr->attr_type));
SU_DEBUG_3(("stun: received attribute: Type %02X, Length %d - %s\n",
attr->attr_type, len, stun_attr_phrase(attr->attr_type)));
switch(attr->attr_type) {
case MAPPED_ADDRESS:
case RESPONSE_ADDRESS:
......@@ -202,7 +210,7 @@ int stun_parse_attr_address(stun_attr_t *attr, const unsigned char *p, unsigned
memcpy(&addr->sin_port, p+2, 2);
memcpy(&addr->sin_addr.s_addr, p+4, 4);
fprintf(stderr, "parsing address attribute: %s:%d\n", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
SU_DEBUG_3(("stun: address attribute: %s:%d\n", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)));
attr->pattr = addr;
stun_init_buffer(&attr->enc_buf);
......@@ -223,7 +231,7 @@ int stun_parse_attr_error_code(stun_attr_t *attr, const unsigned char *p, unsign
error->phrase = (char *) malloc(len-4);
strncpy(error->phrase, p+4, len-4);
strncpy(error->phrase, (char*)p+4, len-4);
attr->pattr = error;
stun_init_buffer(&attr->enc_buf);
......@@ -397,7 +405,8 @@ int stun_encode_buffer(stun_attr_t *attr) {
}
int stun_encode_message_integrity(stun_attr_t *attr, unsigned char *buf, int len, stun_buffer_t *pwd) {
int dig_len, padded_len;
int padded_len;
size_t dig_len;
unsigned char *padded_text;
if(stun_encode_type_len(attr, 20)<0) {
......@@ -434,7 +443,8 @@ int stun_encode_type_len(stun_attr_t *attr, uint16_t len) {
*/
int stun_validate_message_integrity(stun_msg_t *msg, stun_buffer_t *pwd) {
int dig_len, padded_len, len;
int padded_len, len;
size_t dig_len;
unsigned char dig[20]; /* received sha1 digest */
unsigned char *padded_text;
......@@ -464,7 +474,7 @@ int stun_validate_message_integrity(stun_msg_t *msg, stun_buffer_t *pwd) {
}
}
else {
fprintf(stderr, "Message integrity validated.\n");
SU_DEBUG_5(("Message integrity validated.\n"));
}
free(padded_text);
......@@ -538,8 +548,8 @@ int stun_send_message(int sockfd, struct sockaddr_in *to_addr, stun_msg_t *msg,
z = sendto(sockfd, msg->enc_buf.data, msg->enc_buf.size,
0, (struct sockaddr *)to_addr, sizeof(*to_addr));
fprintf(stderr, "STUN message sent to %s:%u\n",
inet_ntoa(to_addr->sin_addr), ntohs(to_addr->sin_port));
SU_DEBUG_5(("stun: message sent to %s:%u\n",
inet_ntoa(to_addr->sin_addr), ntohs(to_addr->sin_port)));
debug_print(&msg->enc_buf);
return z;
......@@ -614,17 +624,17 @@ int stun_encode_message(stun_msg_t *msg, stun_buffer_t *pwd) {
msg->stun_hdr.msg_len = len;
buf_len = 20+msg->stun_hdr.msg_len;
buf = (char *)malloc(buf_len);
buf = (unsigned char *)malloc(buf_len);
/* convert to binary format for transmission */
len = 0;
tmp16 = htons(msg->stun_hdr.msg_type);
memcpy(buf, (char *)&tmp16, 2); len+=2;
memcpy(buf, (unsigned char *)&tmp16, 2); len+=2;
tmp16 = htons(msg->stun_hdr.msg_len);
memcpy(buf+len, (char *)&tmp16, 2); len+=2;
memcpy(buf+len, (unsigned char *)&tmp16, 2); len+=2;
for(i=0; i<8; i++) {
tmp16 = htons(msg->stun_hdr.tran_id[i]);
memcpy(buf+len, (char *)&tmp16, 2); len+=2;
memcpy(buf+len, (unsigned char *)&tmp16, 2); len+=2;
}
/* attaching encoded attributes */
......
......@@ -50,7 +50,8 @@ void usage(int exitcode)
int main(int argc, char *argv[])
{
int result;
int s, addrlen, lifetime;
int s, lifetime;
socklen_t addrlen;
su_sockaddr_t addr;
stun_engine_t *se;
......
......@@ -52,7 +52,6 @@ char const *name = "torture_stun";
static int test_init(char *addr);
static int test_sync_stun(char *addr);
static int test_async_stun(void);
static int test_get_nattype(char *addr);
static int test_get_lifetime(char *addr);
......@@ -140,7 +139,8 @@ int test_init(char *server)
int test_sync_stun(char *localaddr)
{
int result;
int s, addrlen, locallen, lifetime;
int s, lifetime;
socklen_t addrlen, locallen;
su_sockaddr_t addr;
stun_socket_t *ss;
struct sockaddr_in *my_addr, local;
......@@ -160,7 +160,7 @@ int test_sync_stun(char *localaddr)
char username[256], password[256];
if(fscanf(pwd, "\"%[^\"]\",\"%[^\"]\"", username, password)) {
printf("Read username, password from pwd.txt: \"%s\", \"%s\"\n", username, password);
stun_set_uname_pwd(se, username, strlen(username), password, strlen(password));
stun_set_uname_pwd(se, username, (int)strlen(username), password, (int)strlen(password));
}
fclose(pwd);
}
......@@ -287,6 +287,8 @@ int test_get_nattype(char *localaddr)
#include <poll.h>
/* XXX: Not used in the test set yet. */
#if 0
/*
* Run test asynchronously (with non-blocking socket).
* stun_bind() is called repeteadly until it returns 0 (or -1 with errno
......@@ -296,7 +298,8 @@ int test_get_nattype(char *localaddr)
int test_async_stun(void)
{
int result;
int s, addrlen, locallen, lifetime;
int s, lifetime;
socklen_t addrlen, locallen;
su_sockaddr_t addr, local;
stun_socket_t *ss;
......@@ -341,6 +344,7 @@ int test_async_stun(void)
END();
}
#endif
static int test_deinit(void)
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment