Merge pull request #40 from misi/master

new NAT behavior discovery utility
This commit is contained in:
misi 2016-09-04 07:06:01 +02:00 committed by GitHub
commit 9f53237de8
11 changed files with 655 additions and 12 deletions

View File

@ -1,9 +1,13 @@
09/04/2016 Mihaly Meszaros <bakfitty@gmail.com>
Version 4.5.0.6 'dan Eider':
- new NAT behavior discovery utilty.
08/27/2016 Oleg Moskalenko <mom040267@gmail.com>
Version 4.5.0.5 'dan Eider':
- Typos in the text fixed.
- LibreSSL compatibility fixed.
- "read_timeout" option support for MySQL.
08/20/2016 Oleg Moskalenko <mom040267@gmail.com>
Version 4.5.0.4 'dan Eider':
- OpenSSL 1.1.0 support added.

View File

@ -34,7 +34,7 @@ SERVERAPP_HEADERS = src/apps/relay/userdb.h src/apps/relay/tls_listener.h src/ap
SERVERAPP_MODS = src/apps/relay/mainrelay.c src/apps/relay/netengine.c src/apps/relay/libtelnet.c src/apps/relay/turn_admin_server.c src/apps/relay/userdb.c src/apps/relay/tls_listener.c src/apps/relay/dtls_listener.c ${HIREDIS_MODS} ${USERDB_MODS}
SERVERAPP_DEPS = ${SERVERTURN_MODS} ${SERVERTURN_DEPS} ${SERVERAPP_MODS} ${SERVERAPP_HEADERS} ${COMMON_DEPS} ${IMPL_DEPS} lib/libturnclient.a
TURN_BUILD_RESULTS = bin/turnutils_stunclient bin/turnutils_rfc5769check bin/turnutils_uclient bin/turnserver bin/turnutils_peer lib/libturnclient.a include/turn/ns_turn_defs.h sqlite_empty_db
TURN_BUILD_RESULTS = bin/turnutils_natdiscovery bin/turnutils_stunclient bin/turnutils_rfc5769check bin/turnutils_uclient bin/turnserver bin/turnutils_peer lib/libturnclient.a include/turn/ns_turn_defs.h sqlite_empty_db
all: ${TURN_BUILD_RESULTS}
@ -54,6 +54,11 @@ bin/turnutils_uclient: ${COMMON_DEPS} src/apps/uclient/session.h lib/libturnclie
${MKBUILDDIR} bin
${CC} ${CPPFLAGS} ${CFLAGS} src/apps/uclient/uclient.c src/apps/uclient/startuclient.c src/apps/uclient/mainuclient.c ${COMMON_MODS} -o $@ -Llib -lturnclient -Llib ${LDFLAGS}
bin/turnutils_natdiscovery: ${COMMON_DEPS} lib/libturnclient.a src/apps/natdiscovery/natdiscovery.c
pwd
${MKBUILDDIR} bin
${CC} ${CPPFLAGS} ${CFLAGS} src/apps/natdiscovery/natdiscovery.c ${COMMON_MODS} -o $@ -Llib -lturnclient -Llib ${LDFLAGS}
bin/turnutils_stunclient: ${COMMON_DEPS} lib/libturnclient.a src/apps/stunclient/stunclient.c
pwd
${MKBUILDDIR} bin
@ -125,11 +130,13 @@ install: all ${MAKE_DEPS}
${INSTALL_PROGRAM} bin/turnutils_uclient ${DESTDIR}${BINDIR}
${INSTALL_PROGRAM} bin/turnutils_peer ${DESTDIR}${BINDIR}
${INSTALL_PROGRAM} bin/turnutils_stunclient ${DESTDIR}${BINDIR}
${INSTALL_PROGRAM} bin/turnutils_natdiscovery ${DESTDIR}${BINDIR}
${INSTALL_MAN} man/man1/turnserver.1 ${DESTDIR}${MANPREFIX}/man/man1/
${INSTALL_MAN} man/man1/turnadmin.1 ${DESTDIR}${MANPREFIX}/man/man1/
${INSTALL_MAN} man/man1/turnutils.1 ${DESTDIR}${MANPREFIX}/man/man1/
${INSTALL_MAN} man/man1/turnutils_uclient.1 ${DESTDIR}${MANPREFIX}/man/man1/
${INSTALL_MAN} man/man1/turnutils_stunclient.1 ${DESTDIR}${MANPREFIX}/man/man1/
${INSTALL_MAN} man/man1/turnutils_natdiscovery.1 ${DESTDIR}${MANPREFIX}/man/man1/
${INSTALL_MAN} man/man1/turnutils_peer.1 ${DESTDIR}${MANPREFIX}/man/man1/
${INSTALL_MAN} man/man1/coturn.1 ${DESTDIR}${MANPREFIX}/man/man1/
${INSTALL_STATIC_LIB} lib/libturnclient.a ${DESTDIR}${LIBDIR}
@ -169,11 +176,13 @@ deinstall: ${MAKE_DEPS}
${RMCMD} ${DESTDIR}${BINDIR}/turnutils_peer
${RMCMD} ${DESTDIR}${BINDIR}/turnutils_uclient
${RMCMD} ${DESTDIR}${BINDIR}/turnutils_stunclient
${RMCMD} ${DESTDIR}${BINDIR}/turnutils_natdiscovery
${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnserver.1
${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnadmin.1
${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils.1
${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils_uclient.1
${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils_stunclient.1
${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils_natdiscovery.1
${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils_peer.1
${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/coturn.1
${RMCMD} ${DESTDIR}${LIBDIR}/libturnclient.a

View File

@ -252,3 +252,5 @@ to see the man page.
Federico Pinna <fpinna@vivocha.com>
Bradley T. Hughes <bradleythughes@fastmail.fm>
Mihaly Meszaros <bakfitty@gmail.com>

View File

@ -948,3 +948,5 @@ https://groups.google.com/forum/?fromgroups=#!forum/turn-server-project-rfc5766-
Federico Pinna <fpinna@vivocha.com>
Bradley T. Hughes <bradleythughes@fastmail.fm>
Mihaly Meszaros <bakfitty@gmail.com>

View File

@ -25,7 +25,6 @@ The compiled binary image of this program is located in bin/ subdirectory.
STUN/TURN protocol implementation. This utility is used only for the compilation
check procedure, it is not copied to the installation destination.
In the "examples/scripts" subdirectory, you will find the examples of command lines to be used
to run the programs. The scripts are meant to be run from examples/ subdirectory, for example:
@ -33,6 +32,11 @@ $ cd examples
$ ./scripts/secure_relay.sh
5. turnutils_natdiscovery: a utility that provides NAT behavior discovery
according RFC5780. This utility discovers the actual NAT Mapping and Filtering
behavior. Be aweare that at least two different listening IP addresses should
be configured to be able to work properly!
=====================================
NAME
@ -230,6 +234,43 @@ Usage:
$ turnutils_rfc5769check
=====================================
NAME
turnutils_natdiscovery - a utility that discovers NAT mapping and filtering
behavior according RFC5780.
SYNOPSIS
$ turnutils_natdiscovery [options] <STUN-Server-FQDN-or-IP-address>
DESCRIPTION
turnutils_natdiscovery discovers the NAT Mapping and Filtering behavior, to
determine if that NAT is currently using Endpoint-Independent,
Address-Dependent, or Address and Port-Dependent Mapping and/or to determine if
that NAT is currently using Endpoint-Independent, Address-Dependent, or Address
and Port-Dependent Filtering.
Use either -m and/or -f flag to discover NAT Mapping and/or Filtering.
Flags:
-m NAT mapping behavior discovery
-f NAT filtering behavior discovery
Options with required values:
-p STUN server port (Default: 3478)
-L Local address to use (optional)
Usage:
$ turnutils_natdiscovery -m -f stun.example.com
===================================
DOCS
@ -335,3 +376,5 @@ SEE ALSO
Federico Pinna <fpinna@vivocha.com>
Bradley T. Hughes <bradleythughes@fastmail.fm>
Mihaly Meszaros <bakfitty@gmail.com>

View File

@ -2,14 +2,15 @@
rm -rf man/man1/*
txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -B "TURN Server" README.turnserver | sed -e 's/-/\\-/g' > man/man1/turnserver.1
txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -I turnutils_natdiscovery -B "TURN Server" README.turnserver | sed -e 's/-/\\-/g' > man/man1/turnserver.1
txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -B "TURN Server" README.turnadmin | sed -e 's/-/\\-/g'> man/man1/turnadmin.1
txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -I turnutils_natdiscovery -B "TURN Server" README.turnadmin | sed -e 's/-/\\-/g'> man/man1/turnadmin.1
txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -B "TURN Server" README.turnutils | sed -e 's/-/\\-/g' > man/man1/turnutils.1
txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -I turnutils_natdiscovery -B "TURN Server" README.turnutils | sed -e 's/-/\\-/g' > man/man1/turnutils.1
cd man/man1; ln -s turnutils.1 turnutils_uclient.1;cd ../..
cd man/man1; ln -s turnutils.1 turnutils_peer.1;cd ../..
cd man/man1; ln -s turnutils.1 turnutils_stunclient.1;cd ../..
cd man/man1; ln -s turnutils.1 turnutils_natdiscovery.1;cd ../..
cd man/man1; ln -s turnserver.1 coturn.1;cd ../..

View File

@ -1,5 +1,5 @@
.\" Text automatically generated by txt2man
.TH TURN 1 "27 August 2016" "" ""
.TH TURN 1 "04 September 2016" "" ""
.SH GENERAL INFORMATION
\fIturnadmin\fP is a TURN administration tool. This tool can be used to manage
@ -340,3 +340,5 @@ Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
Federico Pinna <fpinna@vivocha.com>
.PP
Bradley T. Hughes <bradleythughes@fastmail.fm>
.PP
Mihaly Meszaros <bakfitty@gmail.com>

View File

@ -1,5 +1,5 @@
.\" Text automatically generated by txt2man
.TH TURN 1 "27 August 2016" "" ""
.TH TURN 1 "04 September 2016" "" ""
.SH GENERAL INFORMATION
The \fBTURN Server\fP project contains the source code of a TURN server and TURN client
@ -1189,3 +1189,5 @@ Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
Federico Pinna <fpinna@vivocha.com>
.PP
Bradley T. Hughes <bradleythughes@fastmail.fm>
.PP
Mihaly Meszaros <bakfitty@gmail.com>

View File

@ -1,5 +1,5 @@
.\" Text automatically generated by txt2man
.TH TURN 1 "27 August 2016" "" ""
.TH TURN 1 "04 September 2016" "" ""
.SH GENERAL INFORMATION
A set of turnutils_* programs provides some utility functionality to be used
@ -34,16 +34,20 @@ The compiled binary image of this program is located in bin/ subdirectory.
\fIturnutils_rfc5769check\fP: a utility that checks the correctness of the
STUN/TURN protocol implementation. This utility is used only for the compilation
check procedure, it is not copied to the installation destination.
.RE
.PP
.RS
In the "examples/scripts" subdirectory, you will find the examples of command lines to be used
to run the programs. The scripts are meant to be run from examples/ subdirectory, for example:
.PP
$ cd examples
.PP
$ ./scripts/secure_relay.sh
.TP
.B
5.
\fIturnutils_natdiscovery\fP: a utility that provides NAT behavior discovery
according RFC5780. This utility discovers the actual NAT Mapping and Filtering
behavior. Be aweare that at least two different listening IP addresses should
be configured to be able to work properly!
.PP
=====================================
.SS NAME
@ -360,6 +364,56 @@ Usage:
.PP
$ \fIturnutils_rfc5769check\fP
.PP
=====================================
.SS NAME
\fB
\fBturnutils_natdiscovery \fP\- a utility that discovers NAT mapping and filtering
\fBbehavior according RFC5780.
\fB
.SS SYNOPSIS
.nf
.fam C
$ \fIturnutils_natdiscovery\fP [\fIoptions\fP] <STUN\-Server\-FQDN\-or\-IP\-address>
.fam T
.fi
.fam T
.fi
.SS DESCRIPTION
\fIturnutils_natdiscovery\fP discovers the NAT Mapping and Filtering behavior, to
determine if that NAT is currently using Endpoint\-Independent,
Address\-Dependent, or Address and Port\-Dependent Mapping and/or to determine if
that NAT is currently using Endpoint\-Independent, Address\-Dependent, or Address
and Port\-Dependent Filtering.
.PP
Use either \fB\-m\fP and/or \fB\-f\fP flag to discover NAT Mapping and/or Filtering.
.PP
Flags:
.TP
.B
\fB\-m\fP
NAT mapping behavior discovery
.TP
.B
\fB\-f\fP
NAT filtering behavior discovery
.PP
Options with required values:
.TP
.B
\fB\-p\fP
STUN server port (Default: 3478)
.TP
.B
\fB\-L\fP
Local address to use (optional)
.PP
Usage:
.PP
$ \fIturnutils_natdiscovery\fP \fB\-m\fP \fB\-f\fP stun.example.com
.PP
===================================
.SH DOCS
@ -460,3 +514,5 @@ Mutsutoshi Yoshimoto <mutsutoshi.yoshimoto@mixi.co.jp>
Federico Pinna <fpinna@vivocha.com>
.PP
Bradley T. Hughes <bradleythughes@fastmail.fm>
.PP
Mihaly Meszaros <bakfitty@gmail.com>

View File

@ -0,0 +1 @@
turnutils.1

View File

@ -0,0 +1,521 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <err.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "ns_turn_utils.h"
#include "apputils.h"
#include "stun_buffer.h"
#ifdef __cplusplus
#include "TurnMsgLib.h"
#endif
////////////////////////////////////////////////////
static int udp_fd = -1;
static ioa_addr real_local_addr;
static int counter = 0;
#ifdef __cplusplus
static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *port, int *rfc5780, int response_port, int change_ip, int change_port, int padding)
{
int ret=0;
if (response_port >= 0) {
addr_set_port(&real_local_addr, response_port);
}
udp_fd = socket(remote_addr->ss.sa_family, SOCK_DGRAM, 0);
if (udp_fd < 0)
err(-1, NULL);
if (!addr_any(&real_local_addr)) {
if (addr_bind(udp_fd, &real_local_addr,0,1,UDP_SOCKET) < 0)
err(-1, NULL);
}
turn::StunMsgRequest req(STUN_METHOD_BINDING);
req.constructBindingRequest();
if (response_port >= 0) {
turn::StunAttrResponsePort rpa;
rpa.setResponsePort((u16bits)response_port);
try {
req.addAttr(rpa);
} catch(turn::WrongStunAttrFormatException &ex1) {
printf("Wrong rp attr format\n");
exit(-1);
} catch(turn::WrongStunBufferFormatException &ex2) {
printf("Wrong stun buffer format (1)\n");
exit(-1);
} catch(...) {
printf("Wrong something (1)\n");
exit(-1);
}
}
if (change_ip || change_port) {
turn::StunAttrChangeRequest cra;
cra.setChangeIp(change_ip);
cra.setChangePort(change_port);
try {
req.addAttr(cra);
} catch(turn::WrongStunAttrFormatException &ex1) {
printf("Wrong cr attr format\n");
exit(-1);
} catch(turn::WrongStunBufferFormatException &ex2) {
printf("Wrong stun buffer format (2)\n");
exit(-1);
} catch(...) {
printf("Wrong something (2)\n");
exit(-1);
}
}
if (padding) {
turn::StunAttrPadding pa;
pa.setPadding(1500);
try {
req.addAttr(pa);
} catch(turn::WrongStunAttrFormatException &ex1) {
printf("Wrong p attr format\n");
exit(-1);
} catch(turn::WrongStunBufferFormatException &ex2) {
printf("Wrong stun buffer format (3)\n");
exit(-1);
} catch(...) {
printf("Wrong something (3)\n");
exit(-1);
}
}
{
int len = 0;
int slen = get_ioa_addr_len(remote_addr);
do {
len = sendto(udp_fd, req.getRawBuffer(), req.getSize(), 0, (struct sockaddr*) remote_addr, (socklen_t) slen);
} while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN)));
if (len < 0)
err(-1, NULL);
}
if (addr_get_from_sock(udp_fd, &real_local_addr) < 0) {
printf("%s: Cannot get address from local socket\n", __FUNCTION__);
} else {
*port = addr_get_port(&real_local_addr);
}
{
int len = 0;
stun_buffer buf;
u08bits *ptr = buf.buf;
int recvd = 0;
const int to_recv = sizeof(buf.buf);
struct timeval tv;
tv.tv_sec = 3; /* 3 Secs Timeout */
tv.tv_usec = 0; // Not init'ing this can cause strange errors
setsockopt(udp_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
do {
len = recv(udp_fd, ptr, to_recv - recvd, 0);
if (len > 0) {
recvd += len;
ptr += len;
break;
}
} while (len < 0 && (errno == EINTR));
if (recvd > 0)
len = recvd;
buf.len = len;
try {
turn::StunMsgResponse res(buf.buf, sizeof(buf.buf), (size_t)buf.len, true);
if (res.isCommand()) {
if(res.isSuccess()) {
if (res.isBindingResponse()) {
turn::StunAttrIterator iter(res,STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS);
if (!iter.eof()) {
turn::StunAttrAddr addr(iter);
addr.getAddr(*reflexive_addr);
turn::StunAttrIterator iter1(res,STUN_ATTRIBUTE_OTHER_ADDRESS);
if (!iter1.eof()) {
*rfc5780 = 1;
printf("\n========================================\n");
printf("RFC 5780 response %d\n",++counter);
turn::StunAttrAddr addr1(iter1);
addr1.getAddr(*other_addr);
turn::StunAttrIterator iter2(res,STUN_ATTRIBUTE_RESPONSE_ORIGIN);
if (!iter2.eof()) {
ioa_addr response_origin;
turn::StunAttrAddr addr2(iter2);
addr2.getAddr(response_origin);
addr_debug_print(1, &response_origin, "Response origin: ");
}
addr_debug_print(1, other_addr, "Other addr: ");
}
addr_debug_print(1, &reflexive_addr, "UDP reflexive addr");
} else {
printf("Cannot read the response\n");
}
} else {
printf("Wrong type of response\n");
}
} else {
int err_code = res.getError();
std::string reason = res.getReason();
printf("The response is an error %d (%s)\n", err_code, reason.c_str());
}
} else {
printf("The response is not a reponse message\n");
}
} catch(...) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
printf("STUN receive timeout..\n");
}else{
printf("The response is not a well formed STUN message\n");
}
ret=1;
}
}
close(udp_fd);
return ret;
}
#else
static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *port, int *rfc5780, int response_port, int change_ip, int change_port, int padding)
{
int ret=0;
stun_buffer buf;
udp_fd = socket(remote_addr->ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL);
if (udp_fd < 0)
err(-1, NULL);
if (!addr_any(&real_local_addr)) {
if (response_port >= 0) {
addr_set_port(&real_local_addr, response_port);
}
if (addr_bind(udp_fd, &real_local_addr,0,1,UDP_SOCKET) < 0) {
err(-1, NULL);
}
}
stun_prepare_binding_request(&buf);
if (response_port >= 0) {
stun_attr_add_response_port_str((u08bits*) (buf.buf), (size_t*) &(buf.len), (u16bits) response_port);
}
if (change_ip || change_port) {
stun_attr_add_change_request_str((u08bits*) buf.buf, (size_t*) &(buf.len), change_ip, change_port);
}
if (padding) {
if(stun_attr_add_padding_str((u08bits*) buf.buf, (size_t*) &(buf.len), 1500)<0) {
printf("%s: ERROR: Cannot add padding\n",__FUNCTION__);
}
}
{
int len = 0;
int slen = get_ioa_addr_len(remote_addr);
do {
len = sendto(udp_fd, buf.buf, buf.len, 0, (struct sockaddr*) remote_addr, (socklen_t) slen);
} while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN)));
if (len < 0)
err(-1, NULL);
}
if (addr_get_from_sock(udp_fd, &real_local_addr) < 0) {
printf("%s: Cannot get address from local socket\n", __FUNCTION__);
} else {
*port = addr_get_port(&real_local_addr);
}
{
int len = 0;
u08bits *ptr = buf.buf;
int recvd = 0;
const int to_recv = sizeof(buf.buf);
struct timeval tv;
tv.tv_sec = 3; /* 3 Secs Timeout */
tv.tv_usec = 0; // Not init'ing this can cause strange errors
setsockopt(udp_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
do {
len = recv(udp_fd, ptr, to_recv - recvd, 0);
if (len > 0) {
recvd += len;
ptr += len;
break;
}
} while (len < 0 && (errno == EINTR));
if (recvd > 0)
len = recvd;
buf.len = len;
if (stun_is_command_message(&buf)) {
if (stun_is_response(&buf)) {
if (stun_is_success_response(&buf)) {
if (stun_is_binding_response(&buf)) {
addr_set_any(reflexive_addr);
if (stun_attr_get_first_addr(&buf, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, reflexive_addr, NULL) >= 0) {
stun_attr_ref sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_OTHER_ADDRESS);
if (sar) {
*rfc5780 = 1;
printf("\n========================================\n");
printf("RFC 5780 response %d\n",++counter);
stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, other_addr, NULL);
sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_RESPONSE_ORIGIN);
if (sar) {
ioa_addr response_origin;
stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, &response_origin, NULL);
addr_debug_print(1, &response_origin, "Response origin: ");
}
addr_debug_print(1, other_addr, "Other addr: ");
}
addr_debug_print(1, reflexive_addr, "UDP reflexive addr");
} else {
printf("Cannot read the response\n");
}
} else {
printf("Wrong type of response\n");
}
} else {
int err_code = 0;
u08bits err_msg[1025] = "\0";
size_t err_msg_size = sizeof(err_msg);
if (stun_is_error_response(&buf, &err_code, err_msg, err_msg_size)) {
printf("The response is an error %d (%s)\n", err_code, (char*) err_msg);
} else {
printf("The response is an unrecognized error\n");
}
}
} else {
printf("The response is not a reponse message\n");
ret=1;
}
} else {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
printf("STUN receive timeout..\n");
}else{
printf("The response is not a STUN message\n");
}
ret=1;
}
}
socket_closesocket(udp_fd);
return ret;
}
#endif
//////////////// local definitions /////////////////
static char Usage[] =
"Usage: natdiscovery [options] address\n"
"Options:\n"
" -m NAT mapping behavior discovery\n"
" -f NAT filtering behavior discovery\n"
" -p STUN server port (Default: 3478)\n"
" -L Local address to use (optional)\n";
//////////////////////////////////////////////////
static void init(ioa_addr *real_local_addr,ioa_addr *remote_addr,int *local_port,int port, int *rfc5780, char* local_addr, char* remote_param)
{
addr_set_any(real_local_addr);
if(local_addr[0]) {
if(make_ioa_addr((const u08bits*)local_addr, 0, real_local_addr)<0) {
err(-1,NULL);
}
}
*local_port = -1;
*rfc5780 = 0;
if (make_ioa_addr((const u08bits*)remote_param, port, remote_addr) < 0)
err(-1, NULL);
}
static void discoveryresult(const char *decision){
printf("\n========================================\n");
printf("%s",decision);
printf("\n========================================\n");
}
int main(int argc, char **argv)
{
int port = DEFAULT_STUN_PORT;
char local_addr[256]="\0";
int c=0;
int mapping = 0;
int filtering = 0;
int local_port, rfc5780;
ioa_addr other_addr, reflexive_addr, tmp_addr, remote_addr;
set_logfile("stdout");
set_system_parameters(0);
ns_bzero(local_addr, sizeof(local_addr));
addr_set_any(&remote_addr);
addr_set_any(&other_addr);
addr_set_any(&reflexive_addr);
addr_set_any(&tmp_addr);
while ((c = getopt(argc, argv, "mfp:L:")) != -1) {
switch(c) {
case 'm':
mapping=1;
break;
case 'f':
filtering=1;
break;
case 'p':
port = atoi(optarg);
break;
case 'L':
STRCPY(local_addr, optarg);
break;
default:
fprintf(stderr,"%s\n", Usage);
exit(1);
}
}
if(optind>=argc) {
fprintf(stderr, "%s\n", Usage);
exit(-1);
}
init(&real_local_addr, &remote_addr, &local_port, port, &rfc5780, local_addr, argv[optind]);
if (mapping) {
run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0);
if (addr_eq(&real_local_addr,&reflexive_addr)){
discoveryresult("No NAT! (Endpoint Independent Mapping)");
}
if(rfc5780) {
if(!addr_any(&other_addr)){
addr_cpy(&tmp_addr, &reflexive_addr);
addr_cpy(&remote_addr, &other_addr);
addr_set_port(&remote_addr, port);
run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0);
if(addr_eq(&tmp_addr,&reflexive_addr)){
discoveryresult("NAT with Enpoint Independent Mapping!");
} else {
addr_cpy(&tmp_addr, &reflexive_addr);
addr_cpy(&remote_addr, &other_addr);
run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0);
if(addr_eq(&tmp_addr,&reflexive_addr)){
discoveryresult("NAT with Address Dependent Mapping!");
} else {
discoveryresult("NAT with Address and Port Dependent Mapping!");
}
};
}
}
}
init(&real_local_addr, &remote_addr, &local_port, port, &rfc5780, local_addr, argv[optind]);
if (filtering) {
run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0);
if (addr_eq(&real_local_addr,&reflexive_addr)){
discoveryresult("No NAT! (Endpoint Independent Mapping)");
}
if(rfc5780) {
if(!addr_any(&other_addr)){
int res=0;
res=run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,1,1,0);
if (!res) {
discoveryresult("NAT with Enpoint Independent Filtering!");
} else {
res=0;
res=run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,1,0);
if(!res){
discoveryresult("NAT with Address Dependent Filtering!");
} else {
discoveryresult("NAT with Address and Port Dependent Filtering!");
}
};
}
}
}
if (!filtering && !mapping) {
printf("Please use either -f or -m parameter for Filtering or Mapping behavior discovery.\n");
}
socket_closesocket(udp_fd);
return 0;
}