Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
nat_traversal
Commits
70c0ff3d
Commit
70c0ff3d
authored
Nov 27, 2018
by
YI
Browse files
connect to client with user provided meta info
parent
868f68b4
Changes
10
Show whitespace changes
Inline
Side-by-side
.gitignore
View file @
70c0ff3d
...
@@ -2,3 +2,4 @@
...
@@ -2,3 +2,4 @@
*.o
*.o
.DS_Store
.DS_Store
*.swp
*.swp
.ccls-cache/
Makefile
View file @
70c0ff3d
CC
=
gcc
CC
=
gcc
CFLAGS
=
-g
-Wall
CFLAGS
=
-g
-Wall
all
:
nat_traversal
all
:
nat_traversal
punch_server stun_server_test
# clang warn about unused argument, it requires -pthread when compiling but not when linking
# clang warn about unused argument, it requires -pthread when compiling but not when linking
nat_traversal
:
main.o nat_traversal.o nat_type.o
nat_traversal
:
main.o nat_traversal.o nat_type.o
$(CC)
$(CFLAGS)
-o
nat_traversal main.o nat_traversal.o nat_type.o
-pthread
$(CC)
$(CFLAGS)
-o
nat_traversal main.o nat_traversal.o nat_type.o
-pthread
punch_server
:
punch_server.go
go build punch_server.go
stun_server_test
:
stun_server_test.c
gcc stun_host_test.c nat_type.c
-o
stun_host_test
main.o
:
main.c
main.o
:
main.c
$(CC)
$(CFLAGS)
-c
main.c
$(CC)
$(CFLAGS)
-c
main.c
...
@@ -17,4 +23,4 @@ nat_type.o: nat_type.c
...
@@ -17,4 +23,4 @@ nat_type.o: nat_type.c
$(CC)
$(CFLAGS)
-c
nat_type.c
$(CC)
$(CFLAGS)
-c
nat_type.c
clean
:
clean
:
$(RM)
nat_traversal
*
.o
*
~
$(RM)
stun_host_test punch_server
nat_traversal
*
.o
*
~
main.c
View file @
70c0ff3d
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <stdio.h>
#include <pthread.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "nat_traversal.h"
#include "nat_traversal.h"
#include "utils.h"
#define DEFAULT_SERVER_PORT 9988
#define DEFAULT_SERVER_PORT 9988
#define MSG_BUF_SIZE 512
#define MSG_BUF_SIZE 512
#define STUN_SERVER_RETRIES 3
// use public stun servers to detect port allocation rule
static
char
*
stun_servers
[]
=
{
"stun.ideasip.com"
,
"stun.ekiga.net"
,
"203.183.172.196"
};
// definition checked against extern declaration
// definition checked against extern declaration
int
verbose
=
0
;
int
verbose
=
0
;
int
main
(
int
argc
,
char
**
argv
)
int
main
(
int
argc
,
char
**
argv
)
{
{
char
*
stun_server
=
NULL
;
char
*
stun_server
=
stun_servers
[
0
];
char
local_ip
[
16
]
=
"0.0.0.0"
;
char
local_ip
[
16
]
=
"0.0.0.0"
;
uint16_t
stun_port
=
DEFAULT_STUN_SERVER_PORT
;
uint16_t
stun_port
=
DEFAULT_STUN_SERVER_PORT
;
uint16_t
local_port
=
DEFAULT_LOCAL_PORT
;
uint16_t
local_port
=
DEFAULT_LOCAL_PORT
;
char
*
punch_server
=
NULL
;
char
*
punch_server
=
NULL
;
char
*
meta
=
NULL
;
char
*
peer_meta
=
NULL
;
uint32_t
peer_id
=
0
;
uint32_t
peer_id
=
0
;
int
ttl
=
10
;
int
ttl
=
10
;
int
get_info
=
0
;
int
get_info_from_meta
=
0
;
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
"
;
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
;
int
opt
;
while
((
opt
=
getopt
(
argc
,
argv
,
"H:h:t:P:p:s:d:i:v"
))
!=
-
1
)
while
((
opt
=
getopt
(
argc
,
argv
,
"H:h:I:t:P:p:s:m:o:d:i:vzZ"
))
!=
-
1
)
{
{
switch
(
opt
)
{
switch
(
opt
)
{
case
'h'
:
case
'h'
:
printf
(
"%s"
,
usage
);
printf
(
"%s"
,
usage
);
break
;
break
;
case
'z'
:
get_info
=
1
;
break
;
case
'Z'
:
get_info_from_meta
=
1
;
break
;
case
'H'
:
case
'H'
:
stun_server
=
optarg
;
stun_server
=
optarg
;
break
;
break
;
...
@@ -56,6 +61,12 @@ int main(int argc, char** argv)
...
@@ -56,6 +61,12 @@ int main(int argc, char** argv)
case
's'
:
case
's'
:
punch_server
=
optarg
;
punch_server
=
optarg
;
break
;
break
;
case
'm'
:
meta
=
optarg
;
break
;
case
'o'
:
peer_meta
=
optarg
;
break
;
case
'd'
:
case
'd'
:
peer_id
=
atoi
(
optarg
);
peer_id
=
atoi
(
optarg
);
break
;
break
;
...
@@ -74,47 +85,124 @@ int main(int argc, char** argv)
...
@@ -74,47 +85,124 @@ int main(int argc, char** argv)
}
}
}
}
if
(
punch_server
==
NULL
)
{
printf
(
"please specify punch server
\n
"
);
return
-
1
;
}
struct
sockaddr_in
server_addr
;
server_addr
.
sin_family
=
AF_INET
;
server_addr
.
sin_addr
.
s_addr
=
inet_addr
(
punch_server
);
server_addr
.
sin_port
=
htons
(
DEFAULT_SERVER_PORT
);
if
(
get_info
)
{
client
cli
;
struct
peer_info
peer
;
int
res
=
init
(
server_addr
,
&
cli
);
if
(
res
)
{
printf
(
"init punch server socket failed
\n
"
);
return
res
;
}
if
(
!
peer_id
)
{
printf
(
"failed to get peer_id
\n
"
);
return
-
1
;
}
int
n
=
get_peer_info
(
&
cli
,
peer_id
,
&
peer
);
if
(
n
)
{
verbose_log
(
"get_peer_info() returned %d
\n
"
,
n
);
printf
(
"failed to get info of remote peer
\n
"
);
return
-
1
;
}
return
0
;
}
if
(
get_info_from_meta
)
{
client
cli
;
struct
peer_info
peer
;
int
res
=
init
(
server_addr
,
&
cli
);
if
(
res
)
{
printf
(
"init punch server socket failed
\n
"
);
return
res
;
}
if
(
peer_meta
==
NULL
)
{
printf
(
"failed to get peer_meta
\n
"
);
return
-
1
;
}
int
n
=
get_peer_info_from_meta
(
&
cli
,
peer_meta
,
&
peer
);
if
(
n
)
{
printf
(
"failed to get info of remote peer
\n
"
);
return
-
1
;
}
return
0
;
}
char
ext_ip
[
16
]
=
{
0
};
char
ext_ip
[
16
]
=
{
0
};
uint16_t
ext_port
=
0
;
uint16_t
ext_port
=
0
;
// TODO we should try another STUN server if failed
// TODO we should try another STUN server if failed
nat_type
type
=
detect_nat_type
(
stun_server
,
stun_port
,
local_ip
,
local_port
,
ext_ip
,
&
ext_port
);
int
i
;
nat_type
type
;
printf
(
"NAT type: %s
\n
"
,
get_nat_desc
(
type
));
for
(
i
=
0
;
i
<
STUN_SERVER_RETRIES
;
i
++
)
{
if
(
ext_port
)
{
type
=
detect_nat_type
(
stun_server
,
stun_port
,
local_ip
,
local_port
,
ext_ip
,
printf
(
"external address: %s:%d
\n
"
,
ext_ip
,
ext_port
);
&
ext_port
);
}
else
{
if
(
type
!=
0
)
{
return
-
1
;
break
;
}
}
}
if
(
!
punch_server
)
{
if
(
!
ext_port
)
{
printf
(
"please specify punch server
\n
"
);
return
-
1
;
return
-
1
;
}
}
verbose_log
(
"nat detect got ip: %s, port %d
\n
"
,
ext_ip
,
ext_port
);
struct
peer_info
self
;
struct
peer_info
self
;
strncpy
(
self
.
ip
,
ext_ip
,
16
);
self
.
meta
=
malloc
(
32
);
strcpy
(
self
.
ip
,
ext_ip
);
self
.
port
=
ext_port
;
self
.
port
=
ext_port
;
self
.
type
=
type
;
self
.
type
=
type
;
/* printf("first %s %ld\n", meta, strlen(meta)); */
if
(
meta
!=
NULL
)
{
strcpy
(
self
.
meta
,
meta
);
}
else
{
gen_random_string
(
self
.
meta
,
20
);
}
/* printf("first %s %ld\n", self.meta, strlen(self.meta)); */
str
uct
sockaddr_in
server_addr
;
/*
str
ncpy(self.meta, meta, strlen(meta)); */
server_addr
.
sin_family
=
AF_INET
;
/* printf(""); */
server_addr
.
sin_addr
.
s_addr
=
inet_addr
(
punch_server
);
server_addr
.
sin_port
=
htons
(
DEFAULT_SERVER_PORT
);
/* printf("second %s %ld\n", meta, strlen(meta)); */
client
c
;
client
c
;
c
.
type
=
type
;
c
.
type
=
type
;
c
.
ttl
=
ttl
;
c
.
ttl
=
ttl
;
/* printf("third %s %ld\n", self.meta, strlen(self.meta)); */
if
(
enroll
(
self
,
server_addr
,
&
c
)
<
0
)
{
if
(
enroll
(
self
,
server_addr
,
&
c
)
<
0
)
{
printf
(
"failed to enroll
\n
"
);
printf
(
"failed to enroll
\n
"
);
return
-
1
;
return
-
1
;
}
}
printf
(
"enroll successfully, ID: %d
\n
"
,
c
.
id
);
verbose_log
(
"enroll successfully, ID: %d
\n
"
,
c
.
id
);
if
(
peer_id
)
{
if
(
peer_id
)
{
printf
(
"connecting to peer %d
\n
"
,
peer_id
);
verbose_log
(
"connecting to peer %d
\n
"
,
peer_id
);
if
(
connect_to_peer
(
&
c
,
peer_id
)
<
0
)
{
if
(
connect_to_peer
(
&
c
,
peer_id
)
<
0
)
{
printf
(
"failed to connect to peer %d
\n
"
,
peer_id
);
verbose_log
(
"failed to connect to peer %d
\n
"
,
peer_id
);
return
-
1
;
}
}
if
(
peer_meta
!=
NULL
)
{
verbose_log
(
"connecting to peer %s
\n
"
,
peer_meta
);
if
(
connect_to_peer_from_meta
(
&
c
,
peer_meta
)
<
0
)
{
verbose_log
(
"failed to connect to peer %s
\n
"
,
peer_meta
);
return
-
1
;
return
-
1
;
}
}
...
...
nat_traversal.c
View file @
70c0ff3d
#include <arpa/inet.h>
#include <errno.h>
#include <math.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <
netinet/in
.h>
#include <
sys/time
.h>
#include <
netdb
.h>
#include <
time
.h>
#include <
pthrea
d.h>
#include <
unist
d.h>
#include "nat_traversal.h"
#include "nat_traversal.h"
...
@@ -22,66 +23,116 @@
...
@@ -22,66 +23,116 @@
// file scope variables
// file scope variables
static
int
ports
[
MAX_PORT
-
MIN_PORT
];
static
int
ports
[
MAX_PORT
-
MIN_PORT
];
static
int
send_to_punch_server
(
client
*
c
)
{
static
int
send_to_punch_server
(
client
*
c
)
{
verbose_log
(
"sending %ld bytes of data to punch server
\n
"
,
c
->
msg_buf
-
c
->
buf
);
hexDump
(
NULL
,
c
->
buf
,
c
->
msg_buf
-
c
->
buf
);
int
n
=
send
(
c
->
sfd
,
c
->
buf
,
c
->
msg_buf
-
c
->
buf
,
0
);
int
n
=
send
(
c
->
sfd
,
c
->
buf
,
c
->
msg_buf
-
c
->
buf
,
0
);
c
->
msg_buf
=
c
->
buf
;
c
->
msg_buf
=
c
->
buf
;
if
(
n
==
-
1
)
{
verbose_log
(
"send to punch server, error number: %d, error: %s
\n
"
,
errno
,
strerror
(
errno
));
return
n
;
return
n
;
}
return
0
;
}
}
static
int
get_peer_info
(
client
*
cli
,
uint32_t
peer_id
,
struct
peer_info
*
peer
)
{
int
get_peer_info
(
client
*
cli
,
uint32_t
peer_id
,
struct
peer_info
*
peer
)
{
cli
->
msg_buf
=
cli
->
buf
;
cli
->
msg_buf
=
encode16
(
cli
->
msg_buf
,
GetPeerInfo
);
cli
->
msg_buf
=
encode16
(
cli
->
msg_buf
,
GetPeerInfo
);
cli
->
msg_buf
=
encode32
(
cli
->
msg_buf
,
peer_id
);
cli
->
msg_buf
=
encode32
(
cli
->
msg_buf
,
peer_id
);
if
(
-
1
==
send_to_punch_server
(
cli
))
{
return
send_get_peer_info_request
(
cli
,
peer
);
return
-
1
;
}
}
int
n_bytes
=
recv
(
cli
->
sfd
,
(
void
*
)
peer
,
sizeof
(
struct
peer_info
),
0
);
int
get_peer_info_from_meta
(
client
*
cli
,
char
peer_meta
[
21
],
struct
peer_info
*
peer
)
{
cli
->
msg_buf
=
cli
->
buf
;
cli
->
msg_buf
=
encode16
(
cli
->
msg_buf
,
GetPeerInfoFromMeta
);
cli
->
msg_buf
=
encode8
(
cli
->
msg_buf
,
(
uint8_t
)
strlen
(
peer_meta
));
cli
->
msg_buf
=
encode
(
cli
->
msg_buf
,
peer_meta
,
strlen
(
peer_meta
));
return
send_get_peer_info_request
(
cli
,
peer
);
}
int
recv_peer_info
(
int
fd
,
struct
peer_info
*
peer
)
{
struct
my_peer_info
peer_i
;
int
n_bytes
;
n_bytes
=
recv
(
fd
,
(
void
*
)
&
peer_i
,
sizeof
(
struct
my_peer_info
),
0
);
if
(
n_bytes
<=
0
)
{
if
(
n_bytes
<=
0
)
{
return
-
1
;
return
-
1
;
}
else
if
(
n_bytes
==
1
)
{
}
// offline
if
(
n_bytes
==
1
)
{
// offline or error
verbose_log
(
"It seems peer has gone offline
\n
"
);
return
1
;
return
1
;
}
else
{
}
peer
->
port
=
ntohs
(
peer
->
port
);
verbose_log
(
peer
->
type
=
ntohs
(
peer
->
type
);
"Dumping %d bytes of data received, should have dumped %ld bytes
\n
"
,
n_bytes
,
sizeof
(
struct
my_peer_info
));
hexDump
(
NULL
,
&
peer_i
,
n_bytes
);
peer
->
id
=
ntohl
(
peer_i
.
id
);
verbose_log
(
"The ip got is %s
\n
"
,
peer_i
.
ip
);
strcpy
(
peer
->
ip
,
peer_i
.
ip
);
peer
->
port
=
ntohs
(
peer_i
.
port
);
peer
->
type
=
ntohs
(
peer_i
.
type
);
verbose_log
(
"Peer info got, id: %d, ip: %s, port: %d, type: %s, len: %d
\n
"
,
peer
->
id
,
peer
->
ip
,
peer
->
port
,
get_nat_desc
(
peer
->
type
),
peer_i
.
len
);
peer
->
meta
=
malloc
(
peer_i
.
len
+
1
);
int
m_bytes
=
recv
(
fd
,
(
void
*
)
peer
->
meta
,
peer_i
.
len
,
0
);
if
(
m_bytes
<=
0
)
{
verbose_log
(
"failed to get meta, error: %s
\n
"
,
strerror
(
errno
));
return
-
1
;
}
verbose_log
(
"meta is %s
\n
"
,
peer
->
meta
);
n_bytes
+=
m_bytes
;
hexDump
(
NULL
,
peer
,
n_bytes
);
return
n_bytes
;
}
int
send_get_peer_info_request
(
client
*
cli
,
struct
peer_info
*
peer
)
{
if
(
-
1
==
send_to_punch_server
(
cli
))
{
return
-
1
;
}
if
(
recv_peer_info
(
cli
->
sfd
,
peer
)
>
0
)
{
return
0
;
return
0
;
}
}
return
-
1
;
}
}
static
int
send_dummy_udp_packet
(
int
fd
,
struct
sockaddr_in
addr
)
{
static
int
send_dummy_udp_packet
(
int
fd
,
struct
sockaddr_in
addr
)
{
char
dummy
=
'c'
;
char
dummy
=
'c'
;
struct
timeval
tv
=
{
5
,
0
};
struct
timeval
tv
=
{
5
,
0
};
setsockopt
(
fd
,
SOL_SOCKET
,
SO_SNDTIMEO
,
(
const
char
*
)
&
tv
,
sizeof
(
tv
));
setsockopt
(
fd
,
SOL_SOCKET
,
SO_SNDTIMEO
,
(
const
char
*
)
&
tv
,
sizeof
(
tv
));
return
sendto
(
fd
,
&
dummy
,
1
,
0
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
));
return
sendto
(
fd
,
&
dummy
,
1
,
0
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
));
}
}
static
int
punch_hole
(
struct
sockaddr_in
peer_addr
,
int
ttl
)
{
static
int
punch_hole
(
struct
sockaddr_in
peer_addr
,
int
ttl
)
{
int
hole
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
int
hole
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
if
(
hole
!=
-
1
)
{
if
(
hole
!=
-
1
)
{
//struct sockaddr_in local_addr;
// struct sockaddr_in local_addr;
//local_addr.sin_family = AF_INET;
// local_addr.sin_family = AF_INET;
//local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//local_addr.sin_port = htons(DEFAULT_LOCAL_PORT + 1);
// local_addr.sin_port = htons(DEFAULT_LOCAL_PORT + 1);
//int reuse_addr = 1;
// int reuse_addr = 1;
//setsockopt(hole, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_addr, sizeof(reuse_addr));
// setsockopt(hole, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_addr,
//if (bind(hole, (struct sockaddr *)&local_addr, sizeof(local_addr))) {
// sizeof(reuse_addr)); if (bind(hole, (struct sockaddr *)&local_addr,
// sizeof(local_addr))) {
// if (errno == EADDRINUSE) {
// if (errno == EADDRINUSE) {
//
printf
("addr already in use, try another port\n");
//
verbose_log
("addr already in use, try another port\n");
// return -1;
// return -1;
// }
// }
//}
//}
/* TODO we can use traceroute to get the number of hops to the peer
/* TODO we can use traceroute to get the number of hops to the peer
* to make sure this packet woudn't reach the peer but get through the NAT in front of itself
* to make sure this packet woudn't reach the peer but get through the NAT
* in front of itself
*/
*/
setsockopt
(
hole
,
IPPROTO_IP
,
IP_TTL
,
&
ttl
,
sizeof
(
ttl
));
setsockopt
(
hole
,
IPPROTO_IP
,
IP_TTL
,
&
ttl
,
sizeof
(
ttl
));
// send short ttl packets to avoid triggering flooding protection of NAT in front of peer
// send short ttl packets to avoid triggering flooding protection of NAT in
// front of peer
if
(
send_dummy_udp_packet
(
hole
,
peer_addr
)
<
0
)
{
if
(
send_dummy_udp_packet
(
hole
,
peer_addr
)
<
0
)
{
return
-
1
;
return
-
1
;
}
}
...
@@ -90,7 +141,7 @@ static int punch_hole(struct sockaddr_in peer_addr, int ttl) {
...
@@ -90,7 +141,7 @@ static int punch_hole(struct sockaddr_in peer_addr, int ttl) {
return
hole
;
return
hole
;
}
}
static
int
wait_for_peer
(
int
*
socks
,
int
sock_num
,
struct
timeval
*
timeout
)
{
static
int
wait_for_peer
(
int
*
socks
,
int
sock_num
,
struct
timeval
*
timeout
)
{
fd_set
fds
;
fd_set
fds
;
int
max_fd
=
0
;
int
max_fd
=
0
;
FD_ZERO
(
&
fds
);
FD_ZERO
(
&
fds
);
...
@@ -144,17 +195,14 @@ static void shuffle(int *num, int len) {
...
@@ -144,17 +195,14 @@ static void shuffle(int *num, int len) {
}
}
}
}
static
int
connect_to_symmetric_nat
(
client
*
c
,
uint32_t
peer_id
,
struct
peer_info
remote_peer
)
{
static
int
connect_to_symmetric_nat
(
client
*
c
,
struct
peer_info
remote_peer
)
{
// TODO choose port prediction strategy
// TODO choose port prediction strategy
/*
/*
* according to birthday paradox, probability that port randomly chosen from [1024, 65535]
* according to birthday paradox, probability that port randomly chosen from
* will collide with another one chosen by the same way is
* [1024, 65535] will collide with another one chosen by the same way is p(n)
* p(n) = 1-(64511!/(64511^n*64511!))
* = 1-(64511!/(64511^n*64511!)) where '!' is the factorial operator, n is the
* where '!' is the factorial operator, n is the number of ports chosen.
* number of ports chosen. P(100)=0.073898 P(200)=0.265667 P(300)=0.501578
* P(100)=0.073898
* P(200)=0.265667
* P(300)=0.501578
* P(400)=0.710488
* P(400)=0.710488
* P(500)=0.856122
* P(500)=0.856122
* P(600)=0.938839
* P(600)=0.938839
...
@@ -177,7 +225,8 @@ static int connect_to_symmetric_nat(client* c, uint32_t peer_id, struct peer_inf
...
@@ -177,7 +225,8 @@ static int connect_to_symmetric_nat(client* c, uint32_t peer_id, struct peer_inf
peer_addr
.
sin_port
=
htons
(
port
);
peer_addr
.
sin_port
=
htons
(
port
);
if
((
holes
[
i
]
=
punch_hole
(
peer_addr
,
c
->
ttl
))
<
0
)
{
if
((
holes
[
i
]
=
punch_hole
(
peer_addr
,
c
->
ttl
))
<
0
)
{
// NAT in front of us wound't tolerate too many ports used by one application
// NAT in front of us wound't tolerate too many ports used by one
// application
verbose_log
(
"failed to punch hole, error: %s
\n
"
,
strerror
(
errno
));
verbose_log
(
"failed to punch hole, error: %s
\n
"
,
strerror
(
errno
));
break
;
break
;
}
}
...
@@ -192,10 +241,10 @@ static int connect_to_symmetric_nat(client* c, uint32_t peer_id, struct peer_inf
...
@@ -192,10 +241,10 @@ static int connect_to_symmetric_nat(client* c, uint32_t peer_id, struct peer_inf
// hole punched, notify remote peer via punch server
// hole punched, notify remote peer via punch server
c
->
msg_buf
=
encode16
(
c
->
msg_buf
,
NotifyPeer
);
c
->
msg_buf
=
encode16
(
c
->
msg_buf
,
NotifyPeer
);
c
->
msg_buf
=
encode32
(
c
->
msg_buf
,
peer
_
id
);
c
->
msg_buf
=
encode32
(
c
->
msg_buf
,
remote_
peer
.
id
);
send_to_punch_server
(
c
);
send_to_punch_server
(
c
);
struct
timeval
timeout
=
{
100
,
0
};
struct
timeval
timeout
=
{
100
,
0
};
int
fd
=
wait_for_peer
(
holes
,
i
,
&
timeout
);
int
fd
=
wait_for_peer
(
holes
,
i
,
&
timeout
);
if
(
fd
>
0
)
{
if
(
fd
>
0
)
{
on_connected
(
fd
);
on_connected
(
fd
);
...
@@ -204,29 +253,15 @@ static int connect_to_symmetric_nat(client* c, uint32_t peer_id, struct peer_inf
...
@@ -204,29 +253,15 @@ static int connect_to_symmetric_nat(client* c, uint32_t peer_id, struct peer_inf
for
(;
j
<
i
;
++
j
)
{
for
(;
j
<
i
;
++
j
)
{
close
(
holes
[
j
]);
close
(
holes
[
j
]);
}
}
printf
(
"timout, not connected
\n
"
);
verbose_log
(
"timout, not connected
\n
"
);
}
}
return
0
;
return
0
;
}
}
// run in another thread
void
try_connect_to_peer
(
struct
peer_info
peer
)
{
static
void
*
server_notify_handler
(
void
*
data
)
{
verbose_log
(
"recved command, ready to connect to %s:%d
\n
"
,
peer
.
ip
,
int
server_sock
=
*
(
int
*
)
data
;
peer
.
port
);
struct
peer_info
peer
;
// wait for notification
printf
(
"waiting for notification...
\n
"
);
for
(;
;)
{
if
(
recv
(
server_sock
,
&
peer
,
sizeof
peer
,
0
)
>
0
)
{
break
;
}
}
peer
.
port
=
ntohs
(
peer
.
port
);
peer
.
type
=
ntohs
(
peer
.
type
);
printf
(
"recved command, ready to connect to %s:%d
\n
"
,
peer
.
ip
,
peer
.
port
);
struct
sockaddr_in
peer_addr
;
struct
sockaddr_in
peer_addr
;
...
@@ -244,7 +279,7 @@ static void* server_notify_handler(void* data) {
...
@@ -244,7 +279,7 @@ static void* server_notify_handler(void* data) {
continue
;
continue
;
}
}
if
((
sock_array
[
i
]
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
))
<
0
)
{
if
((
sock_array
[
i
]
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
))
<
0
)
{
printf
(
"failed to create socket, send %d probe packets
\n
"
,
i
);
verbose_log
(
"failed to create socket, send %d probe packets
\n
"
,
i
);
break
;
break
;
}
}
...
@@ -252,7 +287,7 @@ static void* server_notify_handler(void* data) {
...
@@ -252,7 +287,7 @@ static void* server_notify_handler(void* data) {
// let OS choose available ports
// let OS choose available ports
if
(
send_dummy_udp_packet
(
sock_array
[
i
],
peer_addr
)
<
0
)
{
if
(
send_dummy_udp_packet
(
sock_array
[
i
],
peer_addr
)
<
0
)
{
printf
(
"may trigger flooding protection
\n
"
);
verbose_log
(
"may trigger flooding protection
\n
"
);
break
;
break
;
}
}
...
@@ -264,11 +299,11 @@ static void* server_notify_handler(void* data) {
...
@@ -264,11 +299,11 @@ static void* server_notify_handler(void* data) {
on_connected
(
fd
);
on_connected
(
fd
);
// TODO
// TODO
return
NULL
;
return
;
}
}
}
}
printf
(
"holes punched, waiting for peer
\n
"
);
verbose_log
(
"holes punched, waiting for peer
\n
"
);
struct
timeval
tv
=
{
100
,
0
};
struct
timeval
tv
=
{
100
,
0
};
int
fd
=
wait_for_peer
(
sock_array
,
i
,
&
tv
);
int
fd
=
wait_for_peer
(
sock_array
,
i
,
&
tv
);
if
(
fd
>
0
)
{
if
(
fd
>
0
)
{
...
@@ -279,58 +314,138 @@ static void* server_notify_handler(void* data) {
...
@@ -279,58 +314,138 @@ static void* server_notify_handler(void* data) {
close
(
sock_array
[
j
]);
close
(
sock_array
[
j
]);
}
}
}
}
}
// TODO wait for next notification
// run in another thread
static
void
*
server_notify_handler
(
void
*
data
)
{
int
server_sock
=
*
(
int
*
)
data
;
struct
peer_info
peer
;
// wait for notification
verbose_log
(
"waiting for notification...
\n
"
);
for
(;;)
{
struct
peer_info
peer
;
if
(
recv_peer_info
(
server_sock
,
&
peer
)
>
0
)
{
break
;
}
}
verbose_log
(
"recved command, ready to connect to %s:%d
\n
"
,
peer
.
ip
,
peer
.
port
);
try_connect_to_peer
(
peer
);
return
NULL
;
return
NULL
;
}
}
int
enroll
(
struct
peer_info
self
,
struct
sockaddr_in
punch_server
,
client
*
c
)
{
void
hexDump
(
char
*
desc
,
void
*
addr
,
int
len
)
{
int
i
,
temp
;
int
i
;
for
(
i
=
0
,
temp
=
MIN_PORT
;
temp
<=
MAX_PORT
;
i
++
,
temp
++
)
{
unsigned
char
buff
[
17
];
ports
[
i
]
=
temp
;
unsigned
char
*
pc
=
(
unsigned
char
*
)
addr
;
// Output description if given.
if
(
desc
!=
NULL
)
verbose_log
(
"%s:
\n
"
,
desc
);
// Process every byte in the data.
for
(
i
=
0
;
i
<
len
;
i
++
)
{
// Multiple of 16 means new line (with line offset).
if
((
i
%
16
)
==
0
)
{
// Just don't print ASCII for the zeroth line.
if
(
i
!=
0
)
verbose_log
(
" %s
\n
"
,
buff
);
// Output the offset.
verbose_log
(
" %04x "
,
i
);
}
}
int
server_sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
// Now the hex code for the specific character.
verbose_log
(
" %02x"
,
pc
[
i
]);
if
(
connect
(
server_sock
,
(
struct
sockaddr
*
)
&
punch_server
,
sizeof
(
punch_server
))
<
0
)
{
// And store a printable ASCII character for later.
printf
(
"failed to connect to punch server
\n
"
);
if
((
pc
[
i
]
<
0x20
)
||
(
pc
[
i
]
>
0x7e
))
{
buff
[
i
%
16
]
=
'.'
;
}
else
{
buff
[
i
%
16
]
=
pc
[
i
];
}
return
-
1
;
buff
[(
i
%
16
)
+
1
]
=
'\0'
;
}
// Pad out last line if not exactly 16 characters.
while
((
i
%
16
)
!=
0
)
{
verbose_log
(
" "
);
i
++
;
}
}
// And print the final ASCII bit.
verbose_log
(
" %s
\n
"
,
buff
);
}
int
init
(
struct
sockaddr_in
punch_server
,
client
*
c
)
{
int
server_sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
int
res
=
connect
(
server_sock
,
(
struct
sockaddr
*
)
&
punch_server
,
sizeof
(
punch_server
));
if
(
res
<
0
)
{
verbose_log
(
"failed to connect to punch server: %d, port: %d
\n
"
,
punch_server
.
sin_addr
.
s_addr
,
punch_server
.
sin_port
);
verbose_log
(
"code: %d, error: %s
\n
"
,
res
,
strerror
(
errno
));
return
res
;
}
c
->
sfd
=
server_sock
;
c
->
sfd
=
server_sock
;
return
0
;
}
int
enroll
(
struct
peer_info
self
,
struct
sockaddr_in
punch_server
,
client
*
c
)
{
verbose_log
(
"enrolling, meta: %s, ip: %s, port: %d, nat type: %s
\n
"
,
self
.
meta
,
self
.
ip
,
self
.
port
,
get_nat_desc
(
self
.
type
));
int
i
,
temp
;
for
(
i
=
0
,
temp
=
MIN_PORT
;
temp
<=
MAX_PORT
;
i
++
,
temp
++
)
{
ports
[
i
]
=
temp
;
}
int
res
=
init
(
punch_server
,
c
);
if
(
res
!=
0
)
{
verbose_log
(
"failed to connect to punch server
\n
"
);
return
res
;
}
c
->
msg_buf
=
c
->
buf
;
c
->
msg_buf
=
c
->
buf
;
c
->
msg_buf
=
encode16
(
c
->
msg_buf
,
Enroll
);
c
->
msg_buf
=
encode16
(
c
->
msg_buf
,
Enroll
);
c
->
msg_buf
=
encode
(
c
->
msg_buf
,
self
.
ip
,
16
);
c
->
msg_buf
=
encode
(
c
->
msg_buf
,
self
.
ip
,
16
);
c
->
msg_buf
=
encode16
(
c
->
msg_buf
,
self
.
port
);
c
->
msg_buf
=
encode16
(
c
->
msg_buf
,
self
.
port
);
c
->
msg_buf
=
encode16
(
c
->
msg_buf
,
self
.
type
);
c
->
msg_buf
=
encode16
(
c
->
msg_buf
,
self
.
type
);
c
->
msg_buf
=
encode8
(
c
->
msg_buf
,
(
uint8_t
)
strlen
(
self
.
meta
));
c
->
msg_buf
=
encode
(
c
->
msg_buf
,
self
.
meta
,
strlen
(
self
.
meta
));
if
(
-
1
==
send_to_punch_server
(
c
))
{
if
(
-
1
==
send_to_punch_server
(
c
))
{
verbose_log
(
"sending to punch server failed
\n
"
);
return
-
1
;
return
-
1
;
}
}
// wait for server reply to get own ID
// wait for server reply to get own ID
uint32_t
peer_id
=
0
;
uint32_t
peer_id
=
0
;
struct
timeval
tv
;
struct
timeval
tv
;
tv
.
tv_sec
=
5
;
tv
.
tv_sec
=
10
;
tv
.
tv_usec
=
0
;
tv
.
tv_usec
=
0
;
setsockopt
(
server_sock
,
SOL_SOCKET
,
SO_RCVTIMEO
,
(
const
char
*
)
&
tv
,
sizeof
(
tv
));
setsockopt
(
c
->
sfd
,
SOL_SOCKET
,
SO_RCVTIMEO
,
(
const
char
*
)
&
tv
,
sizeof
(
tv
));
int
n
=
recv
(
server_sock
,
&
peer_id
,
sizeof
(
uint32_t
),
0
);
int
n
=
recv
(
c
->
sfd
,
&
peer_id
,
sizeof
(
uint32_t
),
0
);
if
(
n
!=
sizeof
(
uint32_t
))
{
if
(
n
!=
sizeof
(
uint32_t
))
{
return
-
1
;
return
-
1
;
}
}
c
->
id
=
ntohl
(
peer_id
);
c
->
id
=
ntohl
(
peer_id
);
verbose_log
(
"enrolled, id: %d
\n
"
,
c
->
id
);
return
0
;
return
0
;
}
}
pthread_t
wait_for_command
(
int
*
server_sock
)
pthread_t
wait_for_command
(
int
*
server_sock
)
{
{
// wait for command from punch server in another thread
// wait for command from punch server in another thread
pthread_t
thread_id
;
pthread_t
thread_id
;
pthread_create
(
&
thread_id
,
NULL
,
server_notify_handler
,
(
void
*
)
server_sock
);
pthread_create
(
&
thread_id
,
NULL
,
server_notify_handler
,
(
void
*
)
server_sock
);
return
thread_id
;
return
thread_id
;
}
}
...
@@ -339,56 +454,75 @@ void on_connected(int sock) {
...
@@ -339,56 +454,75 @@ void on_connected(int sock) {
char
buf
[
MSG_BUF_SIZE
]
=
{
0
};
char
buf
[
MSG_BUF_SIZE
]
=
{
0
};
struct
sockaddr_in
remote_addr
;
struct
sockaddr_in
remote_addr
;
socklen_t
fromlen
=
sizeof
remote_addr
;
socklen_t
fromlen
=
sizeof
remote_addr
;
recvfrom
(
sock
,
buf
,
MSG_BUF_SIZE
,
0
,
(
struct
sockaddr
*
)
&
remote_addr
,
&
fromlen
);
recvfrom
(
sock
,
buf
,
MSG_BUF_SIZE
,
0
,
(
struct
sockaddr
*
)
&
remote_addr
,
printf
(
"recv %s
\n
"
,
buf
);
&
fromlen
);
verbose_log
(
"recv %s
\n
"
,
buf
);
printf
(
"connected with peer from %s:%d
\n
"
,
inet_ntoa
(
remote_addr
.
sin_addr
),
ntohs
(
remote_addr
.
sin_port
));
verbose_log
(
"connected with peer from %s:%d
\n
"
,
inet_ntoa
(
remote_addr
.
sin_addr
),
ntohs
(
remote_addr
.
sin_port
));
// restore the ttl
// restore the ttl
int
ttl
=
64
;
int
ttl
=
64
;
setsockopt
(
sock
,
IPPROTO_IP
,
IP_TTL
,
&
ttl
,
sizeof
(
ttl
));
setsockopt
(
sock
,
IPPROTO_IP
,
IP_TTL
,
&
ttl
,
sizeof
(
ttl
));
sendto
(
sock
,
"hello, peer"
,
strlen
(
"hello, peer"
),
0
,
(
struct
sockaddr
*
)
&
remote_addr
,
sizeof
(
remote_addr
));
sendto
(
sock
,
"hello, peer"
,
strlen
(
"hello, peer"
),
0
,
(
struct
sockaddr
*
)
&
remote_addr
,
sizeof
(
remote_addr
));
}
}
int
connect_to_peer
(
client
*
cli
,
uint32_t
peer_id
)
{
int
real_connect_to_peer
(
client
*
cli
,
struct
peer_info
*
peer
)
{
verbose_log
(
"connecting to id: %d, meta: %s, ip: %s, port %d, nat type: %s
\n
"
,
peer
->
id
,
peer
->
meta
,
peer
->
ip
,
peer
->
port
,
get_nat_desc
(
peer
->
type
));
return
connect_to_symmetric_nat
(
cli
,
*
peer
);
// choose less restricted peer as initiator
/* switch(peer.type) { */
/* case OpenInternet: */
/* // todo */
/* break; */
/* case FullCone: */
/* break; */
/* case RestricNAT: */
/* // todo */
/* break; */
/* case RestricPortNAT: */
/* // todo */
/* break; */
/* case SymmetricNAT: */
/* if (cli->type == SymmetricNAT) { */
/* connect_to_symmetric_nat_from_meta(cli, peer_meta, peer); */
/* } */
/* else { */
/* // todo */
/* } */
/* break; */
/* default: */
/* verbose_log("unknown nat type\n"); */
/* return -1; */
/* // log */
/* } */
/* return 0; */
}
int
connect_to_peer
(
client
*
cli
,
uint32_t
peer_id
)
{
struct
peer_info
peer
;
struct
peer_info
peer
;
int
n
=
get_peer_info
(
cli
,
peer_id
,
&
peer
);
int
n
=
get_peer_info
(
cli
,
peer_id
,
&
peer
);
if
(
n
)
{
if
(
n
)
{
verbose_log
(
"get_peer_info() return %d
\n
"
,
n
);
verbose_log
(
"get_peer_info() return %d
\n
"
,
n
);
printf
(
"failed to get info of remote peer
\n
"
);
verbose_log
(
"failed to get info of remote peer
\n
"
);
return
-
1
;
return
-
1
;
}
}
return
real_connect_to_peer
(
cli
,
&
peer
);
}
printf
(
"peer %d: %s:%d, nat type: %s
\n
"
,
peer_id
,
peer
.
ip
,
peer
.
port
,
get_nat_desc
(
peer
.
type
));
int
connect_to_peer_from_meta
(
client
*
cli
,
char
*
peer_meta
)
{
struct
peer_info
peer
;
// choose less restricted peer as initiator
int
n
=
get_peer_info_from_meta
(
cli
,
peer_meta
,
&
peer
);
switch
(
peer
.
type
)
{
if
(
n
)
{
case
OpenInternet
:
verbose_log
(
"get_peer_info() return %d
\n
"
,
n
);
// todo
verbose_log
(
"failed to get info of remote peer
\n
"
);
break
;
case
FullCone
:
break
;
case
RestricNAT
:
// todo
break
;
case
RestricPortNAT
:
// todo
break
;
case
SymmetricNAT
:
if
(
cli
->
type
==
SymmetricNAT
)
{
connect_to_symmetric_nat
(
cli
,
peer_id
,
peer
);
}
else
{
// todo
}
break
;
default:
printf
(
"unknown nat type
\n
"
);
return
-
1
;
return
-
1
;
// log
}
}
return
real_connect_to_peer
(
cli
,
&
peer
);
return
0
;
}
}
nat_traversal.h
View file @
70c0ff3d
...
@@ -7,32 +7,51 @@ struct client {
...
@@ -7,32 +7,51 @@ struct client {
int
sfd
;
int
sfd
;
uint32_t
id
;
uint32_t
id
;
char
buf
[
128
];
char
buf
[
128
];
//use a stack-based buffer to prevent memory allocation every time
//
use a stack-based buffer to prevent memory allocation every time
char
*
msg_buf
;
char
*
msg_buf
;
nat_type
type
;
nat_type
type
;
char
ext_ip
[
16
];
char
ext_ip
[
16
];
uint16_t
ext_port
;
uint16_t
ext_port
;
// ttl of hole punching packets,
// ttl of hole punching packets,
// it should be greater than the number of hops between host to NAT of own
side
// it should be greater than the number of hops between host to NAT of own
// and less than the number of hops between host to NAT of remote side,
//
side
and less than the number of hops between host to NAT of remote side,
// so that the hole punching packets just die in the way
// so that the hole punching packets just die in the way
int
ttl
;
int
ttl
;
};
};
struct
my_peer_info
{
uint32_t
id
;
char
ip
[
16
];
uint16_t
port
;
uint16_t
type
;
uint8_t
len
;
}
__attribute__
((
packed
));
struct
peer_info
{
struct
peer_info
{
uint32_t
id
;
char
ip
[
16
];
char
ip
[
16
];
uint16_t
port
;
uint16_t
port
;
uint16_t
type
;
uint16_t
type
;
char
*
meta
;
};
};
enum
msg_type
{
enum
msg_type
{
Enroll
=
0x01
,
Enroll
=
0x01
,
GetPeerInfo
=
0x02
,
GetPeerInfo
=
0x02
,
NotifyPeer
=
0x03
,
NotifyPeer
=
0x03
,
};
GetPeerInfoFromMeta
=
0x04
,
NotifyPeerFromMeta
=
0x05
,
};
// public functions
// public functions
int
enroll
(
struct
peer_info
self
,
struct
sockaddr_in
punch_server
,
client
*
c
);
int
enroll
(
struct
peer_info
self
,
struct
sockaddr_in
punch_server
,
client
*
c
);
pthread_t
wait_for_command
(
int
*
server_sock
);
pthread_t
wait_for_command
(
int
*
server_sock
);
int
connect_to_peer
(
client
*
cli
,
uint32_t
peer_id
);
int
connect_to_peer
(
client
*
cli
,
uint32_t
peer_id
);
int
connect_to_peer_from_meta
(
client
*
cli
,
char
*
peer_meta
);
void
on_connected
(
int
sock
);
void
on_connected
(
int
sock
);
int
get_peer_info
(
client
*
cli
,
uint32_t
peer_id
,
struct
peer_info
*
peer
);
int
get_peer_info_from_meta
(
client
*
cli
,
char
*
peer_meta
,
struct
peer_info
*
peer
);
int
init
(
struct
sockaddr_in
punch_server
,
client
*
c
);
void
hexDump
(
char
*
desc
,
void
*
addr
,
int
len
);
int
send_get_peer_info_request
(
client
*
cli
,
struct
peer_info
*
peer
);
nat_type.c
View file @
70c0ff3d
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <netdb.h>
#include <time.h>
#include <unistd.h>
#include "nat_type.h"
#include "nat_type.h"
#define MAX_RETRIES_NUM 3
#define MAX_RETRIES_NUM 3
static
const
char
*
nat_types
[]
=
{
// use public stun servers to detect port allocation rule
"blocked"
,
static
char
*
stun_servers
[]
=
{
"stun.avigora.com"
,
"open internet"
,
"iphone-stun.strato-iphone.de"
,
"full cone"
,
"numb.viagenie.ca"
,
"restricted NAT"
,
"stun.12connect.com"
,
"port-restricted cone"
,
"stun.12voip.com"
,
"symmetric NAT"
,
"stun.1und1.de"
,
"error"
"stun.3clogic.com"
,
};
"stun.3cx.com"
,
"stun.a-mm.tv"
,
char
*
encode16
(
char
*
buf
,
uint16_t
data
)
"stun.aa.net.uk"
,
{
"stun.acrobits.cz"
,
"stun.actionvoip.com"
,
"stun.advfn.com"
,
"stun.aeta-audio.com"
,
"stun.aeta.com"
,
"stun.altar.com.pl"
,
"stun.avigora.com"
,
"stun.avigora.fr"
,
"stun.b2b2c.ca"
,
"stun.bahnhof.net"
,
"stun.barracuda.com"
,
"stun.bluesip.net"
,
"stun.botonakis.com"
,
"stun.budgetsip.com"
,
"stun.cablenet-as.net"
,
"stun.callromania.ro"
,
"stun.callwithus.com"
,
"stun.cheapvoip.com"
,
"stun.ciktel.com"
,
"stun.cloopen.com"
,
"stun.commpeak.com"
,
"stun.comtube.com"
,
"stun.comtube.ru"
,
"stun.cope.es"
,
"stun.counterpath.com"
,
"stun.counterpath.net"
,
"stun.cryptonit.net"
,
"stun.demos.ru"
,
"stun.dus.net"
,
"stun.easycall.pl"
,
"stun.easyvoip.com"
,
"stun.ekiga.net"
,
"stun.epygi.com"
,
"stun.etoilediese.fr"
,
"stun.faktortel.com.au"
,
"stun.freecall.com"
,
"stun.freeswitch.org"
,
"stun.freevoipdeal.com"
,
"stun.gmx.de"
,
"stun.gmx.net"
,
"stun.gradwell.com"
,
"stun.halonet.pl"
,
"stun.hoiio.com"
,
"stun.hosteurope.de"
,
"stun.ideasip.com"
,
"stun.infra.net"
,
"stun.internetcalls.com"
,
"stun.intervoip.com"
,
"stun.ippi.fr"
,
"stun.ipshka.com"
,
"stun.irian.at"
,
"stun.it1.hr"
,
"stun.ivao.aero"
,
"stun.jumblo.com"
,
"stun.justvoip.com"
,
"stun.linphone.org"
,
"stun.liveo.fr"
,
"stun.lowratevoip.com"
,
"stun.lundimatin.fr"
,
"stun.mit.de"
,
"stun.miwifi.com"
,
"stun.modulus.gr"
,
"stun.myvoiptraffic.com"
,
"stun.mywatson.it"
,
"stun.netappel.com"
,
"stun.nfon.net"
,
"stun.noc.ams-ix.net"
,
"stun.node4.co.uk"
,
"stun.nonoh.net"
,
"stun.nottingham.ac.uk"
,
"stun.nova.is"
,
"stun.ooma.com"
,
"stun.ozekiphone.com"
,
"stun.personal-voip.de"
,
"stun.phone.com"
,
"stun.pjsip.org"
,
"stun.poivy.com"
,
"stun.powervoip.com"
,
"stun.ppdi.com"
,
"stun.rackco.com"
,
"stun.rockenstein.de"
,
"stun.rolmail.net"
,
"stun.rynga.com"
,
"stun.schlund.de"
,
"stun.services.mozilla.com"
,
"stun.sigmavoip.com"
,
"stun.sip.us"
,
"stun.sipdiscount.com"
,
"stun.sipgate.net"
,
"stun.siplogin.de"
,
"stun.sipnet.net"
,
"stun.sipnet.ru"
,
"stun.siportal.it"
,
"stun.sippeer.dk"
,
"stun.siptraffic.com"
,
"stun.sma.de"
,
"stun.smartvoip.com"
,
"stun.smsdiscount.com"
,
"stun.snafu.de"
,
"stun.solcon.nl"
,
"stun.solnet.ch"
,
"stun.sonetel.com"
,
"stun.sonetel.net"
,
"stun.speedy.com.ar"
,
"stun.srce.hr"
,
"stun.ssl7.net"
,
"stun.stunprotocol.org"
,
"stun.t-online.de"
,
"stun.tel.lu"
,
"stun.telbo.com"
,
"stun.tng.de"
,
"stun.twt.it"
,
"stun.uls.co.za"
,
"stun.usfamily.net"
,
"stun.vipgroup.net"
,
"stun.viva.gr"
,
"stun.vivox.com"
,
"stun.vo.lu"
,
"stun.voicetrading.com"
,
"stun.voip.aebc.com"
,
"stun.voip.blackberry.com"
,
"stun.voip.eutelia.it"
,
"stun.voiparound.com"
,
"stun.voipblast.com"
,
"stun.voipbuster.com"
,
"stun.voipbusterpro.com"
,
"stun.voipcheap.co.uk"
,
"stun.voipcheap.com"
,
"stun.voipfibre.com"
,
"stun.voipgain.com"
,
"stun.voipgate.com"
,
"stun.voipinfocenter.com"
,
"stun.voipplanet.nl"
,
"stun.voippro.com"
,
"stun.voipraider.com"
,
"stun.voipstunt.com"
,
"stun.voipwise.com"
,
"stun.voipzoom.com"
,
"stun.voxgratia.org"
,
"stun.voxox.com"
,
"stun.voztele.com"
,
"stun.webcalldirect.com"
,
"stun.xtratelecom.es"
,
"stun.zadarma.com"
,
"stun.zoiper.com"
,
"stun1.faktortel.com.au"
};
static
const
char
*
nat_types
[]
=
{
"blocked"
,
"open internet"
,
"full cone"
,
"restricted NAT"
,
"port-restricted cone"
,
"symmetric NAT"
,
"error"
};
char
*
encode8
(
char
*
buf
,
size_t
data
)
{
/* uint8_t ndata = htons(data); */
memcpy
(
buf
,
(
void
*
)(
&
data
),
sizeof
(
uint8_t
));
return
buf
+
sizeof
(
uint8_t
);
}
char
*
encode16
(
char
*
buf
,
uint16_t
data
)
{
uint16_t
ndata
=
htons
(
data
);
uint16_t
ndata
=
htons
(
data
);
memcpy
(
buf
,
(
void
*
)(
&
ndata
),
sizeof
(
uint16_t
));
memcpy
(
buf
,
(
void
*
)(
&
ndata
),
sizeof
(
uint16_t
));
return
buf
+
sizeof
(
uint16_t
);
return
buf
+
sizeof
(
uint16_t
);
}
}
char
*
encode32
(
char
*
buf
,
uint32_t
data
)
char
*
encode32
(
char
*
buf
,
uint32_t
data
)
{
{
uint32_t
ndata
=
htonl
(
data
);
uint32_t
ndata
=
htonl
(
data
);
memcpy
(
buf
,
(
void
*
)(
&
ndata
),
sizeof
(
uint32_t
));
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
)
char
*
encodeAtrUInt32
(
char
*
ptr
,
uint16_t
type
,
uint32_t
value
)
{
{
ptr
=
encode16
(
ptr
,
type
);
ptr
=
encode16
(
ptr
,
type
);
ptr
=
encode16
(
ptr
,
4
);
ptr
=
encode16
(
ptr
,
4
);
ptr
=
encode32
(
ptr
,
value
);
ptr
=
encode32
(
ptr
,
value
);
...
@@ -47,15 +204,22 @@ char* encodeAtrUInt32(char* ptr, uint16_t type, uint32_t value)
...
@@ -47,15 +204,22 @@ char* encodeAtrUInt32(char* ptr, uint16_t type, uint32_t value)
return
ptr
;
return
ptr
;
}
}
char
*
encode
(
char
*
buf
,
const
char
*
data
,
unsigned
int
length
)
char
*
encode
(
char
*
buf
,
const
char
*
data
,
unsigned
int
length
)
{
{
memcpy
(
buf
,
data
,
length
);
memcpy
(
buf
,
data
,
length
);
return
buf
+
length
;
return
buf
+
length
;
}
}
static
int
stun_parse_atr_addr
(
char
*
body
,
unsigned
int
hdrLen
,
StunAtrAddress
*
result
)
char
*
encodeWithLen
(
char
*
buf
,
const
char
*
data
)
{
{
size_t
s
=
sizeof
(
*
data
);
if
(
hdrLen
!=
8
/* ipv4 size */
&&
hdrLen
!=
20
/* ipv6 size */
)
{
memcpy
(
buf
,
&
s
,
sizeof
(
s
));
buf
=
buf
+
sizeof
(
s
);
memcpy
(
buf
,
data
,
s
);
return
buf
+
s
;
}
static
int
stun_parse_atr_addr
(
char
*
body
,
unsigned
int
hdrLen
,
StunAtrAddress
*
result
)
{
if
(
hdrLen
!=
8
/* ipv4 size */
&&
hdrLen
!=
20
/* ipv6 size */
)
{
return
-
1
;
return
-
1
;
}
}
body
++
;
// Skip pad
body
++
;
// Skip pad
...
@@ -63,12 +227,13 @@ static int stun_parse_atr_addr( char* body, unsigned int hdrLen, StunAtrAddress*
...
@@ -63,12 +227,13 @@ static int stun_parse_atr_addr( char* body, unsigned int hdrLen, StunAtrAddress*
uint16_t
nport
;
uint16_t
nport
;
memcpy
(
&
nport
,
body
,
2
);
memcpy
(
&
nport
,
body
,
2
);
body
+=
2
;
body
+=
2
;
result
->
port
=
ntohs
(
nport
);
result
->
port
=
ntohs
(
nport
);
if
(
result
->
family
==
IPv4Family
)
{
if
(
result
->
family
==
IPv4Family
)
{
uint32_t
naddr
;
uint32_t
naddr
;
memcpy
(
&
naddr
,
body
,
sizeof
(
uint32_t
));
body
+=
sizeof
(
uint32_t
);
memcpy
(
&
naddr
,
body
,
sizeof
(
uint32_t
));
body
+=
sizeof
(
uint32_t
);
result
->
addr
.
ipv4
=
ntohl
(
naddr
);
result
->
addr
.
ipv4
=
ntohl
(
naddr
);
// Note: addr.ipv4 is stored in host byte order
// Note: addr.ipv4 is stored in host byte order
return
0
;
return
0
;
...
@@ -79,9 +244,9 @@ static int stun_parse_atr_addr( char* body, unsigned int hdrLen, StunAtrAddress*
...
@@ -79,9 +244,9 @@ static int stun_parse_atr_addr( char* body, unsigned int hdrLen, StunAtrAddress*
return
-
1
;
return
-
1
;
}
}
static
void
gen_random_string
(
char
*
s
,
const
int
len
)
{
void
gen_random_string
(
char
*
s
,
const
int
len
)
{
s
tatic
const
char
alphanum
[]
=
s
rand
(
time
(
NULL
));
"0123456789"
const
char
alphanum
[]
=
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
;
"abcdefghijklmnopqrstuvwxyz"
;
...
@@ -89,21 +254,24 @@ static void gen_random_string(char *s, const int len) {
...
@@ -89,21 +254,24 @@ static void gen_random_string(char *s, const int len) {
for
(;
i
<
len
;
++
i
)
{
for
(;
i
<
len
;
++
i
)
{
s
[
i
]
=
alphanum
[
rand
()
%
(
sizeof
(
alphanum
)
-
1
)];
s
[
i
]
=
alphanum
[
rand
()
%
(
sizeof
(
alphanum
)
-
1
)];
}
}
s
[
len
]
=
'\0'
;
}
}
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
)
{
static
int
send_bind_request
(
int
sock
,
const
char
*
remote_host
,
char
*
buf
=
malloc
(
MAX_STUN_MESSAGE_LENGTH
);
uint16_t
remote_port
,
uint32_t
change_ip
,
char
*
ptr
=
buf
;
uint32_t
change_port
,
StunAtrAddress
*
addr_array
)
{
char
*
buf
=
malloc
(
MAX_STUN_MESSAGE_LENGTH
);
char
*
ptr
=
buf
;
StunHeader
h
;
StunHeader
h
;
h
.
msgType
=
BindRequest
;
h
.
msgType
=
BindRequest
;
gen_random_string
((
char
*
)
&
h
.
magicCookieAndTid
,
16
);
gen_random_string
((
char
*
)
&
h
.
magicCookieAndTid
,
16
);
ptr
=
encode16
(
ptr
,
h
.
msgType
);
ptr
=
encode16
(
ptr
,
h
.
msgType
);
char
*
lengthp
=
ptr
;
char
*
lengthp
=
ptr
;
ptr
=
encode16
(
ptr
,
0
);
ptr
=
encode16
(
ptr
,
0
);
ptr
=
encode
(
ptr
,
(
const
char
*
)
&
h
.
id
,
sizeof
(
h
.
id
));
ptr
=
encode
(
ptr
,
(
const
char
*
)
&
h
.
id
,
sizeof
(
h
.
id
));
if
(
change_ip
||
change_port
)
{
if
(
change_ip
||
change_port
)
{
ptr
=
encodeAtrUInt32
(
ptr
,
ChangeRequest
,
change_ip
|
change_port
);
ptr
=
encodeAtrUInt32
(
ptr
,
ChangeRequest
,
change_ip
|
change_port
);
...
@@ -122,12 +290,14 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
...
@@ -122,12 +290,14 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
struct
sockaddr_in
remote_addr
;
struct
sockaddr_in
remote_addr
;
remote_addr
.
sin_family
=
AF_INET
;
remote_addr
.
sin_family
=
AF_INET
;
memcpy
(
&
remote_addr
.
sin_addr
.
s_addr
,
server
->
h_addr_list
[
0
],
server
->
h_length
);
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_port
=
htons
(
remote_port
);
int
retries
;
int
retries
;
for
(
retries
=
0
;
retries
<
MAX_RETRIES_NUM
;
retries
++
)
{
for
(
retries
=
0
;
retries
<
MAX_RETRIES_NUM
;
retries
++
)
{
if
(
-
1
==
sendto
(
sock
,
buf
,
ptr
-
buf
,
0
,
(
struct
sockaddr
*
)
&
remote_addr
,
sizeof
(
remote_addr
)))
{
if
(
-
1
==
sendto
(
sock
,
buf
,
ptr
-
buf
,
0
,
(
struct
sockaddr
*
)
&
remote_addr
,
sizeof
(
remote_addr
)))
{
// sendto() barely failed
// sendto() barely failed
free
(
buf
);
free
(
buf
);
...
@@ -139,15 +309,16 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
...
@@ -139,15 +309,16 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
struct
timeval
tv
;
struct
timeval
tv
;
tv
.
tv_sec
=
3
;
tv
.
tv_sec
=
3
;
tv
.
tv_usec
=
0
;
tv
.
tv_usec
=
0
;
setsockopt
(
sock
,
SOL_SOCKET
,
SO_RCVTIMEO
,
(
const
char
*
)
&
tv
,
sizeof
(
tv
));
setsockopt
(
sock
,
SOL_SOCKET
,
SO_RCVTIMEO
,
(
const
char
*
)
&
tv
,
sizeof
(
tv
));
if
(
recvfrom
(
sock
,
buf
,
512
,
0
,
(
struct
sockaddr
*
)
&
remote_addr
,
&
fromlen
)
<=
0
)
{
if
(
recvfrom
(
sock
,
buf
,
512
,
0
,
(
struct
sockaddr
*
)
&
remote_addr
,
&
fromlen
)
<=
0
)
{
if
(
errno
!=
EAGAIN
||
errno
!=
EWOULDBLOCK
)
{
if
(
errno
!=
EAGAIN
||
errno
!=
EWOULDBLOCK
)
{
free
(
buf
);
free
(
buf
);
return
-
1
;
return
-
1
;
}
}
//timout, retry
//
timout, retry
}
else
{
}
else
{
// got response
// got response
break
;
break
;
...
@@ -163,23 +334,24 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
...
@@ -163,23 +334,24 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
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
);
char
*
body
=
buf
+
sizeof
(
StunHeader
);
uint16_t
size
=
ntohs
(
reply_header
.
msgLength
);
uint16_t
size
=
ntohs
(
reply_header
.
msgLength
);
StunAtrHdr
*
attr
;
StunAtrHdr
*
attr
;
unsigned
int
attrLen
;
unsigned
int
attrLen
;
unsigned
int
attrLenPad
;
unsigned
int
attrLenPad
;
int
atrType
;
int
atrType
;
while
(
size
>
0
)
{
while
(
size
>
0
)
{
attr
=
(
StunAtrHdr
*
)(
body
);
attr
=
(
StunAtrHdr
*
)(
body
);
attrLen
=
ntohs
(
attr
->
length
);
attrLen
=
ntohs
(
attr
->
length
);
// attrLen may not be on 4 byte boundary, in which case we need to pad to 4 bytes when advancing to next attribute
// attrLen may not be on 4 byte boundary, in which case we need to pad to
// 4 bytes when advancing to next attribute
attrLenPad
=
attrLen
%
4
==
0
?
0
:
4
-
(
attrLen
%
4
);
attrLenPad
=
attrLen
%
4
==
0
?
0
:
4
-
(
attrLen
%
4
);
atrType
=
ntohs
(
attr
->
type
);
atrType
=
ntohs
(
attr
->
type
);
if
(
attrLen
+
attrLenPad
+
4
>
size
)
{
if
(
attrLen
+
attrLenPad
+
4
>
size
)
{
free
(
buf
);
free
(
buf
);
return
-
1
;
return
-
1
;
...
@@ -197,7 +369,7 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
...
@@ -197,7 +369,7 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
}
}
break
;
break
;
case
ChangedAddress
:
case
ChangedAddress
:
if
(
stun_parse_atr_addr
(
body
,
attrLen
,
addr_array
+
1
))
{
if
(
stun_parse_atr_addr
(
body
,
attrLen
,
addr_array
+
1
))
{
free
(
buf
);
free
(
buf
);
return
-
1
;
return
-
1
;
...
@@ -217,11 +389,17 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
...
@@ -217,11 +389,17 @@ static int send_bind_request(int sock, const char* remote_host, uint16_t remote_
return
0
;
return
0
;
}
}
const
char
*
get_nat_desc
(
nat_type
type
)
{
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_ip
,
uint16_t
local_port
,
char
*
ext_ip
,
uint16_t
*
ext_port
)
{
nat_type
detect_nat_type
(
char
*
stun_host
,
uint16_t
stun_port
,
const
char
*
local_ip
,
uint16_t
local_port
,
char
*
ext_ip
,
uint16_t
*
ext_port
)
{
if
(
stun_host
==
NULL
)
{
srand
(
time
(
NULL
));
int
i
=
rand
()
%
(
sizeof
(
stun_servers
)
/
sizeof
(
stun_servers
[
0
])
-
1
);
verbose_log
(
"Using the %dth stun server %s
\n
"
,
i
,
stun_servers
[
i
]);
stun_host
=
stun_servers
[
i
];
}
uint32_t
mapped_ip
=
0
;
uint32_t
mapped_ip
=
0
;
uint16_t
mapped_port
=
0
;
uint16_t
mapped_port
=
0
;
int
s
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
int
s
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
...
@@ -232,7 +410,8 @@ nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char*
...
@@ -232,7 +410,8 @@ nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char*
nat_type
nat_type
;
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
;
struct
sockaddr_in
local_addr
;
local_addr
.
sin_family
=
AF_INET
;
local_addr
.
sin_family
=
AF_INET
;
...
@@ -281,9 +460,10 @@ nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char*
...
@@ -281,9 +460,10 @@ nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char*
goto
cleanup_sock
;
goto
cleanup_sock
;
}
else
{
}
else
{
if
(
changed_ip
!=
0
&&
changed_port
!=
0
)
{
if
(
changed_ip
!=
0
&&
changed_port
!=
0
)
{
if
(
send_bind_request
(
s
,
stun_host
,
stun_port
,
ChangeIpFlag
,
ChangePortFlag
,
bind_result
))
{
if
(
send_bind_request
(
s
,
stun_host
,
stun_port
,
ChangeIpFlag
,
ChangePortFlag
,
bind_result
))
{
struct
in_addr
addr
=
{
htonl
(
changed_ip
)};
struct
in_addr
addr
=
{
htonl
(
changed_ip
)};
char
*
alt_host
=
inet_ntoa
(
addr
);
char
*
alt_host
=
inet_ntoa
(
addr
);
memset
(
bind_result
,
0
,
sizeof
(
StunAtrAddress
)
*
2
);
memset
(
bind_result
,
0
,
sizeof
(
StunAtrAddress
)
*
2
);
...
@@ -293,20 +473,21 @@ nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char*
...
@@ -293,20 +473,21 @@ nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char*
goto
cleanup_sock
;
goto
cleanup_sock
;
}
}
if
(
mapped_ip
!=
bind_result
[
0
].
addr
.
ipv4
||
mapped_port
!=
bind_result
[
0
].
port
)
{
if
(
mapped_ip
!=
bind_result
[
0
].
addr
.
ipv4
||
mapped_port
!=
bind_result
[
0
].
port
)
{
nat_type
=
SymmetricNAT
;
nat_type
=
SymmetricNAT
;
goto
cleanup_sock
;
goto
cleanup_sock
;
}
}
if
(
send_bind_request
(
s
,
alt_host
,
changed_port
,
0
,
ChangePortFlag
,
bind_result
))
{
if
(
send_bind_request
(
s
,
alt_host
,
changed_port
,
0
,
ChangePortFlag
,
bind_result
))
{
nat_type
=
RestricPortNAT
;
nat_type
=
RestricPortNAT
;
goto
cleanup_sock
;
goto
cleanup_sock
;
}
}
nat_type
=
RestricNAT
;
nat_type
=
RestricNAT
;
goto
cleanup_sock
;
goto
cleanup_sock
;
}
}
else
{
else
{
nat_type
=
FullCone
;
nat_type
=
FullCone
;
goto
cleanup_sock
;
goto
cleanup_sock
;
}
}
...
...
nat_type.h
View file @
70c0ff3d
...
@@ -73,6 +73,7 @@ typedef struct
...
@@ -73,6 +73,7 @@ typedef struct
}
addr
;
}
addr
;
}
StunAtrAddress
;
}
StunAtrAddress
;
char
*
encode8
(
char
*
buf
,
size_t
data
);
char
*
encode16
(
char
*
buf
,
uint16_t
data
);
char
*
encode16
(
char
*
buf
,
uint16_t
data
);
char
*
encode32
(
char
*
buf
,
uint32_t
data
);
char
*
encode32
(
char
*
buf
,
uint32_t
data
);
char
*
encode
(
char
*
buf
,
const
char
*
data
,
unsigned
int
length
);
char
*
encode
(
char
*
buf
,
const
char
*
data
,
unsigned
int
length
);
...
@@ -83,6 +84,7 @@ extern int verbose;
...
@@ -83,6 +84,7 @@ extern int verbose;
printf(format, ##__VA_ARGS__); \
printf(format, ##__VA_ARGS__); \
} while(0)
} while(0)
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
(
char
*
stun_host
,
uint16_t
stun_port
,
const
char
*
local_host
,
uint16_t
local_port
,
char
*
ext_ip
,
uint16_t
*
ext_port
);
const
char
*
get_nat_desc
(
nat_type
type
);
const
char
*
get_nat_desc
(
nat_type
type
);
void
gen_random_string
(
char
*
s
,
const
int
len
);
public-stun-list.txt
0 → 100644
View file @
70c0ff3d
23.21.150.121
iphone-stun.strato-iphone.de
numb.viagenie.ca
s1.taraba.net
s2.taraba.net
stun.12connect.com
stun.12voip.com
stun.1und1.de
stun.2talk.co.nz
stun.2talk.com
stun.3clogic.com
stun.3cx.com
stun.a-mm.tv
stun.aa.net.uk
stun.acrobits.cz
stun.actionvoip.com
stun.advfn.com
stun.aeta-audio.com
stun.aeta.com
stun.alltel.com.au
stun.altar.com.pl
stun.annatel.net
stun.antisip.com
stun.arbuz.ru
stun.avigora.com
stun.avigora.fr
stun.awa-shima.com
stun.awt.be
stun.b2b2c.ca
stun.bahnhof.net
stun.barracuda.com
stun.bluesip.net
stun.bmwgs.cz
stun.botonakis.com
stun.budgetphone.nl
stun.budgetsip.com
stun.cablenet-as.net
stun.callromania.ro
stun.callwithus.com
stun.cbsys.net
stun.chathelp.ru
stun.cheapvoip.com
stun.ciktel.com
stun.cloopen.com
stun.colouredlines.com.au
stun.comfi.com
stun.commpeak.com
stun.comtube.com
stun.comtube.ru
stun.cope.es
stun.counterpath.com
stun.counterpath.net
stun.cryptonit.net
stun.darioflaccovio.it
stun.datamanagement.it
stun.dcalling.de
stun.decanet.fr
stun.demos.ru
stun.develz.org
stun.dingaling.ca
stun.doublerobotics.com
stun.drogon.net
stun.duocom.es
stun.dus.net
stun.e-fon.ch
stun.easybell.de
stun.easycall.pl
stun.easyvoip.com
stun.efficace-factory.com
stun.einsundeins.com
stun.einsundeins.de
stun.ekiga.net
stun.epygi.com
stun.etoilediese.fr
stun.eyeball.com
stun.faktortel.com.au
stun.freecall.com
stun.freeswitch.org
stun.freevoipdeal.com
stun.fuzemeeting.com
stun.gmx.de
stun.gmx.net
stun.gradwell.com
stun.halonet.pl
stun.hellonanu.com
stun.hoiio.com
stun.hosteurope.de
stun.ideasip.com
stun.imesh.com
stun.infra.net
stun.internetcalls.com
stun.intervoip.com
stun.ipcomms.net
stun.ipfire.org
stun.ippi.fr
stun.ipshka.com
stun.iptel.org
stun.irian.at
stun.it1.hr
stun.ivao.aero
stun.jappix.com
stun.jumblo.com
stun.justvoip.com
stun.kanet.ru
stun.kiwilink.co.nz
stun.kundenserver.de
stun.linea7.net
stun.linphone.org
stun.liveo.fr
stun.lowratevoip.com
stun.lugosoft.com
stun.lundimatin.fr
stun.magnet.ie
stun.manle.com
stun.mgn.ru
stun.mit.de
stun.mitake.com.tw
stun.miwifi.com
stun.modulus.gr
stun.mozcom.com
stun.myvoiptraffic.com
stun.mywatson.it
stun.nas.net
stun.neotel.co.za
stun.netappel.com
stun.netappel.fr
stun.netgsm.com.tr
stun.nfon.net
stun.noblogs.org
stun.noc.ams-ix.net
stun.node4.co.uk
stun.nonoh.net
stun.nottingham.ac.uk
stun.nova.is
stun.nventure.com
stun.on.net.mk
stun.ooma.com
stun.ooonet.ru
stun.oriontelekom.rs
stun.outland-net.de
stun.ozekiphone.com
stun.patlive.com
stun.personal-voip.de
stun.petcube.com
stun.phone.com
stun.phoneserve.com
stun.pjsip.org
stun.poivy.com
stun.powerpbx.org
stun.powervoip.com
stun.ppdi.com
stun.prizee.com
stun.qq.com
stun.qvod.com
stun.rackco.com
stun.rapidnet.de
stun.rb-net.com
stun.refint.net
stun.remote-learner.net
stun.rixtelecom.se
stun.rockenstein.de
stun.rolmail.net
stun.rounds.com
stun.rynga.com
stun.samsungsmartcam.com
stun.schlund.de
stun.services.mozilla.com
stun.sigmavoip.com
stun.sip.us
stun.sipdiscount.com
stun.sipgate.net
stun.siplogin.de
stun.sipnet.net
stun.sipnet.ru
stun.siportal.it
stun.sippeer.dk
stun.siptraffic.com
stun.skylink.ru
stun.sma.de
stun.smartvoip.com
stun.smsdiscount.com
stun.snafu.de
stun.softjoys.com
stun.solcon.nl
stun.solnet.ch
stun.sonetel.com
stun.sonetel.net
stun.sovtest.ru
stun.speedy.com.ar
stun.spokn.com
stun.srce.hr
stun.ssl7.net
stun.stunprotocol.org
stun.symform.com
stun.symplicity.com
stun.sysadminman.net
stun.t-online.de
stun.tagan.ru
stun.tatneft.ru
stun.teachercreated.com
stun.tel.lu
stun.telbo.com
stun.telefacil.com
stun.tis-dialog.ru
stun.tng.de
stun.twt.it
stun.u-blox.com
stun.ucallweconn.net
stun.ucsb.edu
stun.ucw.cz
stun.uls.co.za
stun.unseen.is
stun.usfamily.net
stun.veoh.com
stun.vidyo.com
stun.vipgroup.net
stun.virtual-call.com
stun.viva.gr
stun.vivox.com
stun.vline.com
stun.vo.lu
stun.vodafone.ro
stun.voicetrading.com
stun.voip.aebc.com
stun.voip.blackberry.com
stun.voip.eutelia.it
stun.voiparound.com
stun.voipblast.com
stun.voipbuster.com
stun.voipbusterpro.com
stun.voipcheap.co.uk
stun.voipcheap.com
stun.voipfibre.com
stun.voipgain.com
stun.voipgate.com
stun.voipinfocenter.com
stun.voipplanet.nl
stun.voippro.com
stun.voipraider.com
stun.voipstunt.com
stun.voipwise.com
stun.voipzoom.com
stun.vopium.com
stun.voxgratia.org
stun.voxox.com
stun.voys.nl
stun.voztele.com
stun.vyke.com
stun.webcalldirect.com
stun.whoi.edu
stun.wifirst.net
stun.wwdl.net
stun.xs4all.nl
stun.xtratelecom.es
stun.yesss.at
stun.zadarma.com
stun.zadv.com
stun.zoiper.com
stun1.faktortel.com.au
stun1.voiceeclipse.net
stunserver.org
punch_server.go
View file @
70c0ff3d
package
main
package
main
import
(
import
(
"bytes"
"encoding/binary"
"encoding/binary"
"fmt"
"errors"
"io"
"math/rand"
"net"
"net"
"os"
"sync"
"sync"
"time"
log
"github.com/sirupsen/logrus"
)
)
type
nat_info
struct
{
type
PeerInfo
struct
{
Ip
[
16
]
byte
IP
[
16
]
byte
Port
uint16
NatType
uint16
Meta
string
ID
uint32
}
type
natInfo
struct
{
IP
[
16
]
byte
Port
uint16
Port
uint16
Nat
_t
ype
uint16
Nat
T
ype
uint16
}
}
const
(
const
(
Enroll
=
1
_
=
iota
GetPeerInfo
=
2
Enroll
NotifyPeer
=
3
GetPeerInfo
NotifyPeer
GetPeerInfoFromMeta
NotifyPeerFromMeta
PeerOffline
=
1
PeerError
=
2
ListeningPort
=
":9988"
)
)
var
seq
uint32
=
1
var
(
var
peers
map
[
uint32
]
nat_info
seq
uint32
=
1
var
peers_conn
map
[
uint32
]
net
.
Conn
peers
map
[
uint32
]
PeerInfo
var
m
sync
.
Mutex
peersFromMeta
map
[
string
]
PeerInfo
peerConn
map
[
uint32
]
net
.
Conn
peerConnFromMeta
map
[
string
]
net
.
Conn
mutex
sync
.
RWMutex
letterRunes
=
[]
rune
(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
)
ErrPeerNotFound
=
errors
.
New
(
"Peer not found"
)
ErrConnNotFound
=
errors
.
New
(
"Connection not found, peer maybe is now offline"
)
)
func
main
()
{
func
init
()
{
peers
=
make
(
map
[
uint32
]
nat_info
)
peers
=
make
(
map
[
uint32
]
PeerInfo
)
peers_conn
=
make
(
map
[
uint32
]
net
.
Conn
)
peersFromMeta
=
make
(
map
[
string
]
PeerInfo
)
peerConn
=
make
(
map
[
uint32
]
net
.
Conn
)
peerConnFromMeta
=
make
(
map
[
string
]
net
.
Conn
)
rand
.
Seed
(
time
.
Now
()
.
UnixNano
())
l
,
_
:=
net
.
Listen
(
"tcp"
,
":9988"
)
log
.
SetOutput
(
os
.
Stdout
)
log
.
SetLevel
(
log
.
DebugLevel
)
}
func
main
()
{
l
,
err
:=
net
.
Listen
(
"tcp"
,
ListeningPort
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
})
.
Fatal
(
"Unable to start server"
)
}
defer
l
.
Close
()
defer
l
.
Close
()
go
dumpPeers
()
for
{
for
{
conn
,
err
:=
l
.
Accept
()
conn
,
err
:=
l
.
Accept
()
if
err
!=
nil
{
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
})
.
Error
(
"Accepting connection failed"
)
continue
continue
}
}
log
.
Info
(
"New connection received"
)
go
handleConn
(
conn
)
go
handleConn
(
conn
)
}
}
}
}
func
dumpPeers
()
{
for
{
time
.
Sleep
(
10
*
time
.
Second
)
mutex
.
RLock
()
for
k
,
v
:=
range
peers
{
log
.
WithFields
(
log
.
Fields
{
"Key"
:
k
,
"ID"
:
v
.
ID
,
"Meta"
:
v
.
Meta
,
"IP"
:
string
(
v
.
IP
[
:
]),
"Port"
:
v
.
Port
,
"NatType"
:
v
.
NatType
,
})
.
Debug
(
"peer info"
)
}
mutex
.
RUnlock
()
}
}
func
RandStringRunes
(
n
int
)
string
{
b
:=
make
([]
rune
,
n
)
for
i
:=
range
b
{
b
[
i
]
=
letterRunes
[
rand
.
Intn
(
len
(
letterRunes
))]
}
return
string
(
b
)
}
func
readMeta
(
c
io
.
Reader
)
(
meta
string
,
err
error
)
{
var
metaSize
uint8
err
=
binary
.
Read
(
c
,
binary
.
BigEndian
,
&
metaSize
)
if
err
!=
nil
||
metaSize
==
0
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"metaSize"
:
metaSize
,
})
.
Info
(
"reading meta failed"
)
return
}
data
:=
make
([]
byte
,
metaSize
)
if
_
,
err
=
c
.
Read
(
data
);
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
})
.
Info
(
"reading meta failed"
)
return
}
meta
=
string
(
data
)
return
}
func
writeMeta
(
c
io
.
Writer
,
meta
string
)
(
err
error
)
{
err
=
binary
.
Write
(
c
,
binary
.
BigEndian
,
uint8
(
len
(
meta
)))
if
err
!=
nil
{
return
}
return
binary
.
Write
(
c
,
binary
.
BigEndian
,
[]
byte
(
meta
))
}
func
readPeerInfo
(
r
io
.
Reader
)
(
p
PeerInfo
,
err
error
)
{
var
IP
[
16
]
byte
var
Port
uint16
var
NatType
uint16
if
err
=
binary
.
Read
(
r
,
binary
.
BigEndian
,
&
IP
);
err
!=
nil
{
return
}
if
err
=
binary
.
Read
(
r
,
binary
.
BigEndian
,
&
Port
);
err
!=
nil
{
return
}
if
err
=
binary
.
Read
(
r
,
binary
.
BigEndian
,
&
NatType
);
err
!=
nil
{
return
}
p
=
PeerInfo
{
IP
:
IP
,
Port
:
Port
,
NatType
:
NatType
,
}
meta
,
err
:=
readMeta
(
r
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
})
.
Warn
(
"reading meta failed"
)
meta
=
RandStringRunes
(
18
)
}
p
.
Meta
=
meta
log
.
WithFields
(
log
.
Fields
{
"meta"
:
meta
,
})
.
Info
(
"reading meta succeeded"
)
return
}
func
writePeerInfo
(
w
io
.
Writer
,
p
PeerInfo
)
(
err
error
)
{
p1
:=
natInfo
{
IP
:
p
.
IP
,
Port
:
p
.
Port
,
NatType
:
p
.
NatType
,
}
var
buf
bytes
.
Buffer
if
err
=
binary
.
Write
(
&
buf
,
binary
.
BigEndian
,
p
.
ID
);
err
!=
nil
{
return
}
if
err
=
binary
.
Write
(
&
buf
,
binary
.
BigEndian
,
p1
);
err
!=
nil
{
return
}
if
err
=
writeMeta
(
&
buf
,
p
.
Meta
);
err
!=
nil
{
return
}
return
binary
.
Write
(
w
,
binary
.
BigEndian
,
(
&
buf
)
.
Bytes
())
}
func
getPeerInfo
(
p
PeerInfo
)
(
p1
PeerInfo
,
err
error
)
{
var
ok
bool
mutex
.
RLock
()
defer
mutex
.
RUnlock
()
if
p
.
ID
!=
0
{
if
p1
,
ok
=
peers
[
p
.
ID
];
ok
{
return
}
}
if
p
.
Meta
!=
""
{
if
p1
,
ok
=
peersFromMeta
[
p
.
Meta
];
ok
{
return
}
}
err
=
ErrPeerNotFound
return
}
func
getConn
(
p
PeerInfo
)
(
c
net
.
Conn
,
err
error
)
{
var
ok
bool
mutex
.
RLock
()
defer
mutex
.
RUnlock
()
if
p
.
ID
!=
0
{
if
c
,
ok
=
peerConn
[
p
.
ID
];
ok
{
return
}
}
if
p
.
Meta
!=
""
{
if
c
,
ok
=
peerConnFromMeta
[
p
.
Meta
];
ok
{
return
}
}
err
=
ErrConnNotFound
return
}
// 2 bytes for message type
// 2 bytes for message type
func
handleConn
(
c
net
.
Conn
)
{
func
handleConn
(
c
net
.
Conn
)
{
defer
c
.
Close
()
defer
c
.
Close
()
var
peerID
uint32
=
0
log
.
Info
(
"new connection received!"
)
var
myInfo
PeerInfo
for
{
for
{
// read message type first
var
myBuf
bytes
.
Buffer
w
:=
io
.
MultiWriter
(
&
myBuf
,
c
)
data
:=
make
([]
byte
,
2
)
data
:=
make
([]
byte
,
2
)
_
,
err
:=
c
.
Read
(
data
)
_
,
err
:=
c
.
Read
(
data
)
log
.
WithFields
(
log
.
Fields
{
"header"
:
data
,
})
.
Info
(
"new received header"
)
if
err
!=
nil
{
if
err
!=
nil
{
m
.
Lock
()
mutex
.
Lock
()
fmt
.
Printf
(
"error: %v, peer %d disconnected
\n
"
,
err
,
peerID
)
delete
(
peers
,
myInfo
.
ID
)
delete
(
peers
,
peerID
)
delete
(
peerConn
,
myInfo
.
ID
)
delete
(
peers_conn
,
peerID
)
delete
(
peersFromMeta
,
myInfo
.
Meta
)
m
.
Unlock
()
delete
(
peerConnFromMeta
,
myInfo
.
Meta
)
mutex
.
Unlock
()
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"myID"
:
myInfo
.
ID
,
})
.
Info
(
"peer left"
)
return
return
}
}
t
:=
binary
.
BigEndian
.
Uint16
(
data
[
:
])
switch
binary
.
BigEndian
.
Uint16
(
data
[
:
])
{
switch
t
{
case
Enroll
:
case
Enroll
:
var
peer
nat_info
var
err
error
err
=
binary
.
Read
(
c
,
binary
.
BigEndian
,
&
peer
)
myInfo
,
err
=
readPeerInfo
(
c
)
if
err
!=
nil
{
if
err
!=
nil
{
continue
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
})
.
Warn
(
"Reading meta failed"
)
break
}
}
mutex
.
Lock
()
fmt
.
Println
(
"peer enrolled, addr: "
,
string
(
peer
.
Ip
[
:
]),
peer
.
Port
,
peer
.
Nat_type
)
m
.
Lock
()
seq
++
seq
++
peerID
=
seq
myInfo
.
ID
=
seq
peers
[
peerID
]
=
peer
peers
[
myInfo
.
ID
]
=
myInfo
peers_conn
[
peerID
]
=
c
peerConn
[
myInfo
.
ID
]
=
c
fmt
.
Println
(
"new peer, id : "
,
peerID
)
if
myInfo
.
Meta
!=
""
{
m
.
Unlock
()
peersFromMeta
[
myInfo
.
Meta
]
=
myInfo
err
=
binary
.
Write
(
c
,
binary
.
BigEndian
,
peerID
)
peerConnFromMeta
[
myInfo
.
Meta
]
=
c
}
mutex
.
Unlock
()
log
.
WithFields
(
log
.
Fields
{
"ID"
:
myInfo
.
ID
,
"Meta"
:
myInfo
.
Meta
,
"IP"
:
string
(
myInfo
.
IP
[
:
]),
"Port"
:
myInfo
.
Port
,
"NatType"
:
myInfo
.
NatType
,
})
.
Debug
(
"New peer enrolled"
)
err
=
binary
.
Write
(
w
,
binary
.
BigEndian
,
myInfo
.
ID
)
if
err
!=
nil
{
if
err
!=
nil
{
continue
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"ID"
:
myInfo
.
ID
,
"Meta"
:
myInfo
.
Meta
,
"IP"
:
string
(
myInfo
.
IP
[
:
]),
"Port"
:
myInfo
.
Port
,
"NatType"
:
myInfo
.
NatType
,
})
.
Warn
(
"Unable to return my peer info"
)
break
}
}
case
GetPeerInfo
:
case
GetPeerInfo
:
var
peer_id
uint32
var
peerID
uint32
binary
.
Read
(
c
,
binary
.
BigEndian
,
&
peer_id
)
err
=
binary
.
Read
(
c
,
binary
.
BigEndian
,
&
peerID
)
if
val
,
ok
:=
peers
[
peer_id
];
ok
{
if
err
!=
nil
{
binary
.
Write
(
c
,
binary
.
BigEndian
,
val
)
log
.
WithFields
(
log
.
Fields
{
}
else
{
"err"
:
err
,
var
offline
uint8
=
0
"peerID"
:
peerID
,
binary
.
Write
(
c
,
binary
.
BigEndian
,
offline
)
"myID"
:
myInfo
.
ID
,
fmt
.
Printf
(
"%d offline
\n
"
,
peer_id
)
})
.
Warn
(
"Unable to get peer id"
)
binary
.
Write
(
c
,
binary
.
BigEndian
,
PeerOffline
)
break
}
peer
,
err
:=
getPeerInfo
(
PeerInfo
{
ID
:
peerID
})
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"peerID"
:
peerID
,
"myID"
:
myInfo
.
ID
,
})
.
Warn
(
"Unable to get peer info"
)
break
}
err
=
writePeerInfo
(
w
,
peer
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"peerID"
:
peerID
,
"myID"
:
myInfo
.
ID
,
})
.
Warn
(
"Unable to write peer info"
)
break
}
}
case
NotifyPeer
:
case
NotifyPeer
:
var
peer_id
uint32
var
peerID
uint32
binary
.
Read
(
c
,
binary
.
BigEndian
,
&
peer_id
)
err
=
binary
.
Read
(
c
,
binary
.
BigEndian
,
&
peerID
)
fmt
.
Println
(
"notify to peer"
,
peer_id
)
if
err
!=
nil
{
if
val
,
ok
:=
peers_conn
[
peer_id
];
ok
{
log
.
WithFields
(
log
.
Fields
{
if
err
=
binary
.
Write
(
val
,
binary
.
BigEndian
,
peers
[
peerID
]);
err
!=
nil
{
"err"
:
err
,
// unable to notify peer
"peerID"
:
peerID
,
fmt
.
Println
(
"offline"
)
"myID"
:
myInfo
.
ID
,
})
.
Warn
(
"Unable to get peer id"
)
break
}
}
}
else
{
conn
,
err
:=
getConn
(
PeerInfo
{
ID
:
peerID
})
fmt
.
Println
(
"offline"
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"peerID"
:
peerID
,
"myID"
:
myInfo
.
ID
,
})
.
Warn
(
"Unable to get peer conn"
)
binary
.
Write
(
c
,
binary
.
BigEndian
,
PeerOffline
)
break
}
err
=
writePeerInfo
(
conn
,
myInfo
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"peerID"
:
peerID
,
"myID"
:
myInfo
.
ID
,
})
.
Warn
(
"Unable to write my peer info to peer connection"
)
break
}
case
GetPeerInfoFromMeta
:
peerMeta
,
err
:=
readMeta
(
c
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"myMeta"
:
myInfo
.
Meta
,
})
.
Warn
(
"Unable to get peer meta"
)
break
}
peer
,
err
:=
getPeerInfo
(
PeerInfo
{
Meta
:
peerMeta
})
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"meta"
:
peerMeta
,
"myMeta"
:
myInfo
.
Meta
,
})
.
Warn
(
"Unable to get peer info"
)
break
}
err
=
writePeerInfo
(
w
,
peer
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"peerMeta"
:
peer
.
Meta
,
"myMeta"
:
myInfo
.
Meta
,
})
.
Warn
(
"Unable to write peer info"
)
break
}
case
NotifyPeerFromMeta
:
peerMeta
,
err
:=
readMeta
(
c
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"myMeta"
:
myInfo
.
Meta
,
})
.
Warn
(
"Unable to get peer id"
)
break
}
conn
,
err
:=
getConn
(
PeerInfo
{
Meta
:
peerMeta
})
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"meta"
:
peerMeta
,
"myMeta"
:
myInfo
.
Meta
,
})
.
Warn
(
"Unable to get peer conn"
)
binary
.
Write
(
c
,
binary
.
BigEndian
,
PeerOffline
)
break
}
err
=
writePeerInfo
(
conn
,
myInfo
)
if
err
!=
nil
{
log
.
WithFields
(
log
.
Fields
{
"err"
:
err
,
"peerMeta"
:
peerMeta
,
"myMeta"
:
myInfo
.
Meta
,
})
.
Warn
(
"Unable to write my peer to peer connection"
)
break
}
}
default
:
default
:
fmt
.
Println
(
"illegal message"
)
log
.
WithFields
(
log
.
Fields
{
"type"
:
t
,
})
.
Warn
(
"Illegal message"
)
}
}
log
.
WithFields
(
log
.
Fields
{
"response"
:
(
&
myBuf
)
.
Bytes
(),
})
.
Debug
(
"Response sent"
)
}
}
return
return
...
...
stun_host_test.c
0 → 100644
View file @
70c0ff3d
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nat_type.h"
#define DEFAULT_STUN_SERVER_PORT 3478
#define DEFAULT_LOCAL_PORT 34780
int
appendToFile
(
char
*
c
,
nat_type
type
)
{
FILE
*
fp
;
int
retval
;
fp
=
fopen
(
"public_stun_list-working.txt"
,
"a"
);
if
(
fp
==
NULL
)
return
-
1
;
retval
=
fprintf
(
fp
,
"%s, %d
\n
"
,
c
,
type
);
fclose
(
fp
);
return
retval
;
}
int
main
()
{
uint16_t
stun_port
=
DEFAULT_STUN_SERVER_PORT
;
uint16_t
local_port
=
DEFAULT_LOCAL_PORT
;
char
ext_ip
[
16
]
=
{
0
};
uint16_t
ext_port
=
0
;
char
local_ip
[
16
]
=
"0.0.0.0"
;
FILE
*
fp
;
char
*
line
=
NULL
;
size_t
len
=
0
;
ssize_t
read
;
/* from https://gist.github.com/mondain/b0ec1cf5f60ae726202e */
fp
=
fopen
(
"public-stun-list.txt"
,
"r"
);
if
(
fp
==
NULL
)
exit
(
EXIT_FAILURE
);
while
((
read
=
getline
(
&
line
,
&
len
,
fp
))
!=
-
1
)
{
printf
(
"Retrieved line of length %zu:
\n
"
,
read
);
printf
(
"%s
\n
"
,
line
);
line
[
strcspn
(
line
,
"
\n
"
)]
=
0
;
char
*
stun_server
=
line
;
printf
(
"Testing stun server %s
\n
"
,
stun_server
);
nat_type
type
=
detect_nat_type
(
stun_server
,
stun_port
,
local_ip
,
local_port
,
ext_ip
,
&
ext_port
);
printf
(
"The return value is %d (%s)
\n
"
,
type
,
get_nat_desc
(
type
));
if
(
type
!=
0
)
{
appendToFile
(
stun_server
,
type
);
};
;
}
fclose
(
fp
);
if
(
line
)
free
(
line
);
exit
(
EXIT_SUCCESS
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment