Commit b435fd9e authored by Fong's avatar Fong
Browse files

fix stack overflow and indent code

parent 7ccd0b6c
......@@ -25,7 +25,7 @@ int verbose = 0;
int main(int argc, char** argv)
{
char* stun_server = stun_servers[0];
char* local_host = "0.0.0.0";
char local_ip[16] = "0.0.0.0";
uint16_t stun_port = DEFAULT_STUN_SERVER_PORT;
uint16_t local_port = DEFAULT_LOCAL_PORT;
char* punch_server = NULL;
......@@ -34,7 +34,7 @@ int main(int argc, char** argv)
static char usage[] = "usage: [-h] [-H STUN_HOST] [-t ttl] [-P STUN_PORT] [-s punch server] [-d id] [-i SOURCE_IP] [-p SOURCE_PORT] [-v verbose]\n";
int opt;
while ((opt = getopt (argc, argv, "H:h:t:P:p:s:d:i")) != -1)
while ((opt = getopt (argc, argv, "H:h:t:P:p:s:d:i:v")) != -1)
{
switch (opt)
{
......@@ -50,20 +50,21 @@ int main(int argc, char** argv)
case 'P':
stun_port = atoi(optarg);
break;
case 's':
punch_server = optarg;
break;
case 'p':
local_port = atoi(optarg);
break;
case 's':
punch_server = optarg;
break;
case 'd':
peer_id = atoi(optarg);
break;
case 'i':
local_host = optarg;
strncpy(local_ip, optarg, 16);
break;
case 'v':
verbose = 1;
break;
case '?':
default:
printf("invalid option: %c\n", opt);
......@@ -77,7 +78,7 @@ int main(int argc, char** argv)
uint16_t ext_port = 0;
// TODO we should try another STUN server if failed
nat_type type = detect_nat_type(stun_server, stun_port, local_host, local_port, ext_ip, &ext_port);
nat_type type = detect_nat_type(stun_server, stun_port, local_ip, local_port, ext_ip, &ext_port);
printf("NAT type: %s\n", get_nat_desc(type));
if (ext_port) {
......
......@@ -148,20 +148,20 @@ static int connect_to_symmetric_nat(client* c, uint32_t peer_id, struct peer_inf
// TODO choose port prediction strategy
/*
* according to birthday paradox, probability that port randomly chosen from [1024, 65535]
* will collide with another one chosen by the same way is
* p(n) = 1-(64511!/(64511^n*64511!))
* where '!' is the factorial operator, n is the number of ports chosen.
* P(100)=0.073898
* P(200)=0.265667
* P(300)=0.501578
* P(400)=0.710488
* P(500)=0.856122
* P(600)=0.938839
* according to birthday paradox, probability that port randomly chosen from [1024, 65535]
* will collide with another one chosen by the same way is
* p(n) = 1-(64511!/(64511^n*64511!))
* where '!' is the factorial operator, n is the number of ports chosen.
* P(100)=0.073898
* P(200)=0.265667
* P(300)=0.501578
* P(400)=0.710488
* P(500)=0.856122
* P(600)=0.938839
* but symmetric NAT has port sensitive filter for incoming packet
* which makes the probalility decline dramatically.
* Moreover, symmetric NATs don't really allocate ports randomly.
*/
*/
struct sockaddr_in peer_addr;
peer_addr.sin_family = AF_INET;
......@@ -181,7 +181,8 @@ static int connect_to_symmetric_nat(client* c, uint32_t peer_id, struct peer_inf
verbose_log("%s, NAT flooding protection triggered, try %d times\n", strerror(errno), i);
break;
}
// sleep for a while to avoid flooding protection
usleep(1000 * 100);
++i;
} else {
nums[i] = nums[1000];
......@@ -255,11 +256,8 @@ static void* server_notify_handler(void* data) {
break;
}
/* add socket to FD_SET and check if connected
* set both fields of the timeval structure to zero
* to make select() return immediately
*/
struct timeval tv = {0, 0};
// wait for a while
struct timeval tv = {0, 1000 * 100};
int fd = wait_for_peer(sock_array, ++i, &tv);
if (fd > 0) {
// connected
......@@ -270,7 +268,8 @@ static void* server_notify_handler(void* data) {
}
}
struct timeval tv = {10, 0};
printf("holes punched, waiting for peer\n");
struct timeval tv = {100, 0};
int fd = wait_for_peer(sock_array, i, &tv);
if (fd > 0) {
on_connected(fd);
......
......@@ -14,123 +14,121 @@
#define MAX_RETRIES_NUM 3
static const char* nat_types[] = {
"blocked",
"open internet",
"full cone",
"restricted NAT",
"port-restricted cone",
"symmetric NAT",
"error"
"blocked",
"open internet",
"full cone",
"restricted NAT",
"port-restricted cone",
"symmetric NAT",
"error"
};
char* encode16(char* buf, uint16_t data)
{
uint16_t ndata = htons(data);
memcpy(buf, (void*)(&ndata), sizeof(uint16_t));
return buf + sizeof(uint16_t);
uint16_t ndata = htons(data);
memcpy(buf, (void*)(&ndata), sizeof(uint16_t));
return buf + sizeof(uint16_t);
}
char* encode32(char* buf, uint32_t data)
{
uint32_t ndata = htonl(data);
memcpy(buf, (void*)(&ndata), sizeof(uint32_t));
uint32_t ndata = htonl(data);
memcpy(buf, (void*)(&ndata), sizeof(uint32_t));
return buf + sizeof(uint32_t);
return buf + sizeof(uint32_t);
}
char* encodeAtrUInt32(char* ptr, uint16_t type, uint32_t value)
{
ptr = encode16(ptr, type);
ptr = encode16(ptr, 4);
ptr = encode32(ptr, value);
ptr = encode16(ptr, type);
ptr = encode16(ptr, 4);
ptr = encode32(ptr, value);
return ptr;
return ptr;
}
char* encode(char* buf, const char* data, unsigned int length)
{
memcpy(buf, data, length);
return buf + length;
memcpy(buf, data, length);
return buf + length;
}
static int stun_parse_atr_addr( char* body, unsigned int hdrLen, StunAtrAddress* result )
{
if (hdrLen != 8 /* ipv4 size */ && hdrLen != 20 /* ipv6 size */ ) {
return -1;
}
body++; // Skip pad
result->family = *body++;
uint16_t nport;
memcpy(&nport, body, 2);
if (hdrLen != 8 /* ipv4 size */ && hdrLen != 20 /* ipv6 size */ ) {
return -1;
}
body++; // Skip pad
result->family = *body++;
uint16_t nport;
memcpy(&nport, body, 2);
body+=2;
result->port = ntohs(nport);
if (result->family == IPv4Family) {
uint32_t naddr;
memcpy(&naddr, body, sizeof(uint32_t)); body+=sizeof(uint32_t);
result->addr.ipv4 = ntohl(naddr);
// Note: addr.ipv4 is stored in host byte order
return 0;
} else if (result->family == IPv6Family) {
printf("ipv6 is not implemented yet");
}
return -1;
result->port = ntohs(nport);
if (result->family == IPv4Family) {
uint32_t naddr;
memcpy(&naddr, body, sizeof(uint32_t)); body+=sizeof(uint32_t);
result->addr.ipv4 = ntohl(naddr);
// Note: addr.ipv4 is stored in host byte order
return 0;
} else if (result->family == IPv6Family) {
printf("ipv6 is not implemented yet");
}
return -1;
}
static void gen_random_string(char *s, const int len) {
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
int i = 0;
for (; i < len; ++i) {
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
}
s[len] = 0;
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
int i = 0;
for (; i < len; ++i) {
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
}
}
static int send_bind_request(int sock, const char* remote_host, uint16_t remote_port, uint32_t change_ip, uint32_t change_port, StunAtrAddress* addr_array) {
char* buf = malloc(MAX_STUN_MESSAGE_LENGTH);
char* ptr = buf;
char* buf = malloc(MAX_STUN_MESSAGE_LENGTH);
char* ptr = buf;
StunHeader h;
h.msgType = BindRequest;
gen_random_string((char*)&h.magicCookieAndTid, 16);
StunHeader h;
h.msgType = BindRequest;
gen_random_string((char*)&h.magicCookieAndTid, 16);
ptr = encode16(ptr, h.msgType);
char* lengthp = ptr;
ptr = encode16(ptr, 0);
ptr = encode(ptr, (const char*)&h.id, sizeof(h.id));
ptr = encode16(ptr, h.msgType);
char* lengthp = ptr;
ptr = encode16(ptr, 0);
ptr = encode(ptr, (const char*)&h.id, sizeof(h.id));
if (change_ip || change_port) {
ptr = encodeAtrUInt32(ptr, ChangeRequest, change_ip | change_port);
if (change_ip || change_port) {
ptr = encodeAtrUInt32(ptr, ChangeRequest, change_ip | change_port);
// length of stun body
encode16(lengthp, ptr - buf - sizeof(StunHeader));
}
// length of stun body
encode16(lengthp, ptr - buf - sizeof(StunHeader));
}
struct hostent *server = gethostbyname(remote_host);
if (server == NULL) {
fprintf(stderr, "no such host, %s\n", remote_host);
if (server == NULL) {
fprintf(stderr, "no such host, %s\n", remote_host);
free(buf);
return -1;
}
struct sockaddr_in remote_addr;
return -1;
}
struct sockaddr_in remote_addr;
remote_addr.sin_family = AF_INET;
memcpy(&remote_addr.sin_addr.s_addr, server->h_addr_list[0], server->h_length);
remote_addr.sin_port = htons(remote_port);
remote_addr.sin_family = AF_INET;
memcpy(&remote_addr.sin_addr.s_addr, server->h_addr_list[0], server->h_length);
remote_addr.sin_port = htons(remote_port);
int retries;
for (retries = 0; retries < MAX_RETRIES_NUM; retries++) {
if (-1 == sendto(sock, buf, ptr - buf, 0, (struct sockaddr *)&remote_addr, sizeof(remote_addr))) {
// udp sendto barely failed
// sendto() barely failed
free(buf);
return -1;
......@@ -159,12 +157,12 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
if (retries == MAX_RETRIES_NUM)
return -1;
StunHeader reply_header;
memcpy(&reply_header, buf, sizeof(StunHeader));
StunHeader reply_header;
memcpy(&reply_header, buf, sizeof(StunHeader));
uint16_t msg_type = ntohs(reply_header.msgType);
uint16_t msg_type = ntohs(reply_header.msgType);
if (msg_type == BindResponse) {
if (msg_type == BindResponse) {
char* body = buf + sizeof(StunHeader);
uint16_t size = ntohs(reply_header.msgLength);
......@@ -205,13 +203,6 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
return -1;
}
break;
case SourceAddress:
if (stun_parse_atr_addr( body, attrLen, addr_array + 2)) {
free(buf);
return -1;
}
break;
default:
// ignore
break;
......@@ -220,36 +211,36 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
size -= attrLen + attrLenPad;
}
}
free(buf);
free(buf);
return 0;
return 0;
}
const char* get_nat_desc(nat_type type) {
return nat_types[type];
return nat_types[type];
}
nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char* local_host, uint16_t local_port, char* ext_ip, uint16_t* ext_port) {
nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char* local_ip, uint16_t local_port, char* ext_ip, uint16_t* ext_port) {
uint32_t mapped_ip = 0;
uint16_t mapped_port = 0;
int s;
if((s = socket(AF_INET, SOCK_DGRAM, 0)) <= 0) {
return Error;
}
int s;
if((s = socket(AF_INET, SOCK_DGRAM, 0)) <= 0) {
return Error;
}
nat_type nat_type;
int reuse_addr = 1;
int reuse_addr = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_addr, sizeof(reuse_addr));
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_addr, sizeof(reuse_addr));
struct sockaddr_in local_addr;
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(local_host);
struct sockaddr_in local_addr;
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(local_ip);
local_addr.sin_port = htons(local_port);
if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr))) {
local_addr.sin_port = htons(local_port);
if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr))) {
if (errno == EADDRINUSE) {
printf("addr in use, try another port\n");
nat_type = Error;
......@@ -257,76 +248,75 @@ nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char*
}
}
// 0 for mapped addr, 1 for changed addr
StunAtrAddress bind_result[2];
// 0 for mapped addr, 1 for changed addr
StunAtrAddress bind_result[2];
memset(bind_result, 0, sizeof(StunAtrAddress) * 2);
if (send_bind_request(s, stun_host, stun_port, 0, 0, bind_result)) {
nat_type = Blocked;
memset(bind_result, 0, sizeof(StunAtrAddress) * 2);
if (send_bind_request(s, stun_host, stun_port, 0, 0, bind_result)) {
nat_type = Blocked;
goto cleanup_sock;
}
}
mapped_ip = bind_result[0].addr.ipv4; // in host byte order
mapped_port = bind_result[0].port;
uint32_t changed_ip = bind_result[1].addr.ipv4;
uint16_t changed_port = bind_result[1].port;
mapped_ip = bind_result[0].addr.ipv4; // in host byte order
mapped_port = bind_result[0].port;
uint32_t changed_ip = bind_result[1].addr.ipv4;
uint16_t changed_port = bind_result[1].port;
struct in_addr mapped_addr;
mapped_addr.s_addr = htonl(mapped_ip);
/*
* it's complicated to get the RECEIVER address of UDP packet,
* For Linux, use the setsockopt() called IP_PKTINFO
* which will get you a parameter over recvmsg() called
* IP_PKTINFO, which carries a struct in_pktinfo,
* which has a 4 byte IP address hiding in its ipi_addr field.
* For Linux/Windows, set IP_PKTINFO option to enable ancillary
* message that contains a pktinfo structure that supplies
* some information about the incoming packets
*/
/* TODO use getifaddrs() to get interface address,
* then compare it with mapped address to determine
* if it's open internet
* if it's open Internet
*/
if (!strcmp(local_host, inet_ntoa(mapped_addr))) {
if (!strcmp(local_ip, inet_ntoa(mapped_addr))) {
nat_type = OpenInternet;
goto cleanup_sock;
} else {
if (changed_ip != 0 && changed_port != 0) {
if (send_bind_request(s, stun_host, stun_port, ChangeIpFlag, ChangePortFlag, bind_result)) {
struct in_addr addr = {htonl(changed_ip)};
char* alt_host = inet_ntoa(addr);
goto cleanup_sock;
} else {
if (changed_ip != 0 && changed_port != 0) {
if (send_bind_request(s, stun_host, stun_port, ChangeIpFlag, ChangePortFlag, bind_result)) {
struct in_addr addr = {htonl(changed_ip)};
char* alt_host = inet_ntoa(addr);
memset(bind_result, 0, sizeof(StunAtrAddress) * 2);
memset(bind_result, 0, sizeof(StunAtrAddress) * 2);
if (send_bind_request(s, alt_host, changed_port, 0, 0, bind_result)) {
printf("failed to send request to alterative server\n");
if (send_bind_request(s, alt_host, changed_port, 0, 0, bind_result)) {
printf("failed to send request to alterative server\n");
nat_type = Error;
goto cleanup_sock;
}
}
if (mapped_ip != bind_result[0].addr.ipv4 || mapped_port != bind_result[0].port) {
nat_type = SymmetricNAT;
if (mapped_ip != bind_result[0].addr.ipv4 || mapped_port != bind_result[0].port) {
nat_type = SymmetricNAT;
goto cleanup_sock;
}
}
if (send_bind_request(s, alt_host, changed_port, 0, ChangePortFlag, bind_result)) {
nat_type = RestricPortNAT;
if (send_bind_request(s, alt_host, changed_port, 0, ChangePortFlag, bind_result)) {
nat_type = RestricPortNAT;
goto cleanup_sock;
}
}
nat_type = RestricNAT;
nat_type = RestricNAT;
goto cleanup_sock;
}
else {
nat_type = FullCone;
}
else {
nat_type = FullCone;
goto cleanup_sock;
}
} else {
printf("no alterative server, can't detect nat type\n");
nat_type = Error;
}
} else {
printf("no alterative server, can't detect nat type\n");
nat_type = Error;
goto cleanup_sock;
}
}
}
}
cleanup_sock:
close(s);
struct in_addr ext_addr;
......
......@@ -41,36 +41,36 @@ typedef struct { uint32_t longpart[3]; } UInt96;
typedef struct
{
uint32_t magicCookie; // rfc 5389
UInt96 tid;
uint32_t magicCookie; // rfc 5389
UInt96 tid;
} Id;
typedef struct
{
uint16_t msgType;
uint16_t msgLength; // length of stun body
union
{
UInt128 magicCookieAndTid;
Id id;
};
uint16_t msgType;
uint16_t msgLength; // length of stun body
union
{
UInt128 magicCookieAndTid;
Id id;
};
} StunHeader;
typedef struct
{
uint16_t type;
uint16_t length;
uint16_t type;
uint16_t length;
} StunAtrHdr;
typedef struct
{
uint8_t family;
uint16_t port;
union
{
uint32_t ipv4; // in host byte order
UInt128 ipv6; // in network byte order
} addr;
uint8_t family;
uint16_t port;
union
{
uint32_t ipv4; // in host byte order
UInt128 ipv6; // in network byte order
} addr;
} StunAtrAddress;
char* encode16(char* buf, uint16_t data);
......
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