mirror of
https://github.com/coturn/coturn.git
synced 2025-10-24 12:31:00 +02:00
2673 lines
87 KiB
C
2673 lines
87 KiB
C
/*
|
|
* 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 "mainrelay.h"
|
|
|
|
////// TEMPORARY data //////////
|
|
|
|
static int use_lt_credentials = 0;
|
|
static int anon_credentials = 0;
|
|
|
|
////// TURNDB //////////////
|
|
|
|
#if defined(TURNDB)
|
|
|
|
#if defined(Q)
|
|
#undef Q
|
|
#endif
|
|
|
|
#define Q(x) #x
|
|
|
|
#if defined(QUOTE)
|
|
#undef QUOTE
|
|
#endif
|
|
|
|
#define QUOTE(x) Q(x)
|
|
|
|
#define DEFAULT_USERDB_FILE QUOTE(TURNDB)
|
|
|
|
#else
|
|
|
|
#define DEFAULT_USERDB_FILE "/usr/local/var/db/turndb"
|
|
|
|
#endif
|
|
|
|
//////TURN PARAMS STRUCTURE DEFINITION //////
|
|
|
|
#define DEFAULT_GENERAL_RELAY_SERVERS_NUMBER (1)
|
|
|
|
turn_params_t turn_params = {
|
|
NULL, NULL,
|
|
#if TLSv1_1_SUPPORTED
|
|
NULL,
|
|
#if TLSv1_2_SUPPORTED
|
|
NULL,
|
|
#endif
|
|
#endif
|
|
#if DTLS_SUPPORTED
|
|
NULL,
|
|
#endif
|
|
#if DTLSv1_2_SUPPORTED
|
|
NULL,
|
|
#endif
|
|
|
|
DH_1066, "", "", "",
|
|
"turn_server_cert.pem","turn_server_pkey.pem", "", "",
|
|
0,0,0,0,
|
|
#if !TLS_SUPPORTED
|
|
1,
|
|
#else
|
|
0,
|
|
#endif
|
|
|
|
#if !DTLS_SUPPORTED
|
|
1,
|
|
#else
|
|
0,
|
|
#endif
|
|
|
|
TURN_VERBOSE_NONE,0,0,
|
|
"/var/run/turnserver.pid",
|
|
DEFAULT_STUN_PORT,DEFAULT_STUN_TLS_PORT,0,0,1,
|
|
0,0,0,0,
|
|
"",
|
|
"",0,
|
|
{
|
|
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,NULL,NULL,NULL
|
|
},
|
|
{NULL, 0},{NULL, 0},
|
|
NEV_UNKNOWN,
|
|
{ "Unknown", "UDP listening socket per session", "UDP thread per network endpoint", "UDP thread per CPU core" },
|
|
//////////////// Relay servers //////////////////////////////////
|
|
LOW_DEFAULT_PORTS_BOUNDARY,HIGH_DEFAULT_PORTS_BOUNDARY,0,0,0,"",
|
|
0,NULL,0,NULL,DEFAULT_GENERAL_RELAY_SERVERS_NUMBER,0,
|
|
////////////// Auth server /////////////////////////////////////
|
|
"","",0,
|
|
/////////////// AUX SERVERS ////////////////
|
|
{NULL,0,{0,NULL}},0,
|
|
/////////////// ALTERNATE SERVERS ////////////////
|
|
{NULL,0,{0,NULL}},{NULL,0,{0,NULL}},
|
|
/////////////// stop server ////////////////
|
|
0,
|
|
/////////////// MISC PARAMS ////////////////
|
|
0,0,0,0,0,SHATYPE_SHA1,':',0,0,TURN_CREDENTIALS_NONE,0,0,0,0,0,0,
|
|
///////////// Users DB //////////////
|
|
{ (TURN_USERDB_TYPE)0, {"\0"}, {0,NULL, {NULL,0}} },
|
|
///////////// CPUs //////////////////
|
|
DEFAULT_CPUS_NUMBER
|
|
};
|
|
|
|
//////////////// OpenSSL Init //////////////////////
|
|
|
|
static void openssl_setup(void);
|
|
|
|
/*
|
|
* openssl genrsa -out pkey 2048
|
|
* openssl req -new -key pkey -out cert.req
|
|
* openssl x509 -req -days 365 -in cert.req -signkey pkey -out cert
|
|
*
|
|
*/
|
|
|
|
//////////// Common static process params ////////
|
|
|
|
static gid_t procgroupid = 0;
|
|
static uid_t procuserid = 0;
|
|
static gid_t procgroupid_set = 0;
|
|
static uid_t procuserid_set = 0;
|
|
static char procusername[1025]="\0";
|
|
static char procgroupname[1025]="\0";
|
|
|
|
////////////// Configuration functionality ////////////////////////////////
|
|
|
|
static void read_config_file(int argc, char **argv, int pass);
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
static int make_local_listeners_list(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
struct ifaddrs * ifs = NULL;
|
|
struct ifaddrs * ifa = NULL;
|
|
|
|
char saddr[INET6_ADDRSTRLEN] = "";
|
|
|
|
if((getifaddrs(&ifs) == 0) && ifs) {
|
|
|
|
for (ifa = ifs; ifa != NULL; ifa = ifa->ifa_next) {
|
|
|
|
if(!(ifa->ifa_flags & IFF_UP))
|
|
continue;
|
|
|
|
if(!(ifa->ifa_addr))
|
|
continue;
|
|
|
|
if (ifa ->ifa_addr->sa_family == AF_INET) {
|
|
if(!inet_ntop(AF_INET, &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr, saddr,
|
|
INET_ADDRSTRLEN))
|
|
continue;
|
|
if(strstr(saddr,"169.254.") == saddr)
|
|
continue;
|
|
if(!strcmp(saddr,"0.0.0.0"))
|
|
continue;
|
|
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
|
|
if(!inet_ntop(AF_INET6, &((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr, saddr,
|
|
INET6_ADDRSTRLEN))
|
|
continue;
|
|
if(strstr(saddr,"fe80") == saddr)
|
|
continue;
|
|
if(!strcmp(saddr,"::"))
|
|
continue;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
add_listener_addr(saddr);
|
|
|
|
if(!(ifa->ifa_flags & IFF_LOOPBACK))
|
|
ret++;
|
|
}
|
|
freeifaddrs(ifs);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int make_local_relays_list(int allow_local, int family)
|
|
{
|
|
struct ifaddrs * ifs = NULL;
|
|
struct ifaddrs * ifa = NULL;
|
|
|
|
char saddr[INET6_ADDRSTRLEN] = "";
|
|
|
|
getifaddrs(&ifs);
|
|
|
|
int counter = 0;
|
|
|
|
if (ifs) {
|
|
for (ifa = ifs; ifa != NULL; ifa = ifa->ifa_next) {
|
|
|
|
if(!(ifa->ifa_flags & IFF_UP))
|
|
continue;
|
|
|
|
if(!(ifa->ifa_name))
|
|
continue;
|
|
if(!(ifa ->ifa_addr))
|
|
continue;
|
|
|
|
if(!allow_local && (ifa->ifa_flags & IFF_LOOPBACK))
|
|
continue;
|
|
|
|
if (ifa ->ifa_addr->sa_family == AF_INET) {
|
|
|
|
if(family != AF_INET)
|
|
continue;
|
|
|
|
if(!inet_ntop(AF_INET, &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr, saddr,
|
|
INET_ADDRSTRLEN))
|
|
continue;
|
|
if(strstr(saddr,"169.254.") == saddr)
|
|
continue;
|
|
if(!strcmp(saddr,"0.0.0.0"))
|
|
continue;
|
|
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
|
|
|
|
if(family != AF_INET6)
|
|
continue;
|
|
|
|
if(!inet_ntop(AF_INET6, &((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr, saddr,
|
|
INET6_ADDRSTRLEN))
|
|
continue;
|
|
if(strstr(saddr,"fe80") == saddr)
|
|
continue;
|
|
if(!strcmp(saddr,"::"))
|
|
continue;
|
|
} else
|
|
continue;
|
|
|
|
if(add_relay_addr(saddr)>0) {
|
|
counter += 1;
|
|
}
|
|
}
|
|
freeifaddrs(ifs);
|
|
}
|
|
|
|
return counter;
|
|
}
|
|
|
|
int get_a_local_relay(int family, ioa_addr *relay_addr)
|
|
{
|
|
struct ifaddrs * ifs = NULL;
|
|
|
|
int allow_local = 0;
|
|
|
|
int ret = -1;
|
|
|
|
char saddr[INET6_ADDRSTRLEN] = "";
|
|
|
|
getifaddrs(&ifs);
|
|
|
|
if (ifs) {
|
|
|
|
galr_start:
|
|
|
|
{
|
|
struct ifaddrs *ifa = NULL;
|
|
|
|
for (ifa = ifs; ifa != NULL ; ifa = ifa->ifa_next) {
|
|
|
|
if (!(ifa->ifa_flags & IFF_UP))
|
|
continue;
|
|
|
|
if (!(ifa->ifa_name))
|
|
continue;
|
|
if (!(ifa->ifa_addr))
|
|
continue;
|
|
|
|
if (!allow_local && (ifa->ifa_flags & IFF_LOOPBACK))
|
|
continue;
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET) {
|
|
|
|
if (family != AF_INET)
|
|
continue;
|
|
|
|
if (!inet_ntop(AF_INET,
|
|
&((struct sockaddr_in *) ifa->ifa_addr)->sin_addr,
|
|
saddr, INET_ADDRSTRLEN))
|
|
continue;
|
|
if (strstr(saddr, "169.254.") == saddr)
|
|
continue;
|
|
if (!strcmp(saddr, "0.0.0.0"))
|
|
continue;
|
|
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
|
|
|
|
if (family != AF_INET6)
|
|
continue;
|
|
|
|
if (!inet_ntop(AF_INET6,
|
|
&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr,
|
|
saddr, INET6_ADDRSTRLEN))
|
|
continue;
|
|
if (strstr(saddr, "fe80") == saddr)
|
|
continue;
|
|
if (!strcmp(saddr, "::"))
|
|
continue;
|
|
} else
|
|
continue;
|
|
|
|
if (make_ioa_addr((const u08bits*) saddr, 0, relay_addr) < 0) {
|
|
continue;
|
|
} else {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ret<0 && !allow_local) {
|
|
allow_local = 1;
|
|
goto galr_start;
|
|
}
|
|
|
|
freeifaddrs(ifs);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
static char Usage[] = "Usage: turnserver [options]\n"
|
|
"Options:\n"
|
|
" -d, --listening-device <device-name> Listener interface device (NOT RECOMMENDED. Optional, Linux only).\n"
|
|
" -p, --listening-port <port> TURN listener port (Default: 3478).\n"
|
|
" Note: actually, TLS & DTLS sessions can connect to the \"plain\" TCP & UDP port(s), too,\n"
|
|
" if allowed by configuration.\n"
|
|
" --tls-listening-port <port> TURN listener port for TLS & DTLS listeners\n"
|
|
" (Default: 5349).\n"
|
|
" Note: actually, \"plain\" TCP & UDP sessions can connect to the TLS & DTLS port(s), too,\n"
|
|
" if allowed by configuration. The TURN server\n"
|
|
" \"automatically\" recognizes the type of traffic. Actually, two listening\n"
|
|
" endpoints (the \"plain\" one and the \"tls\" one) are equivalent in terms of\n"
|
|
" functionality; but we keep both endpoints to satisfy the RFC 5766 specs.\n"
|
|
" For secure TCP connections, we currently support SSL version 3 and\n"
|
|
" TLS versions 1.0, 1.1 and 1.2. For secure UDP connections, we support\n"
|
|
" DTLS version 1.\n"
|
|
" --alt-listening-port<port> <port> Alternative listening port for STUN CHANGE_REQUEST (in RFC 5780 sense, \n"
|
|
" or in old RFC 3489 sense, default is \"listening port plus one\").\n"
|
|
" --alt-tls-listening-port <port> Alternative listening port for TLS and DTLS,\n"
|
|
" the default is \"TLS/DTLS port plus one\".\n"
|
|
" -L, --listening-ip <ip> Listener IP address of relay server. Multiple listeners can be specified.\n"
|
|
" --aux-server <ip:port> Auxiliary STUN/TURN server listening endpoint.\n"
|
|
" Auxiliary servers do not have alternative ports and\n"
|
|
" they do not support RFC 5780 functionality (CHANGE REQUEST).\n"
|
|
" Valid formats are 1.2.3.4:5555 for IPv4 and [1:2::3:4]:5555 for IPv6.\n"
|
|
" --udp-self-balance (recommended for older Linuxes only) Automatically balance UDP traffic\n"
|
|
" over auxiliary servers (if configured).\n"
|
|
" The load balancing is using the ALTERNATE-SERVER mechanism.\n"
|
|
" The TURN client must support 300 ALTERNATE-SERVER response for this functionality.\n"
|
|
" -i, --relay-device <device-name> Relay interface device for relay sockets (NOT RECOMMENDED. Optional, Linux only).\n"
|
|
" -E, --relay-ip <ip> Relay address (the local IP address that will be used to relay the\n"
|
|
" packets to the peer).\n"
|
|
" Multiple relay addresses may be used.\n"
|
|
" The same IP(s) can be used as both listening IP(s) and relay IP(s).\n"
|
|
" If no relay IP(s) specified, then the turnserver will apply the default\n"
|
|
" policy: it will decide itself which relay addresses to be used, and it\n"
|
|
" will always be using the client socket IP address as the relay IP address\n"
|
|
" of the TURN session (if the requested relay address family is the same\n"
|
|
" as the family of the client socket).\n"
|
|
" -X, --external-ip <public-ip[/private-ip]> TURN Server public/private address mapping, if the server is behind NAT.\n"
|
|
" In that situation, if a -X is used in form \"-X ip\" then that ip will be reported\n"
|
|
" as relay IP address of all allocations. This scenario works only in a simple case\n"
|
|
" when one single relay address is be used, and no STUN CHANGE_REQUEST\n"
|
|
" functionality is required.\n"
|
|
" That single relay address must be mapped by NAT to the 'external' IP.\n"
|
|
" For that 'external' IP, NAT must forward ports directly (relayed port 12345\n"
|
|
" must be always mapped to the same 'external' port 12345).\n"
|
|
" In more complex case when more than one IP address is involved,\n"
|
|
" that option must be used several times in the command line, each entry must\n"
|
|
" have form \"-X public-ip/private-ip\", to map all involved addresses.\n"
|
|
" --no-loopback-peers Disallow peers on the loopback addresses (127.x.x.x and ::1).\n"
|
|
" --no-multicast-peers Disallow peers on well-known broadcast addresses (224.0.0.0 and above, and FFXX:*).\n"
|
|
" -m, --relay-threads <number> Number of relay threads to handle the established connections\n"
|
|
" (in addition to authentication thread and the listener thread).\n"
|
|
" If explicitly set to 0 then application runs in single-threaded mode.\n"
|
|
" If not set then a default OS-dependent optimal algorithm will be employed.\n"
|
|
" The default thread number is the number of CPUs.\n"
|
|
" In older systems (pre-Linux 3.9) the number of UDP relay threads always equals\n"
|
|
" the number of listening endpoints (unless -m 0 is set).\n"
|
|
" --min-port <port> Lower bound of the UDP port range for relay endpoints allocation.\n"
|
|
" Default value is 49152, according to RFC 5766.\n"
|
|
" --max-port <port> Upper bound of the UDP port range for relay endpoints allocation.\n"
|
|
" Default value is 65535, according to RFC 5766.\n"
|
|
" -v, --verbose 'Moderate' verbose mode.\n"
|
|
" -V, --Verbose Extra verbose mode, very annoying (for debug purposes only).\n"
|
|
" -o, --daemon Start process as daemon (detach from current shell).\n"
|
|
" -f, --fingerprint Use fingerprints in the TURN messages.\n"
|
|
" -a, --lt-cred-mech Use the long-term credential mechanism.\n"
|
|
" -z, --no-auth Do not use any credential mechanism, allow anonymous access.\n"
|
|
" -u, --user <user:pwd> User account, in form 'username:password', for long-term credentials.\n"
|
|
" Cannot be used with TURN REST API.\n"
|
|
" -r, --realm <realm> The default realm to be used for the users when no explicit\n"
|
|
" origin/realm relationship was found in the database.\n"
|
|
" Must be used with long-term credentials \n"
|
|
" mechanism or with TURN REST API.\n"
|
|
" --check-origin-consistency The flag that sets the origin consistency check:\n"
|
|
" across the session, all requests must have the same\n"
|
|
" main ORIGIN attribute value (if the ORIGIN was\n"
|
|
" initially used by the session).\n"
|
|
" -q, --user-quota <number> Per-user allocation quota: how many concurrent allocations a user can create.\n"
|
|
" This option can also be set through the database, for a particular realm.\n"
|
|
" -Q, --total-quota <number> Total allocations quota: global limit on concurrent allocations.\n"
|
|
" This option can also be set through the database, for a particular realm.\n"
|
|
" -s, --max-bps <number> Default max bytes-per-second bandwidth a TURN session is allowed to handle\n"
|
|
" (input and output network streams are treated separately). Anything above\n"
|
|
" that limit will be dropped or temporary suppressed\n"
|
|
" (within the available buffer limits).\n"
|
|
" This option can also be set through the database, for a particular realm.\n"
|
|
" -B, --bps-capacity <number> Maximum server capacity.\n"
|
|
" Total bytes-per-second bandwidth the TURN server is allowed to allocate\n"
|
|
" for the sessions, combined (input and output network streams are treated separately).\n"
|
|
" -c <filename> Configuration file name (default - turnserver.conf).\n"
|
|
#if !defined(TURN_NO_SQLITE)
|
|
" -b, , --db, --userdb <filename> SQLite database file name; default - /var/db/turndb or\n"
|
|
" /usr/local/var/db/turndb or /var/lib/turn/turndb.\n"
|
|
#endif
|
|
#if !defined(TURN_NO_PQ)
|
|
" -e, --psql-userdb, --sql-userdb <conn-string> PostgreSQL database connection string, if used (default - empty, no PostreSQL DB used).\n"
|
|
" This database can be used for long-term credentials mechanism users,\n"
|
|
" and it can store the secret value(s) for secret-based timed authentication in TURN RESP API.\n"
|
|
" See http://www.postgresql.org/docs/8.4/static/libpq-connect.html for 8.x PostgreSQL\n"
|
|
" versions format, see \n"
|
|
" http://www.postgresql.org/docs/9.2/static/libpq-connect.html#LIBPQ-CONNSTRING\n"
|
|
" for 9.x and newer connection string formats.\n"
|
|
#endif
|
|
#if !defined(TURN_NO_MYSQL)
|
|
" -M, --mysql-userdb <connection-string> MySQL database connection string, if used (default - empty, no MySQL DB used).\n"
|
|
" This database can be used for long-term credentials mechanism users,\n"
|
|
" and it can store the secret value(s) for secret-based timed authentication in TURN RESP API.\n"
|
|
" The connection string my be space-separated list of parameters:\n"
|
|
" \"host=<ip-addr> dbname=<database-name> user=<database-user> \\\n password=<database-user-password> port=<db-port> connect_timeout=<seconds>\".\n\n"
|
|
" The connection string parameters for the secure communications (SSL):\n"
|
|
" ca, capath, cert, key, cipher\n"
|
|
" (see http://dev.mysql.com/doc/refman/5.1/en/ssl-options.html for the\n"
|
|
" command options description).\n\n"
|
|
" All connection-string parameters are optional.\n\n"
|
|
#endif
|
|
#if !defined(TURN_NO_MONGO)
|
|
" -J, --mongo-userdb <connection-string> MongoDB connection string, if used (default - empty, no MongoDB used).\n"
|
|
" This database can be used for long-term credentials mechanism users,\n"
|
|
" and it can store the secret value(s) for secret-based timed authentication in TURN RESP API.\n"
|
|
#endif
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
" -N, --redis-userdb <connection-string> Redis user database connection string, if used (default - empty, no Redis DB used).\n"
|
|
" This database can be used for long-term credentials mechanism users,\n"
|
|
" and it can store the secret value(s) for secret-based timed authentication in TURN RESP API.\n"
|
|
" The connection string my be space-separated list of parameters:\n"
|
|
" \"host=<ip-addr> dbname=<db-number> \\\n password=<database-user-password> port=<db-port> connect_timeout=<seconds>\".\n\n"
|
|
" All connection-string parameters are optional.\n\n"
|
|
" -O, --redis-statsdb <connection-string> Redis status and statistics database connection string, if used \n"
|
|
" (default - empty, no Redis stats DB used).\n"
|
|
" This database keeps allocations status information, and it can be also used for publishing\n"
|
|
" and delivering traffic and allocation event notifications.\n"
|
|
" The connection string has the same parameters as redis-userdb connection string.\n"
|
|
#endif
|
|
" --use-auth-secret TURN REST API flag.\n"
|
|
" Flag that sets a special authorization option that is based upon authentication secret\n"
|
|
" (TURN Server REST API, see TURNServerRESTAPI.pdf). This option is used with timestamp.\n"
|
|
" --static-auth-secret <secret> 'Static' authentication secret value (a string) for TURN REST API only.\n"
|
|
" If not set, then the turn server will try to use the 'dynamic' value\n"
|
|
" in turn_secret table in user database (if present).\n"
|
|
" That database value can be changed on-the-fly\n"
|
|
" by a separate program, so this is why it is 'dynamic'.\n"
|
|
" Multiple shared secrets can be used (both in the database and in the \"static\" fashion).\n"
|
|
" --server-name Server name used for\n"
|
|
" the oAuth authentication purposes.\n"
|
|
" The default value is the realm name.\n"
|
|
" --oauth Support oAuth authentication.\n"
|
|
" -n Do not use configuration file, take all parameters from the command line only.\n"
|
|
" --cert <filename> Certificate file, PEM format. Same file search rules\n"
|
|
" applied as for the configuration file.\n"
|
|
" If both --no-tls and --no_dtls options\n"
|
|
" are specified, then this parameter is not needed.\n"
|
|
" --pkey <filename> Private key file, PEM format. Same file search rules\n"
|
|
" applied as for the configuration file.\n"
|
|
" If both --no-tls and --no-dtls options\n"
|
|
" --pkey-pwd <password> If the private key file is encrypted, then this password to be used.\n"
|
|
" --cipher-list <\"cipher-string\"> Allowed OpenSSL cipher list for TLS/DTLS connections.\n"
|
|
" Default value is \"DEFAULT\".\n"
|
|
" --CA-file <filename> CA file in OpenSSL format.\n"
|
|
" Forces TURN server to verify the client SSL certificates.\n"
|
|
" By default, no CA is set and no client certificate check is performed.\n"
|
|
" --ec-curve-name <curve-name> Curve name for EC ciphers, if supported by OpenSSL\n"
|
|
" library (TLS and DTLS). The default value is prime256v1,\n"
|
|
" if pre-OpenSSL 1.0.2 is used. With OpenSSL 1.0.2+,\n"
|
|
" an optimal curve will be automatically calculated, if not defined\n"
|
|
" by this option.\n"
|
|
" --dh566 Use 566 bits predefined DH TLS key. Default size of the predefined key is 1066.\n"
|
|
" --dh2066 Use 2066 bits predefined DH TLS key. Default size of the predefined key is 1066.\n"
|
|
" --dh-file <dh-file-name> Use custom DH TLS key, stored in PEM format in the file.\n"
|
|
" Flags --dh566 and --dh2066 are ignored when the DH key is taken from a file.\n"
|
|
" --no-sslv3 Do not allow SSLv3 protocol.\n"
|
|
" --no-tlsv1 Do not allow TLSv1/DTLSv1 protocol.\n"
|
|
" --no-tlsv1_1 Do not allow TLSv1.1 protocol.\n"
|
|
" --no-tlsv1_2 Do not allow TLSv1.2/DTLSv1.2 protocol.\n"
|
|
" --no-udp Do not start UDP client listeners.\n"
|
|
" --no-tcp Do not start TCP client listeners.\n"
|
|
" --no-tls Do not start TLS client listeners.\n"
|
|
" --no-dtls Do not start DTLS client listeners.\n"
|
|
" --no-udp-relay Do not allow UDP relay endpoints, use only TCP relay option.\n"
|
|
" --no-tcp-relay Do not allow TCP relay endpoints, use only UDP relay options.\n"
|
|
" -l, --log-file <filename> Option to set the full path name of the log file.\n"
|
|
" By default, the turnserver tries to open a log file in\n"
|
|
" /var/log/turnserver/, /var/log, /var/tmp, /tmp and . (current) directories\n"
|
|
" (which open operation succeeds first that file will be used).\n"
|
|
" With this option you can set the definite log file name.\n"
|
|
" The special names are \"stdout\" and \"-\" - they will force everything\n"
|
|
" to the stdout; and \"syslog\" name will force all output to the syslog.\n"
|
|
" --no-stdout-log Flag to prevent stdout log messages.\n"
|
|
" By default, all log messages are going to both stdout and to\n"
|
|
" a log file. With this option everything will be going to the log file only\n"
|
|
" (unless the log file itself is stdout).\n"
|
|
" --syslog Output all log information into the system log (syslog), do not use the file output.\n"
|
|
" --simple-log This flag means that no log file rollover will be used, and the log file\n"
|
|
" name will be constructed as-is, without PID and date appendage.\n"
|
|
" This option can be used, for example, together with the logrotate tool.\n"
|
|
" --stale-nonce Use extra security with nonce value having limited lifetime (600 secs).\n"
|
|
" -S, --stun-only Option to set standalone STUN operation only, all TURN requests will be ignored.\n"
|
|
" --no-stun Option to suppress STUN functionality, only TURN requests will be processed.\n"
|
|
" --alternate-server <ip:port> Set the TURN server to redirect the allocate requests (UDP and TCP services).\n"
|
|
" Multiple alternate-server options can be set for load balancing purposes.\n"
|
|
" See the docs for more information.\n"
|
|
" --tls-alternate-server <ip:port> Set the TURN server to redirect the allocate requests (DTLS and TLS services).\n"
|
|
" Multiple alternate-server options can be set for load balancing purposes.\n"
|
|
" See the docs for more information.\n"
|
|
" -C, --rest-api-separator <SYMBOL> This is the timestamp/username separator symbol (character) in TURN REST API.\n"
|
|
" The default value is ':'.\n"
|
|
" --max-allocate-timeout=<seconds> Max time, in seconds, allowed for full allocation establishment. Default is 60.\n"
|
|
" --allowed-peer-ip=<ip[-ip]> Specifies an ip or range of ips that are explicitly allowed to connect to the \n"
|
|
" turn server. Multiple allowed-peer-ip can be set.\n"
|
|
" --denied-peer-ip=<ip[-ip]> Specifies an ip or range of ips that are not allowed to connect to the turn server.\n"
|
|
" Multiple denied-peer-ip can be set.\n"
|
|
" --pidfile <\"pid-file-name\"> File name to store the pid of the process.\n"
|
|
" Default is /var/run/turnserver.pid (if superuser account is used) or\n"
|
|
" /var/tmp/turnserver.pid .\n"
|
|
" --secure-stun Require authentication of the STUN Binding request.\n"
|
|
" By default, the clients are allowed anonymous access to the STUN Binding functionality.\n"
|
|
" --sha256 Require SHA256 digest function to be used for the message integrity.\n"
|
|
" By default, the server SHA1 (as per TURN standard specs).\n"
|
|
" With this option, the server\n"
|
|
" requires the stronger SHA256 function. The client application must\n"
|
|
" support SHA256 hash function if this option is used. If the server obtains\n"
|
|
" a message from the client with a weaker (SHA1) hash function then the server\n"
|
|
" returns error code 426.\n"
|
|
" --sha384 Require SHA384 digest function to be used for the message integrity.\n"
|
|
" --sha512 Require SHA512 digest function to be used for the message integrity.\n"
|
|
" --proc-user <user-name> User name to run the turnserver process.\n"
|
|
" After the initialization, the turnserver process\n"
|
|
" will make an attempt to change the current user ID to that user.\n"
|
|
" --proc-group <group-name> Group name to run the turnserver process.\n"
|
|
" After the initialization, the turnserver process\n"
|
|
" will make an attempt to change the current group ID to that group.\n"
|
|
" --mobility Mobility with ICE (MICE) specs support.\n"
|
|
" --no-cli Turn OFF the CLI support. By default it is always ON.\n"
|
|
" --cli-ip=<IP> Local system IP address to be used for CLI server endpoint. Default value\n"
|
|
" is 127.0.0.1.\n"
|
|
" --cli-port=<port> CLI server port. Default is 5766.\n"
|
|
" --cli-password=<password> CLI access password. Default is empty (no password).\n"
|
|
" --server-relay Server relay. NON-STANDARD AND DANGEROUS OPTION. Only for those applications\n"
|
|
" when we want to run server applications on the relay endpoints.\n"
|
|
" This option eliminates the IP permissions check on the packets\n"
|
|
" incoming to the relay endpoints.\n"
|
|
" --cli-max-output-sessions Maximum number of output sessions in ps CLI command.\n"
|
|
" This value can be changed on-the-fly in CLI. The default value is 256.\n"
|
|
" --ne=[1|2|3] Set network engine type for the process (for internal purposes).\n"
|
|
" -h Help\n"
|
|
"\n"
|
|
" For more information, see the wiki pages:\n"
|
|
"\n"
|
|
" http://code.google.com/p/coturn/w/list\n"
|
|
"\n";
|
|
|
|
static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
|
|
"\nCommands:\n\n"
|
|
" -P, --generate-encrypted-password Generate and print to the standard\n"
|
|
" output an encrypted form of a password\n"
|
|
" (for web admin user, or shared\n"
|
|
" secret, or CLI). See wiki, README or man\n"
|
|
" pages for more detailed description.\n"
|
|
" -k, --key generate long-term credential mechanism key for a user\n"
|
|
" -a, --add add/update a long-term mechanism user\n"
|
|
" -A, --add-admin add/update a web admin user\n"
|
|
" -d, --delete delete a long-term mechanism user\n"
|
|
" -D, --delete-admin delete an admin user\n"
|
|
" -l, --list list all long-term mechanism users\n"
|
|
" -L, --list-admin list all admin users\n"
|
|
" -s, --set-secret=<value> Add shared secret for TURN RESP API\n"
|
|
" -S, --show-secret Show stored shared secrets for TURN REST API\n"
|
|
" -X, --delete-secret=<value> Delete a shared secret\n"
|
|
" --delete-all-secrets Delete all shared secrets for REST API\n"
|
|
" -O, --add-origin Add origin-to-realm relation.\n"
|
|
" -R, --del-origin Delete origin-to-realm relation.\n"
|
|
" -I, --list-origins List origin-to-realm relations.\n"
|
|
" -g, --set-realm-option Set realm params: max-bps, total-quota, user-quota.\n"
|
|
" -G, --list-realm-options List realm params.\n"
|
|
"\nOptions with mandatory values:\n\n"
|
|
#if !defined(TURN_NO_SQLITE)
|
|
" -b, --db, --userdb SQLite database file, default value is /var/db/turndb or\n"
|
|
" /usr/local/var/db/turndb or /var/lib/turn/turndb.\n"
|
|
#endif
|
|
#if !defined(TURN_NO_PQ)
|
|
" -e, --psql-userdb, --sql-userdb PostgreSQL user database connection string, if PostgreSQL DB is used.\n"
|
|
#endif
|
|
#if !defined(TURN_NO_MYSQL)
|
|
" -M, --mysql-userdb MySQL user database connection string, if MySQL DB is used.\n"
|
|
#endif
|
|
#if !defined(TURN_NO_MONGO)
|
|
" -J, --mongo-userdb MongoDB user database connection string, if MongoDB is used.\n"
|
|
#endif
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
" -N, --redis-userdb Redis user database connection string, if Redis DB is used.\n"
|
|
#endif
|
|
" -u, --user Username\n"
|
|
" -r, --realm Realm\n"
|
|
" -p, --password Password\n"
|
|
#if !defined(TURN_NO_SQLITE) || !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
|
|
" -o, --origin Origin\n"
|
|
#endif
|
|
" -H, --sha256 Use SHA256 digest function to be used for the message integrity.\n"
|
|
" By default, the server SHA1 (as per TURN standard specs).\n"
|
|
" -Y, --sha384 Use SHA384 digest function to be used for the message integrity.\n"
|
|
" -K, --sha512 Use SHA512 digest function to be used for the message integrity.\n"
|
|
" --max-bps Set value of realm's max-bps parameter.\n"
|
|
" Setting to zero value means removal of the option.\n"
|
|
" --total-quota Set value of realm's total-quota parameter.\n"
|
|
" Setting to zero value means removal of the option.\n"
|
|
" --user-quota Set value of realm's user-quota parameter.\n"
|
|
" Setting to zero value means removal of the option.\n"
|
|
" -h, --help Help\n";
|
|
|
|
#define OPTIONS "c:d:p:L:E:X:i:m:l:r:u:b:B:e:M:J:N:O:q:Q:s:C:vVofhznaAS"
|
|
|
|
#define ADMIN_OPTIONS "PgGORIHKYlLkaADSdb:e:M:J:N:u:r:p:s:X:o:h"
|
|
|
|
enum EXTRA_OPTS {
|
|
NO_UDP_OPT=256,
|
|
NO_TCP_OPT,
|
|
NO_TLS_OPT,
|
|
NO_DTLS_OPT,
|
|
NO_UDP_RELAY_OPT,
|
|
NO_TCP_RELAY_OPT,
|
|
TLS_PORT_OPT,
|
|
ALT_PORT_OPT,
|
|
ALT_TLS_PORT_OPT,
|
|
CERT_FILE_OPT,
|
|
PKEY_FILE_OPT,
|
|
PKEY_PWD_OPT,
|
|
MIN_PORT_OPT,
|
|
MAX_PORT_OPT,
|
|
STALE_NONCE_OPT,
|
|
AUTH_SECRET_OPT,
|
|
DEL_ALL_AUTH_SECRETS_OPT,
|
|
STATIC_AUTH_SECRET_VAL_OPT,
|
|
AUTH_SECRET_TS_EXP, /* deprecated */
|
|
NO_STDOUT_LOG_OPT,
|
|
SYSLOG_OPT,
|
|
SIMPLE_LOG_OPT,
|
|
AUX_SERVER_OPT,
|
|
UDP_SELF_BALANCE_OPT,
|
|
ALTERNATE_SERVER_OPT,
|
|
TLS_ALTERNATE_SERVER_OPT,
|
|
NO_MULTICAST_PEERS_OPT,
|
|
NO_LOOPBACK_PEERS_OPT,
|
|
MAX_ALLOCATE_TIMEOUT_OPT,
|
|
ALLOWED_PEER_IPS,
|
|
DENIED_PEER_IPS,
|
|
CIPHER_LIST_OPT,
|
|
PIDFILE_OPT,
|
|
SECURE_STUN_OPT,
|
|
CA_FILE_OPT,
|
|
DH_FILE_OPT,
|
|
SHA256_OPT,
|
|
SHA384_OPT,
|
|
SHA512_OPT,
|
|
NO_STUN_OPT,
|
|
PROC_USER_OPT,
|
|
PROC_GROUP_OPT,
|
|
MOBILITY_OPT,
|
|
NO_CLI_OPT,
|
|
CLI_IP_OPT,
|
|
CLI_PORT_OPT,
|
|
CLI_PASSWORD_OPT,
|
|
SERVER_RELAY_OPT,
|
|
CLI_MAX_SESSIONS_OPT,
|
|
EC_CURVE_NAME_OPT,
|
|
DH566_OPT,
|
|
DH2066_OPT,
|
|
NE_TYPE_OPT,
|
|
NO_SSLV2_OPT, /*deprecated*/
|
|
NO_SSLV3_OPT,
|
|
NO_TLSV1_OPT,
|
|
NO_TLSV1_1_OPT,
|
|
NO_TLSV1_2_OPT,
|
|
CHECK_ORIGIN_CONSISTENCY_OPT,
|
|
ADMIN_MAX_BPS_OPT,
|
|
ADMIN_TOTAL_QUOTA_OPT,
|
|
ADMIN_USER_QUOTA_OPT,
|
|
SERVER_NAME_OPT,
|
|
OAUTH_OPT
|
|
};
|
|
|
|
struct myoption {
|
|
const char *name; /* name of long option */
|
|
int has_arg; /* whether option takes an argument */
|
|
int *flag; /* if not NULL, set *flag to val when option found */
|
|
int val; /* if flag is not NULL, value to set *flag to. */
|
|
/* if flag is NULL, return value */
|
|
};
|
|
|
|
struct uoptions {
|
|
union {
|
|
const struct myoption *m;
|
|
const struct option *o;
|
|
} u;
|
|
};
|
|
|
|
static const struct myoption long_options[] = {
|
|
{ "listening-device", required_argument, NULL, 'd' },
|
|
{ "listening-port", required_argument, NULL, 'p' },
|
|
{ "tls-listening-port", required_argument, NULL, TLS_PORT_OPT },
|
|
{ "alt-listening-port", required_argument, NULL, ALT_PORT_OPT },
|
|
{ "alt-tls-listening-port", required_argument, NULL, ALT_TLS_PORT_OPT },
|
|
{ "listening-ip", required_argument, NULL, 'L' },
|
|
{ "relay-device", required_argument, NULL, 'i' },
|
|
{ "relay-ip", required_argument, NULL, 'E' },
|
|
{ "external-ip", required_argument, NULL, 'X' },
|
|
{ "relay-threads", required_argument, NULL, 'm' },
|
|
{ "min-port", required_argument, NULL, MIN_PORT_OPT },
|
|
{ "max-port", required_argument, NULL, MAX_PORT_OPT },
|
|
{ "lt-cred-mech", optional_argument, NULL, 'a' },
|
|
{ "no-auth", optional_argument, NULL, 'z' },
|
|
{ "user", required_argument, NULL, 'u' },
|
|
#if !defined(TURN_NO_SQLITE)
|
|
{ "userdb", required_argument, NULL, 'b' },
|
|
{ "db", required_argument, NULL, 'b' },
|
|
#endif
|
|
#if !defined(TURN_NO_PQ)
|
|
{ "psql-userdb", required_argument, NULL, 'e' },
|
|
{ "sql-userdb", required_argument, NULL, 'e' },
|
|
#endif
|
|
#if !defined(TURN_NO_MYSQL)
|
|
{ "mysql-userdb", required_argument, NULL, 'M' },
|
|
#endif
|
|
#if !defined(TURN_NO_MONGO)
|
|
{ "mongo-userdb", required_argument, NULL, 'J' },
|
|
#endif
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
{ "redis-userdb", required_argument, NULL, 'N' },
|
|
{ "redis-statsdb", required_argument, NULL, 'O' },
|
|
#endif
|
|
{ "use-auth-secret", optional_argument, NULL, AUTH_SECRET_OPT },
|
|
{ "static-auth-secret", required_argument, NULL, STATIC_AUTH_SECRET_VAL_OPT },
|
|
/* deprecated: */ { "secret-ts-exp-time", optional_argument, NULL, AUTH_SECRET_TS_EXP },
|
|
{ "realm", required_argument, NULL, 'r' },
|
|
{ "server-name", required_argument, NULL, SERVER_NAME_OPT },
|
|
{ "oauth", optional_argument, NULL, OAUTH_OPT },
|
|
{ "user-quota", required_argument, NULL, 'q' },
|
|
{ "total-quota", required_argument, NULL, 'Q' },
|
|
{ "max-bps", required_argument, NULL, 's' },
|
|
{ "bps-capacity", required_argument, NULL, 'B' },
|
|
{ "verbose", optional_argument, NULL, 'v' },
|
|
{ "Verbose", optional_argument, NULL, 'V' },
|
|
{ "daemon", optional_argument, NULL, 'o' },
|
|
{ "fingerprint", optional_argument, NULL, 'f' },
|
|
{ "check-origin-consistency", optional_argument, NULL, CHECK_ORIGIN_CONSISTENCY_OPT },
|
|
{ "no-udp", optional_argument, NULL, NO_UDP_OPT },
|
|
{ "no-tcp", optional_argument, NULL, NO_TCP_OPT },
|
|
{ "no-tls", optional_argument, NULL, NO_TLS_OPT },
|
|
{ "no-dtls", optional_argument, NULL, NO_DTLS_OPT },
|
|
{ "no-udp-relay", optional_argument, NULL, NO_UDP_RELAY_OPT },
|
|
{ "no-tcp-relay", optional_argument, NULL, NO_TCP_RELAY_OPT },
|
|
{ "stale-nonce", optional_argument, NULL, STALE_NONCE_OPT },
|
|
{ "stun-only", optional_argument, NULL, 'S' },
|
|
{ "no-stun", optional_argument, NULL, NO_STUN_OPT },
|
|
{ "cert", required_argument, NULL, CERT_FILE_OPT },
|
|
{ "pkey", required_argument, NULL, PKEY_FILE_OPT },
|
|
{ "pkey-pwd", required_argument, NULL, PKEY_PWD_OPT },
|
|
{ "log-file", required_argument, NULL, 'l' },
|
|
{ "no-stdout-log", optional_argument, NULL, NO_STDOUT_LOG_OPT },
|
|
{ "syslog", optional_argument, NULL, SYSLOG_OPT },
|
|
{ "simple-log", optional_argument, NULL, SIMPLE_LOG_OPT },
|
|
{ "aux-server", required_argument, NULL, AUX_SERVER_OPT },
|
|
{ "udp-self-balance", optional_argument, NULL, UDP_SELF_BALANCE_OPT },
|
|
{ "alternate-server", required_argument, NULL, ALTERNATE_SERVER_OPT },
|
|
{ "tls-alternate-server", required_argument, NULL, TLS_ALTERNATE_SERVER_OPT },
|
|
{ "rest-api-separator", required_argument, NULL, 'C' },
|
|
{ "max-allocate-timeout", required_argument, NULL, MAX_ALLOCATE_TIMEOUT_OPT },
|
|
{ "no-multicast-peers", optional_argument, NULL, NO_MULTICAST_PEERS_OPT },
|
|
{ "no-loopback-peers", optional_argument, NULL, NO_LOOPBACK_PEERS_OPT },
|
|
{ "allowed-peer-ip", required_argument, NULL, ALLOWED_PEER_IPS },
|
|
{ "denied-peer-ip", required_argument, NULL, DENIED_PEER_IPS },
|
|
{ "cipher-list", required_argument, NULL, CIPHER_LIST_OPT },
|
|
{ "pidfile", required_argument, NULL, PIDFILE_OPT },
|
|
{ "secure-stun", optional_argument, NULL, SECURE_STUN_OPT },
|
|
{ "CA-file", required_argument, NULL, CA_FILE_OPT },
|
|
{ "dh-file", required_argument, NULL, DH_FILE_OPT },
|
|
{ "sha256", optional_argument, NULL, SHA256_OPT },
|
|
{ "sha384", optional_argument, NULL, SHA384_OPT },
|
|
{ "sha512", optional_argument, NULL, SHA512_OPT },
|
|
{ "proc-user", required_argument, NULL, PROC_USER_OPT },
|
|
{ "proc-group", required_argument, NULL, PROC_GROUP_OPT },
|
|
{ "mobility", optional_argument, NULL, MOBILITY_OPT },
|
|
{ "no-cli", optional_argument, NULL, NO_CLI_OPT },
|
|
{ "cli-ip", required_argument, NULL, CLI_IP_OPT },
|
|
{ "cli-port", required_argument, NULL, CLI_PORT_OPT },
|
|
{ "cli-password", required_argument, NULL, CLI_PASSWORD_OPT },
|
|
{ "server-relay", optional_argument, NULL, SERVER_RELAY_OPT },
|
|
{ "cli-max-output-sessions", required_argument, NULL, CLI_MAX_SESSIONS_OPT },
|
|
{ "ec-curve-name", required_argument, NULL, EC_CURVE_NAME_OPT },
|
|
{ "dh566", optional_argument, NULL, DH566_OPT },
|
|
{ "dh2066", optional_argument, NULL, DH2066_OPT },
|
|
{ "ne", required_argument, NULL, NE_TYPE_OPT },
|
|
{ "no-sslv2", optional_argument, NULL, NO_SSLV2_OPT }, /* deprecated */
|
|
{ "no-sslv3", optional_argument, NULL, NO_SSLV3_OPT },
|
|
{ "no-tlsv1", optional_argument, NULL, NO_TLSV1_OPT },
|
|
{ "no-tlsv1_1", optional_argument, NULL, NO_TLSV1_1_OPT },
|
|
{ "no-tlsv1_2", optional_argument, NULL, NO_TLSV1_2_OPT },
|
|
{ NULL, no_argument, NULL, 0 }
|
|
};
|
|
|
|
static const struct myoption admin_long_options[] = {
|
|
{"generate-encrypted-password", no_argument, NULL, 'P' },
|
|
{ "key", no_argument, NULL, 'k' },
|
|
{ "add", no_argument, NULL, 'a' },
|
|
{ "delete", no_argument, NULL, 'd' },
|
|
{ "list", no_argument, NULL, 'l' },
|
|
{ "list-admin", no_argument, NULL, 'L' },
|
|
{ "set-secret", required_argument, NULL, 's' },
|
|
{ "show-secret", no_argument, NULL, 'S' },
|
|
{ "delete-secret", required_argument, NULL, 'X' },
|
|
{ "delete-all-secrets", no_argument, NULL, DEL_ALL_AUTH_SECRETS_OPT },
|
|
{ "add-admin", no_argument, NULL, 'A' },
|
|
{ "delete-admin", no_argument, NULL, 'D' },
|
|
#if !defined(TURN_NO_SQLITE)
|
|
{ "userdb", required_argument, NULL, 'b' },
|
|
{ "db", required_argument, NULL, 'b' },
|
|
#endif
|
|
#if !defined(TURN_NO_PQ)
|
|
{ "psql-userdb", required_argument, NULL, 'e' },
|
|
{ "sql-userdb", required_argument, NULL, 'e' },
|
|
#endif
|
|
#if !defined(TURN_NO_MYSQL)
|
|
{ "mysql-userdb", required_argument, NULL, 'M' },
|
|
#endif
|
|
#if !defined(TURN_NO_MONGO)
|
|
{ "mongo-userdb", required_argument, NULL, 'J' },
|
|
#endif
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
{ "redis-userdb", required_argument, NULL, 'N' },
|
|
#endif
|
|
{ "user", required_argument, NULL, 'u' },
|
|
{ "realm", required_argument, NULL, 'r' },
|
|
{ "password", required_argument, NULL, 'p' },
|
|
{ "sha256", no_argument, NULL, 'H' },
|
|
{ "sha384", no_argument, NULL, 'Y' },
|
|
{ "sha512", no_argument, NULL, 'K' },
|
|
{ "add-origin", no_argument, NULL, 'O' },
|
|
{ "del-origin", no_argument, NULL, 'R' },
|
|
{ "list-origins", required_argument, NULL, 'I' },
|
|
{ "origin", required_argument, NULL, 'o' },
|
|
{ "set-realm-option", no_argument, NULL, 'g' },
|
|
{ "list-realm-option", no_argument, NULL, 'G' },
|
|
{ "user-quota", required_argument, NULL, ADMIN_USER_QUOTA_OPT },
|
|
{ "total-quota", required_argument, NULL, ADMIN_TOTAL_QUOTA_OPT },
|
|
{ "max-bps", required_argument, NULL, ADMIN_MAX_BPS_OPT },
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ NULL, no_argument, NULL, 0 }
|
|
};
|
|
|
|
static int get_bool_value(const char* s)
|
|
{
|
|
if(!s || !(s[0])) return 1;
|
|
if(s[0]=='0' || s[0]=='n' || s[0]=='N' || s[0]=='f' || s[0]=='F') return 0;
|
|
if(s[0]=='y' || s[0]=='Y' || s[0]=='t' || s[0]=='T') return 1;
|
|
if(s[0]>'0' && s[0]<='9') return 1;
|
|
if(!strcmp(s,"off") || !strcmp(s,"OFF") || !strcmp(s,"Off")) return 0;
|
|
if(!strcmp(s,"on") || !strcmp(s,"ON") || !strcmp(s,"On")) return 1;
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown boolean value: %s. You can use on/off, yes/no, 1/0, true/false.\n",s);
|
|
exit(-1);
|
|
}
|
|
|
|
static void set_option(int c, char *value)
|
|
{
|
|
if(value && value[0]=='=') {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: option -%c is possibly used incorrectly. The short form of the option must be used as this: -%c <value>, no \'equals\' sign may be used, that sign is used only with long form options (like --user=<username>).\n",(char)c,(char)c);
|
|
}
|
|
|
|
switch (c) {
|
|
case SERVER_NAME_OPT:
|
|
STRCPY(turn_params.oauth_server_name,value);
|
|
break;
|
|
case OAUTH_OPT:
|
|
turn_params.oauth = get_bool_value(value);
|
|
break;
|
|
case NO_SSLV2_OPT:
|
|
//deprecated
|
|
break;
|
|
case NO_SSLV3_OPT:
|
|
turn_params.no_sslv3 = get_bool_value(value);
|
|
break;
|
|
case NO_TLSV1_OPT:
|
|
turn_params.no_tlsv1 = get_bool_value(value);
|
|
break;
|
|
case NO_TLSV1_1_OPT:
|
|
turn_params.no_tlsv1_1 = get_bool_value(value);
|
|
break;
|
|
case NO_TLSV1_2_OPT:
|
|
turn_params.no_tlsv1_2 = get_bool_value(value);
|
|
break;
|
|
case NE_TYPE_OPT:
|
|
{
|
|
int ne = atoi(value);
|
|
if((ne<(int)NEV_MIN)||(ne>(int)NEV_MAX)) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "ERROR: wrong version of the network engine: %d\n",ne);
|
|
}
|
|
turn_params.net_engine_version = (NET_ENG_VERSION)ne;
|
|
}
|
|
break;
|
|
case DH566_OPT:
|
|
if(get_bool_value(value))
|
|
turn_params.dh_key_size = DH_566;
|
|
break;
|
|
case DH2066_OPT:
|
|
if(get_bool_value(value))
|
|
turn_params.dh_key_size = DH_2066;
|
|
break;
|
|
case EC_CURVE_NAME_OPT:
|
|
STRCPY(turn_params.ec_curve_name,value);
|
|
break;
|
|
case CLI_MAX_SESSIONS_OPT:
|
|
cli_max_output_sessions = atoi(value);
|
|
break;
|
|
case SERVER_RELAY_OPT:
|
|
turn_params.server_relay = get_bool_value(value);
|
|
break;
|
|
case MOBILITY_OPT:
|
|
turn_params.mobility = get_bool_value(value);
|
|
break;
|
|
case NO_CLI_OPT:
|
|
use_cli = !get_bool_value(value);
|
|
break;
|
|
case CLI_IP_OPT:
|
|
if(make_ioa_addr((const u08bits*)value,0,&cli_addr)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"Cannot set cli address: %s\n",value);
|
|
} else{
|
|
cli_addr_set = 1;
|
|
}
|
|
break;
|
|
case CLI_PORT_OPT:
|
|
cli_port = atoi(value);
|
|
break;
|
|
case CLI_PASSWORD_OPT:
|
|
STRCPY(cli_password,value);
|
|
break;
|
|
case PROC_USER_OPT: {
|
|
struct passwd* pwd = getpwnam(value);
|
|
if(!pwd) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown user name: %s\n",value);
|
|
exit(-1);
|
|
} else {
|
|
procuserid = pwd->pw_uid;
|
|
procuserid_set = 1;
|
|
STRCPY(procusername,value);
|
|
}
|
|
}
|
|
break;
|
|
case PROC_GROUP_OPT: {
|
|
struct group* gr = getgrnam(value);
|
|
if(!gr) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown group name: %s\n",value);
|
|
exit(-1);
|
|
} else {
|
|
procgroupid = gr->gr_gid;
|
|
procgroupid_set = 1;
|
|
STRCPY(procgroupname,value);
|
|
}
|
|
}
|
|
break;
|
|
case 'i':
|
|
STRCPY(turn_params.relay_ifname, value);
|
|
break;
|
|
case 'm':
|
|
#if defined(OPENSSL_THREADS)
|
|
if(atoi(value)>MAX_NUMBER_OF_GENERAL_RELAY_SERVERS) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: max number of relay threads is 128.\n");
|
|
turn_params.general_relay_servers_number = MAX_NUMBER_OF_GENERAL_RELAY_SERVERS;
|
|
} else if(atoi(value)<=0) {
|
|
turn_params.general_relay_servers_number = 0;
|
|
} else {
|
|
turn_params.general_relay_servers_number = atoi(value);
|
|
}
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: OpenSSL version is too old OR does not support threading,\n I am using single thread for relaying.\n");
|
|
#endif
|
|
break;
|
|
case 'd':
|
|
STRCPY(turn_params.listener_ifname, value);
|
|
break;
|
|
case 'p':
|
|
turn_params.listener_port = atoi(value);
|
|
break;
|
|
case TLS_PORT_OPT:
|
|
turn_params.tls_listener_port = atoi(value);
|
|
break;
|
|
case ALT_PORT_OPT:
|
|
turn_params.alt_listener_port = atoi(value);
|
|
break;
|
|
case ALT_TLS_PORT_OPT:
|
|
turn_params.alt_tls_listener_port = atoi(value);
|
|
break;
|
|
case MIN_PORT_OPT:
|
|
turn_params.min_port = atoi(value);
|
|
break;
|
|
case MAX_PORT_OPT:
|
|
turn_params.max_port = atoi(value);
|
|
break;
|
|
case SECURE_STUN_OPT:
|
|
turn_params.secure_stun = get_bool_value(value);
|
|
break;
|
|
case SHA256_OPT:
|
|
if(get_bool_value(value))
|
|
turn_params.shatype = SHATYPE_SHA256;
|
|
break;
|
|
case SHA384_OPT:
|
|
if(get_bool_value(value))
|
|
turn_params.shatype = SHATYPE_SHA384;
|
|
break;
|
|
case SHA512_OPT:
|
|
if(get_bool_value(value))
|
|
turn_params.shatype = SHATYPE_SHA512;
|
|
break;
|
|
case NO_MULTICAST_PEERS_OPT:
|
|
turn_params.no_multicast_peers = get_bool_value(value);
|
|
break;
|
|
case NO_LOOPBACK_PEERS_OPT:
|
|
turn_params.no_loopback_peers = get_bool_value(value);
|
|
break;
|
|
case STALE_NONCE_OPT:
|
|
turn_params.stale_nonce = get_bool_value(value);
|
|
break;
|
|
case MAX_ALLOCATE_TIMEOUT_OPT:
|
|
TURN_MAX_ALLOCATE_TIMEOUT = atoi(value);
|
|
TURN_MAX_ALLOCATE_TIMEOUT_STUN_ONLY = atoi(value);
|
|
break;
|
|
case 'S':
|
|
turn_params.stun_only = get_bool_value(value);
|
|
break;
|
|
case NO_STUN_OPT:
|
|
turn_params.no_stun = get_bool_value(value);
|
|
break;
|
|
case 'L':
|
|
add_listener_addr(value);
|
|
break;
|
|
case 'E':
|
|
add_relay_addr(value);
|
|
break;
|
|
case 'X':
|
|
if(value) {
|
|
char *div = strchr(value,'/');
|
|
if(div) {
|
|
char *nval=turn_strdup(value);
|
|
div = strchr(nval,'/');
|
|
div[0]=0;
|
|
++div;
|
|
ioa_addr apub,apriv;
|
|
if(make_ioa_addr((const u08bits*)nval,0,&apub)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"-X : Wrong address format: %s\n",nval);
|
|
} else {
|
|
if(make_ioa_addr((const u08bits*)div,0,&apriv)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"-X : Wrong address format: %s\n",div);
|
|
} else {
|
|
ioa_addr_add_mapping(&apub,&apriv);
|
|
}
|
|
}
|
|
turn_free(nval,strlen(nval)+1);
|
|
} else {
|
|
if(turn_params.external_ip) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "You cannot define external IP more than once in the configuration\n");
|
|
} else {
|
|
turn_params.external_ip = (ioa_addr*)allocate_super_memory_engine(turn_params.listener.ioa_eng, sizeof(ioa_addr));
|
|
if(make_ioa_addr((const u08bits*)value,0,turn_params.external_ip)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"-X : Wrong address format: %s\n",value);
|
|
turn_free(turn_params.external_ip,sizeof(ioa_addr));
|
|
turn_params.external_ip = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 'v':
|
|
if(get_bool_value(value)) {
|
|
turn_params.verbose = TURN_VERBOSE_NORMAL;
|
|
} else {
|
|
turn_params.verbose = TURN_VERBOSE_NONE;
|
|
}
|
|
break;
|
|
case 'V':
|
|
if(get_bool_value(value)) {
|
|
turn_params.verbose = TURN_VERBOSE_EXTRA;
|
|
}
|
|
break;
|
|
case 'o':
|
|
turn_params.turn_daemon = get_bool_value(value);
|
|
break;
|
|
case 'a':
|
|
if (get_bool_value(value)) {
|
|
turn_params.ct = TURN_CREDENTIALS_LONG_TERM;
|
|
use_lt_credentials=1;
|
|
} else {
|
|
turn_params.ct = TURN_CREDENTIALS_UNDEFINED;
|
|
use_lt_credentials=0;
|
|
}
|
|
break;
|
|
case 'z':
|
|
if (!get_bool_value(value)) {
|
|
turn_params.ct = TURN_CREDENTIALS_UNDEFINED;
|
|
anon_credentials = 0;
|
|
} else {
|
|
turn_params.ct = TURN_CREDENTIALS_NONE;
|
|
anon_credentials = 1;
|
|
}
|
|
break;
|
|
case 'f':
|
|
turn_params.fingerprint = get_bool_value(value);
|
|
break;
|
|
case 'u':
|
|
add_static_user_account(value);
|
|
break;
|
|
#if !defined(TURN_NO_SQLITE)
|
|
case 'b':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_SQLITE;
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_PQ)
|
|
case 'e':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_PQ;
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_MYSQL)
|
|
case 'M':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MYSQL;
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_MONGO)
|
|
case 'J':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MONGO;
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
case 'N':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_REDIS;
|
|
break;
|
|
case 'O':
|
|
STRCPY(turn_params.redis_statsdb, value);
|
|
turn_params.use_redis_statsdb = 1;
|
|
break;
|
|
#endif
|
|
case AUTH_SECRET_OPT:
|
|
turn_params.use_auth_secret_with_timestamp = 1;
|
|
break;
|
|
case STATIC_AUTH_SECRET_VAL_OPT:
|
|
add_to_secrets_list(&turn_params.default_users_db.ram_db.static_auth_secrets,value);
|
|
turn_params.use_auth_secret_with_timestamp = 1;
|
|
break;
|
|
case AUTH_SECRET_TS_EXP:
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: Option --secret-ts-exp-time deprecated and has no effect.\n");
|
|
break;
|
|
case 'r':
|
|
set_default_realm_name(value);
|
|
break;
|
|
case 'q':
|
|
turn_params.total_quota = (vint)atoi(value);
|
|
get_realm(NULL)->options.perf_options.user_quota = atoi(value);
|
|
break;
|
|
case 'Q':
|
|
turn_params.user_quota = (vint)atoi(value);
|
|
get_realm(NULL)->options.perf_options.total_quota = atoi(value);
|
|
break;
|
|
case 's':
|
|
turn_params.max_bps = (band_limit_t)strtoul(value,NULL,10);
|
|
get_realm(NULL)->options.perf_options.max_bps = (band_limit_t)strtoul(value,NULL,10);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%lu bytes per second allowed per session\n",(unsigned long)turn_params.max_bps);
|
|
break;
|
|
case 'B':
|
|
turn_params.bps_capacity = (band_limit_t)strtoul(value,NULL,10);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%lu bytes per second allowed, combined server capacity\n",(unsigned long)turn_params.bps_capacity);
|
|
break;
|
|
case CHECK_ORIGIN_CONSISTENCY_OPT:
|
|
turn_params.check_origin = get_bool_value(value);
|
|
break;
|
|
case NO_UDP_OPT:
|
|
turn_params.no_udp = get_bool_value(value);
|
|
break;
|
|
case NO_TCP_OPT:
|
|
turn_params.no_tcp = get_bool_value(value);
|
|
break;
|
|
case NO_UDP_RELAY_OPT:
|
|
turn_params.no_udp_relay = get_bool_value(value);
|
|
break;
|
|
case NO_TCP_RELAY_OPT:
|
|
turn_params.no_tcp_relay = get_bool_value(value);
|
|
break;
|
|
case NO_TLS_OPT:
|
|
#if !TLS_SUPPORTED
|
|
turn_params.no_tls = 1;
|
|
#else
|
|
turn_params.no_tls = get_bool_value(value);
|
|
#endif
|
|
break;
|
|
case NO_DTLS_OPT:
|
|
#if DTLS_SUPPORTED
|
|
turn_params.no_dtls = get_bool_value(value);
|
|
#else
|
|
turn_params.no_dtls = 1;
|
|
#endif
|
|
break;
|
|
case CERT_FILE_OPT:
|
|
STRCPY(turn_params.cert_file,value);
|
|
break;
|
|
case CA_FILE_OPT:
|
|
STRCPY(turn_params.ca_cert_file,value);
|
|
break;
|
|
case DH_FILE_OPT:
|
|
STRCPY(turn_params.dh_file,value);
|
|
break;
|
|
case PKEY_FILE_OPT:
|
|
STRCPY(turn_params.pkey_file,value);
|
|
break;
|
|
case PKEY_PWD_OPT:
|
|
STRCPY(turn_params.tls_password,value);
|
|
break;
|
|
case ALTERNATE_SERVER_OPT:
|
|
add_alternate_server(value);
|
|
break;
|
|
case AUX_SERVER_OPT:
|
|
add_aux_server(value);
|
|
break;
|
|
case UDP_SELF_BALANCE_OPT:
|
|
turn_params.udp_self_balance = get_bool_value(value);
|
|
break;
|
|
case TLS_ALTERNATE_SERVER_OPT:
|
|
add_tls_alternate_server(value);
|
|
break;
|
|
case ALLOWED_PEER_IPS:
|
|
if (add_ip_list_range(value, NULL, &turn_params.ip_whitelist) == 0) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "White listing: %s\n", value);
|
|
break;
|
|
case DENIED_PEER_IPS:
|
|
if (add_ip_list_range(value, NULL, &turn_params.ip_blacklist) == 0) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Black listing: %s\n", value);
|
|
break;
|
|
case CIPHER_LIST_OPT:
|
|
STRCPY(turn_params.cipher_list,value);
|
|
break;
|
|
case PIDFILE_OPT:
|
|
STRCPY(turn_params.pidfile,value);
|
|
break;
|
|
case 'C':
|
|
if(value && *value) {
|
|
turn_params.rest_api_separator=*value;
|
|
}
|
|
break;
|
|
/* these options have been already taken care of before: */
|
|
case 'l':
|
|
case NO_STDOUT_LOG_OPT:
|
|
case SYSLOG_OPT:
|
|
case SIMPLE_LOG_OPT:
|
|
case 'c':
|
|
case 'n':
|
|
case 'h':
|
|
break;
|
|
default:
|
|
fprintf(stderr,"\n%s\n", Usage);
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
static int parse_arg_string(char *sarg, int *c, char **value)
|
|
{
|
|
int i = 0;
|
|
char *name = sarg;
|
|
while(*sarg) {
|
|
if((*sarg==' ') || (*sarg=='=') || (*sarg=='\t')) {
|
|
*sarg=0;
|
|
do {
|
|
++sarg;
|
|
} while((*sarg==' ') || (*sarg=='=') || (*sarg=='\t'));
|
|
*value = sarg;
|
|
break;
|
|
}
|
|
++sarg;
|
|
*value=sarg;
|
|
}
|
|
|
|
|
|
if(value && *value && **value=='\"') {
|
|
*value += 1;
|
|
size_t len = strlen(*value);
|
|
while(len>0 && (
|
|
((*value)[len-1]=='\n') ||
|
|
((*value)[len-1]=='\r') ||
|
|
((*value)[len-1]==' ') ||
|
|
((*value)[len-1]=='\t')
|
|
) ) {
|
|
(*value)[--len]=0;
|
|
}
|
|
if(len>0 && (*value)[len-1]=='\"') {
|
|
(*value)[--len]=0;
|
|
}
|
|
}
|
|
|
|
while(long_options[i].name) {
|
|
if(strcmp(long_options[i].name,name)) {
|
|
++i;
|
|
continue;
|
|
}
|
|
*c=long_options[i].val;
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void read_config_file(int argc, char **argv, int pass)
|
|
{
|
|
static char config_file[1025] = DEFAULT_CONFIG_FILE;
|
|
|
|
if(pass == 0) {
|
|
|
|
if (argv) {
|
|
int i = 0;
|
|
for (i = 0; i < argc; i++) {
|
|
if (!strcmp(argv[i], "-c")) {
|
|
if (i < argc - 1) {
|
|
STRCPY(config_file, argv[i + 1]);
|
|
} else {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Wrong usage of -c option\n");
|
|
}
|
|
} else if (!strcmp(argv[i], "-n")) {
|
|
turn_params.do_not_use_config_file = 1;
|
|
config_file[0]=0;
|
|
return;
|
|
} else if (!strcmp(argv[i], "-h")) {
|
|
printf("\n%s\n",Usage);
|
|
exit(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!turn_params.do_not_use_config_file && config_file[0]) {
|
|
|
|
FILE *f = NULL;
|
|
char *full_path_to_config_file = NULL;
|
|
|
|
full_path_to_config_file = find_config_file(config_file, 1);
|
|
if (full_path_to_config_file)
|
|
f = fopen(full_path_to_config_file, "r");
|
|
|
|
if (f && full_path_to_config_file) {
|
|
|
|
char sbuf[1025];
|
|
char sarg[1035];
|
|
|
|
for (;;) {
|
|
char *s = fgets(sbuf, sizeof(sbuf) - 1, f);
|
|
if (!s)
|
|
break;
|
|
s = skip_blanks(s);
|
|
if (s[0] == '#')
|
|
continue;
|
|
if (!s[0])
|
|
continue;
|
|
size_t slen = strlen(s);
|
|
while (slen && ((s[slen - 1] == 10) || (s[slen - 1] == 13)))
|
|
s[--slen] = 0;
|
|
if (slen) {
|
|
int c = 0;
|
|
char *value = NULL;
|
|
STRCPY(sarg, s);
|
|
if (parse_arg_string(sarg, &c, &value) < 0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Bad configuration format: %s\n",
|
|
sarg);
|
|
} else if((pass == 0) && (c == 'l')) {
|
|
set_logfile(value);
|
|
} else if((pass==0) && (c==NO_STDOUT_LOG_OPT)) {
|
|
set_no_stdout_log(get_bool_value(value));
|
|
} else if((pass==0) && (c==SYSLOG_OPT)) {
|
|
set_log_to_syslog(get_bool_value(value));
|
|
} else if((pass==0) && (c==SIMPLE_LOG_OPT)) {
|
|
set_simple_log(get_bool_value(value));
|
|
} else if((pass == 0) && (c != 'u')) {
|
|
set_option(c, value);
|
|
} else if((pass > 0) && (c == 'u')) {
|
|
set_option(c, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
} else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: Cannot find config file: %s. Default and command-line settings will be used.\n",
|
|
config_file);
|
|
}
|
|
}
|
|
|
|
static int adminmain(int argc, char **argv)
|
|
{
|
|
int c = 0;
|
|
|
|
TURNADMIN_COMMAND_TYPE ct = TA_COMMAND_UNKNOWN;
|
|
|
|
int is_admin = 0;
|
|
|
|
u08bits user[STUN_MAX_USERNAME_SIZE+1]="\0";
|
|
u08bits realm[STUN_MAX_REALM_SIZE+1]="\0";
|
|
u08bits pwd[STUN_MAX_PWD_SIZE+1]="\0";
|
|
u08bits secret[AUTH_SECRET_SIZE+1]="\0";
|
|
u08bits origin[STUN_MAX_ORIGIN_SIZE+1]="\0";
|
|
perf_options_t po = {(band_limit_t)-1,-1,-1};
|
|
|
|
struct uoptions uo;
|
|
uo.u.m = admin_long_options;
|
|
|
|
int print_enc_password = 0;
|
|
|
|
while (((c = getopt_long(argc, argv, ADMIN_OPTIONS, uo.u.o, NULL)) != -1)) {
|
|
switch (c){
|
|
case 'P':
|
|
if(pwd[0]) {
|
|
char result[257];
|
|
generate_new_enc_password((char*)pwd, result);
|
|
printf("%s\n",result);
|
|
exit(0);
|
|
}
|
|
print_enc_password = 1;
|
|
break;
|
|
case 'g':
|
|
ct = TA_SET_REALM_OPTION;
|
|
break;
|
|
case 'G':
|
|
ct = TA_LIST_REALM_OPTIONS;
|
|
break;
|
|
case ADMIN_USER_QUOTA_OPT:
|
|
po.user_quota = (vint)atoi(optarg);
|
|
break;
|
|
case ADMIN_TOTAL_QUOTA_OPT:
|
|
po.total_quota = (vint)atoi(optarg);
|
|
break;
|
|
case ADMIN_MAX_BPS_OPT:
|
|
po.max_bps = (vint)atoi(optarg);
|
|
break;
|
|
case 'O':
|
|
ct = TA_ADD_ORIGIN;
|
|
break;
|
|
case 'R':
|
|
ct = TA_DEL_ORIGIN;
|
|
break;
|
|
case 'I':
|
|
ct = TA_LIST_ORIGINS;
|
|
break;
|
|
case 'o':
|
|
STRCPY(origin,optarg);
|
|
break;
|
|
case 'k':
|
|
ct = TA_PRINT_KEY;
|
|
break;
|
|
case 'a':
|
|
ct = TA_UPDATE_USER;
|
|
break;
|
|
case 'd':
|
|
ct = TA_DELETE_USER;
|
|
break;
|
|
case 'A':
|
|
ct = TA_UPDATE_USER;
|
|
is_admin = 1;
|
|
break;
|
|
case 'D':
|
|
ct = TA_DELETE_USER;
|
|
is_admin = 1;
|
|
break;
|
|
case 'l':
|
|
ct = TA_LIST_USERS;
|
|
break;
|
|
case 'L':
|
|
ct = TA_LIST_USERS;
|
|
is_admin = 1;
|
|
break;
|
|
case 's':
|
|
ct = TA_SET_SECRET;
|
|
STRCPY(secret,optarg);
|
|
break;
|
|
case 'S':
|
|
ct = TA_SHOW_SECRET;
|
|
break;
|
|
case 'X':
|
|
ct = TA_DEL_SECRET;
|
|
if(optarg)
|
|
STRCPY(secret,optarg);
|
|
break;
|
|
case DEL_ALL_AUTH_SECRETS_OPT:
|
|
ct = TA_DEL_SECRET;
|
|
break;
|
|
#if !defined(TURN_NO_SQLITE)
|
|
case 'b':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_SQLITE;
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_PQ)
|
|
case 'e':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_PQ;
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_MYSQL)
|
|
case 'M':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MYSQL;
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_MONGO)
|
|
case 'J':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MONGO;
|
|
break;
|
|
#endif
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
case 'N':
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
|
|
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_REDIS;
|
|
break;
|
|
#endif
|
|
case 'u':
|
|
STRCPY(user,optarg);
|
|
if(SASLprep((u08bits*)user)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong user name: %s\n",user);
|
|
exit(-1);
|
|
}
|
|
break;
|
|
case 'r':
|
|
set_default_realm_name(optarg);
|
|
STRCPY(realm,optarg);
|
|
if(SASLprep((u08bits*)realm)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong realm: %s\n",realm);
|
|
exit(-1);
|
|
}
|
|
break;
|
|
case 'p':
|
|
STRCPY(pwd,optarg);
|
|
if(SASLprep((u08bits*)pwd)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong password: %s\n",pwd);
|
|
exit(-1);
|
|
}
|
|
if(print_enc_password) {
|
|
char result[257];
|
|
generate_new_enc_password((char*)pwd, result);
|
|
printf("%s\n",result);
|
|
exit(0);
|
|
}
|
|
break;
|
|
case 'H':
|
|
if(get_bool_value(optarg))
|
|
turn_params.shatype = SHATYPE_SHA256;
|
|
break;
|
|
case 'Y':
|
|
if(get_bool_value(optarg))
|
|
turn_params.shatype = SHATYPE_SHA384;
|
|
break;
|
|
case 'K':
|
|
if(get_bool_value(optarg))
|
|
turn_params.shatype = SHATYPE_SHA512;
|
|
break;
|
|
case 'h':
|
|
printf("\n%s\n", AdminUsage);
|
|
exit(0);
|
|
break;
|
|
default:
|
|
fprintf(stderr,"\n%s\n", AdminUsage);
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
#if !defined(TURN_NO_SQLITE)
|
|
if(!strlen(turn_params.default_users_db.persistent_users_db.userdb) && (turn_params.default_users_db.userdb_type == TURN_USERDB_TYPE_SQLITE))
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,DEFAULT_USERDB_FILE);
|
|
#endif
|
|
|
|
if(ct == TA_COMMAND_UNKNOWN) {
|
|
fprintf(stderr,"\n%s\n", AdminUsage);
|
|
exit(-1);
|
|
}
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if(argc != 0) {
|
|
fprintf(stderr,"\n%s\n", AdminUsage);
|
|
exit(-1);
|
|
}
|
|
|
|
return adminuser(user, realm, pwd, secret, origin, ct, &po, is_admin);
|
|
}
|
|
|
|
static void print_features(unsigned long mfn)
|
|
{
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\nRFC 3489/5389/5766/5780/6062/6156 STUN/TURN Server\nVersion %s\n",TURN_SOFTWARE);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\nMax number of open files/sockets allowed for this process: %lu\n",mfn);
|
|
if(turn_params.net_engine_version == NEV_UDP_SOCKET_PER_ENDPOINT)
|
|
mfn = mfn/3;
|
|
else
|
|
mfn = mfn/2;
|
|
mfn = ((unsigned long)(mfn/500))*500;
|
|
if(mfn<500)
|
|
mfn = 500;
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\nDue to the open files/sockets limitation,\nmax supported number of TURN Sessions possible is: %lu (approximately)\n",mfn);
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n\n==== Show him the instruments, Practical Frost: ====\n\n");
|
|
|
|
#if !TLS_SUPPORTED
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "TLS is not supported\n");
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "TLS supported\n");
|
|
#endif
|
|
|
|
#if !DTLS_SUPPORTED
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "DTLS is not supported\n");
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "DTLS supported\n");
|
|
#endif
|
|
|
|
#if defined(TURN_NO_GCM)
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "AEAD is not supported\n");
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "AEAD supported\n");
|
|
#endif
|
|
|
|
#if !defined(TURN_NO_SQLITE)
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "SQLite supported, default database location is %s\n",DEFAULT_USERDB_FILE);
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "SQLite is not supported\n");
|
|
#endif
|
|
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Redis supported\n");
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Redis is not supported\n");
|
|
#endif
|
|
|
|
#if !defined(TURN_NO_PQ)
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "PostgreSQL supported\n");
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "PostgreSQL is not supported\n");
|
|
#endif
|
|
|
|
#if !defined(TURN_NO_MYSQL)
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MySQL supported\n");
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MySQL is not supported\n");
|
|
#endif
|
|
|
|
#if !defined(TURN_NO_MONGO)
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MongoDB supported\n");
|
|
#else
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MongoDB is not supported\n");
|
|
#endif
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "OpenSSL compile-time version: %s\n",OPENSSL_VERSION_TEXT);
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Default Net Engine version: %d (%s)\n\n=====================================================\n\n", (int)turn_params.net_engine_version, turn_params.net_engine_version_txt[(int)turn_params.net_engine_version]);
|
|
|
|
}
|
|
|
|
#if defined(__linux__) || defined(__LINUX__) || defined(__linux) || defined(linux__) || defined(LINUX) || defined(__LINUX) || defined(LINUX__)
|
|
#include <linux/version.h>
|
|
#endif
|
|
|
|
static void set_network_engine(void)
|
|
{
|
|
if(turn_params.net_engine_version != NEV_UNKNOWN)
|
|
return;
|
|
turn_params.net_engine_version = NEV_UDP_SOCKET_PER_ENDPOINT;
|
|
#if defined(SO_REUSEPORT)
|
|
#if defined(__linux__) || defined(__LINUX__) || defined(__linux) || defined(linux__) || defined(LINUX) || defined(__LINUX) || defined(LINUX__)
|
|
turn_params.net_engine_version = NEV_UDP_SOCKET_PER_THREAD;
|
|
#else /* BSD ? */
|
|
turn_params.net_engine_version = NEV_UDP_SOCKET_PER_SESSION;
|
|
#endif /* Linux */
|
|
#else /* defined(SO_REUSEPORT) */
|
|
#if defined(__linux__) || defined(__LINUX__) || defined(__linux) || defined(linux__) || defined(LINUX) || defined(__LINUX) || defined(LINUX__)
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
|
|
//net_engine_version = NEV_UDP_SOCKET_PER_SESSION;
|
|
turn_params.net_engine_version = NEV_UDP_SOCKET_PER_ENDPOINT;
|
|
#else
|
|
turn_params.net_engine_version = NEV_UDP_SOCKET_PER_ENDPOINT;
|
|
#endif /* Linux version */
|
|
#endif /* Linux */
|
|
#endif /* defined(SO_REUSEPORT) */
|
|
|
|
}
|
|
|
|
static void drop_privileges(void)
|
|
{
|
|
if(procgroupid_set) {
|
|
if(getgid() != procgroupid) {
|
|
if (setgid(procgroupid) != 0) {
|
|
perror("setgid: Unable to change group privileges");
|
|
exit(-1);
|
|
} else {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "New GID: %s(%lu)\n", procgroupname, (unsigned long)procgroupid);
|
|
}
|
|
} else {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Keep GID: %s(%lu)\n", procgroupname, (unsigned long)procgroupid);
|
|
}
|
|
}
|
|
|
|
if(procuserid_set) {
|
|
if(procuserid != getuid()) {
|
|
if (setuid(procuserid) != 0) {
|
|
perror("setuid: Unable to change user privileges");
|
|
exit(-1);
|
|
} else {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "New UID: %s(%lu)\n", procusername, (unsigned long)procuserid);
|
|
}
|
|
} else {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Keep UID: %s(%lu)\n", procusername, (unsigned long)procuserid);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void init_domain(void)
|
|
{
|
|
#if !defined(TURN_NO_GETDOMAINNAME)
|
|
if(getdomainname(turn_params.domain,sizeof(turn_params.domain)-1)<0) {
|
|
turn_params.domain[0]=0;
|
|
} else if(!strcmp(turn_params.domain,"(none)")) {
|
|
turn_params.domain[0]=0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int c = 0;
|
|
|
|
IS_TURN_SERVER = 1;
|
|
|
|
set_execdir();
|
|
|
|
init_super_memory();
|
|
|
|
#if !defined(TURN_NO_HIREDIS)
|
|
redis_async_init();
|
|
#endif
|
|
|
|
init_domain();
|
|
create_default_realm();
|
|
|
|
init_turn_server_addrs_list(&turn_params.alternate_servers_list);
|
|
init_turn_server_addrs_list(&turn_params.tls_alternate_servers_list);
|
|
init_turn_server_addrs_list(&turn_params.aux_servers_list);
|
|
|
|
set_network_engine();
|
|
|
|
init_listener();
|
|
init_secrets_list(&turn_params.default_users_db.ram_db.static_auth_secrets);
|
|
init_dynamic_ip_lists();
|
|
|
|
if (!strstr(argv[0], "turnadmin")) {
|
|
|
|
struct uoptions uo;
|
|
uo.u.m = long_options;
|
|
|
|
while (((c = getopt_long(argc, argv, OPTIONS, uo.u.o, NULL)) != -1)) {
|
|
switch (c){
|
|
case 'l':
|
|
set_logfile(optarg);
|
|
break;
|
|
case NO_STDOUT_LOG_OPT:
|
|
set_no_stdout_log(get_bool_value(optarg));
|
|
break;
|
|
case SYSLOG_OPT:
|
|
set_log_to_syslog(get_bool_value(optarg));
|
|
break;
|
|
case SIMPLE_LOG_OPT:
|
|
set_simple_log(get_bool_value(optarg));
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
}
|
|
|
|
optind = 0;
|
|
|
|
#if !TLS_SUPPORTED
|
|
turn_params.no_tls = 1;
|
|
#endif
|
|
|
|
#if !DTLS_SUPPORTED
|
|
turn_params.no_dtls = 1;
|
|
#endif
|
|
|
|
#if defined(_SC_NPROCESSORS_ONLN)
|
|
|
|
{
|
|
turn_params.cpus = (long)sysconf(_SC_NPROCESSORS_CONF);
|
|
|
|
if(turn_params.cpus<DEFAULT_CPUS_NUMBER)
|
|
turn_params.cpus = DEFAULT_CPUS_NUMBER;
|
|
else if(turn_params.cpus>MAX_NUMBER_OF_GENERAL_RELAY_SERVERS)
|
|
turn_params.cpus = MAX_NUMBER_OF_GENERAL_RELAY_SERVERS;
|
|
|
|
turn_params.general_relay_servers_number = (turnserver_id)turn_params.cpus;
|
|
}
|
|
|
|
#endif
|
|
|
|
ns_bzero(&turn_params.default_users_db,sizeof(default_users_db_t));
|
|
turn_params.default_users_db.ram_db.static_accounts = ur_string_map_create(turn_free_simple);
|
|
|
|
if(strstr(argv[0],"turnadmin"))
|
|
return adminmain(argc,argv);
|
|
|
|
{
|
|
unsigned long mfn = set_system_parameters(1);
|
|
|
|
print_features(mfn);
|
|
}
|
|
|
|
read_config_file(argc,argv,0);
|
|
|
|
struct uoptions uo;
|
|
uo.u.m = long_options;
|
|
|
|
while (((c = getopt_long(argc, argv, OPTIONS, uo.u.o, NULL)) != -1)) {
|
|
if(c != 'u')
|
|
set_option(c,optarg);
|
|
}
|
|
|
|
read_config_file(argc,argv,1);
|
|
|
|
if(!get_realm(NULL)->options.name[0]) {
|
|
STRCPY(get_realm(NULL)->options.name,turn_params.domain);
|
|
}
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Domain name: %s\n",turn_params.domain);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Default realm: %s\n",get_realm(NULL)->options.name);
|
|
if(turn_params.oauth && turn_params.oauth_server_name[0]) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "oAuth server name: %s\n",turn_params.oauth_server_name);
|
|
}
|
|
|
|
optind = 0;
|
|
|
|
while (((c = getopt_long(argc, argv, OPTIONS, uo.u.o, NULL)) != -1)) {
|
|
if(c == 'u') {
|
|
set_option(c,optarg);
|
|
}
|
|
}
|
|
|
|
if(turn_params.bps_capacity && !(turn_params.max_bps)) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "\nCONFIG ERROR: If you set the --bps-capacity option, then you must set --max-bps options, too.\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if(turn_params.no_udp_relay && turn_params.no_tcp_relay) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "\nCONFIG ERROR: --no-udp-relay and --no-tcp-relay options cannot be used together.\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if(turn_params.no_udp_relay) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\nCONFIG: --no-udp-relay: UDP relay endpoints are not allowed.\n");
|
|
}
|
|
|
|
if(turn_params.no_tcp_relay) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\nCONFIG: --no-tcp-relay: TCP relay endpoints are not allowed.\n");
|
|
}
|
|
|
|
if(turn_params.server_relay) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "\nCONFIG: WARNING: --server-relay: NON-STANDARD AND DANGEROUS OPTION.\n");
|
|
}
|
|
|
|
#if !defined(TURN_NO_SQLITE)
|
|
if(!strlen(turn_params.default_users_db.persistent_users_db.userdb) && (turn_params.default_users_db.userdb_type == TURN_USERDB_TYPE_SQLITE))
|
|
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,DEFAULT_USERDB_FILE);
|
|
#endif
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if(argc>0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "\nCONFIGURATION ALERT: Unknown argument: %s\n",argv[argc-1]);
|
|
}
|
|
|
|
if(use_lt_credentials && anon_credentials) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "\nCONFIG ERROR: -a and -z options cannot be used together.\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if(!use_lt_credentials && !anon_credentials) {
|
|
if(turn_params.default_users_db.ram_db.users_number) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "\nCONFIGURATION ALERT: you specified long-term user accounts, (-u option) \n but you did not specify the long-term credentials option\n (-a or --lt-cred-mech option).\n I am turning --lt-cred-mech ON for you, but double-check your configuration.\n");
|
|
turn_params.ct = TURN_CREDENTIALS_LONG_TERM;
|
|
use_lt_credentials=1;
|
|
} else {
|
|
turn_params.ct = TURN_CREDENTIALS_NONE;
|
|
use_lt_credentials=0;
|
|
}
|
|
}
|
|
|
|
if(use_lt_credentials) {
|
|
if(!get_realm(NULL)->options.name[0]) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "\nCONFIGURATION ALERT: you did specify the long-term credentials usage\n but you did not specify the default realm option (-r option).\n Check your configuration.\n");
|
|
}
|
|
}
|
|
|
|
if(anon_credentials) {
|
|
if(turn_params.default_users_db.ram_db.users_number) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "\nCONFIGURATION ALERT: you specified user accounts, (-u option) \n but you also specified the anonymous user access option (-z or --no-auth option).\n User accounts will be ignored.\n");
|
|
turn_params.ct = TURN_CREDENTIALS_NONE;
|
|
use_lt_credentials=0;
|
|
}
|
|
}
|
|
|
|
openssl_setup();
|
|
|
|
int local_listeners = 0;
|
|
if (!turn_params.listener.addrs_number) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "NO EXPLICIT LISTENER ADDRESS(ES) ARE CONFIGURED\n");
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "===========Discovering listener addresses: =========\n");
|
|
int maddrs = make_local_listeners_list();
|
|
if((maddrs<1) || !turn_params.listener.addrs_number) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot configure any meaningful IP listener address\n", __FUNCTION__);
|
|
fprintf(stderr,"\n%s\n", Usage);
|
|
exit(-1);
|
|
}
|
|
local_listeners = 1;
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "=====================================================\n");
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Total: %d 'real' addresses discovered\n",maddrs);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "=====================================================\n");
|
|
}
|
|
|
|
if (!turn_params.relays_number) {
|
|
if(!local_listeners && turn_params.listener.addrs_number && turn_params.listener.addrs) {
|
|
size_t la = 0;
|
|
for(la=0;la<turn_params.listener.addrs_number;la++) {
|
|
if(turn_params.listener.addrs[la]) {
|
|
add_relay_addr(turn_params.listener.addrs[la]);
|
|
}
|
|
}
|
|
}
|
|
if (!turn_params.relays_number) {
|
|
turn_params.default_relays = 1;
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "NO EXPLICIT RELAY ADDRESS(ES) ARE CONFIGURED\n");
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "===========Discovering relay addresses: =============\n");
|
|
if(make_local_relays_list(0,AF_INET)<1) {
|
|
make_local_relays_list(1,AF_INET);
|
|
}
|
|
if(make_local_relays_list(0,AF_INET6)<1) {
|
|
make_local_relays_list(1,AF_INET6);
|
|
}
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "=====================================================\n");
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Total: %d relay addresses discovered\n",(int)turn_params.relays_number);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "=====================================================\n");
|
|
}
|
|
|
|
if (!turn_params.relays_number) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: You must specify the relay address(es)\n",
|
|
__FUNCTION__);
|
|
fprintf(stderr,"\n%s\n", Usage);
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
if(turn_params.external_ip && turn_params.relay_addrs) {
|
|
size_t ir = 0;
|
|
for(ir = 0; ir < turn_params.relays_number; ++ir) {
|
|
if(turn_params.relay_addrs[ir]) {
|
|
const char* sra = (const char*)turn_params.relay_addrs[ir];
|
|
if((strstr(sra,"127.0.0.1") != sra)&&(strstr(sra,"::1")!=sra)) {
|
|
ioa_addr ra;
|
|
if(make_ioa_addr((const u08bits*)sra,0,&ra)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"-X : Wrong address format: %s\n",sra);
|
|
} else if(ra.ss.sa_family == turn_params.external_ip->ss.sa_family) {
|
|
ioa_addr_add_mapping(turn_params.external_ip,&ra);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(turn_params.turn_daemon) {
|
|
#if !defined(TURN_HAS_DAEMON)
|
|
pid_t pid = fork();
|
|
if(pid>0)
|
|
exit(0);
|
|
if(pid<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "ERROR: Cannot start daemon process\n");
|
|
exit(-1);
|
|
}
|
|
#else
|
|
if(daemon(1,0)<0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "ERROR: Cannot start daemon process\n");
|
|
exit(-1);
|
|
}
|
|
reset_rtpprintf();
|
|
#endif
|
|
}
|
|
|
|
if(turn_params.pidfile[0]) {
|
|
|
|
char s[2049];
|
|
FILE *f = fopen(turn_params.pidfile,"w");
|
|
if(f) {
|
|
STRCPY(s,turn_params.pidfile);
|
|
} else {
|
|
snprintf(s,sizeof(s),"Cannot create pid file: %s",turn_params.pidfile);
|
|
perror(s);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "%s\n", s);
|
|
|
|
{
|
|
const char *pfs[] = {"/var/run/turnserver.pid",
|
|
"/var/spool/turnserver.pid",
|
|
"/var/turnserver.pid",
|
|
"/var/tmp/turnserver.pid",
|
|
"/tmp/turnserver.pid",
|
|
"turnserver.pid",
|
|
NULL};
|
|
const char **ppfs = pfs;
|
|
while(*ppfs) {
|
|
f = fopen(*ppfs,"w");
|
|
if(f) {
|
|
STRCPY(s,*ppfs);
|
|
break;
|
|
} else {
|
|
++ppfs;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(f) {
|
|
fprintf(f,"%lu\n",(unsigned long)getpid());
|
|
fclose(f);
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "pid file created: %s\n", s);
|
|
}
|
|
}
|
|
|
|
setup_server();
|
|
|
|
drop_privileges();
|
|
|
|
run_listener_server(&(turn_params.listener));
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////// OpenSSL locking ////////////////////////////////////////
|
|
|
|
#if defined(OPENSSL_THREADS)
|
|
|
|
static char some_buffer[65536];
|
|
|
|
//array larger than anything that OpenSSL may need:
|
|
static pthread_mutex_t mutex_buf[256];
|
|
static int mutex_buf_initialized = 0;
|
|
|
|
static void locking_function(int mode, int n, const char *file, int line) {
|
|
UNUSED_ARG(file);
|
|
UNUSED_ARG(line);
|
|
if(mutex_buf_initialized && (n < CRYPTO_num_locks())) {
|
|
if (mode & CRYPTO_LOCK)
|
|
pthread_mutex_lock(&(mutex_buf[n]));
|
|
else
|
|
pthread_mutex_unlock(&(mutex_buf[n]));
|
|
}
|
|
}
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
|
static void id_function(CRYPTO_THREADID *ctid)
|
|
{
|
|
CRYPTO_THREADID_set_numeric(ctid, (unsigned long)pthread_self());
|
|
}
|
|
#else
|
|
static unsigned long id_function(void)
|
|
{
|
|
return (unsigned long)pthread_self();
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
static int THREAD_setup(void) {
|
|
|
|
#if defined(OPENSSL_THREADS)
|
|
|
|
int i;
|
|
|
|
some_buffer[0] = 0;
|
|
|
|
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
|
pthread_mutex_init(&(mutex_buf[i]), NULL);
|
|
}
|
|
|
|
mutex_buf_initialized = 1;
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
|
CRYPTO_THREADID_set_callback(id_function);
|
|
#else
|
|
CRYPTO_set_id_callback(id_function);
|
|
#endif
|
|
|
|
CRYPTO_set_locking_callback(locking_function);
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
int THREAD_cleanup(void);
|
|
int THREAD_cleanup(void) {
|
|
|
|
#if defined(OPENSSL_THREADS)
|
|
|
|
int i;
|
|
|
|
if (!mutex_buf_initialized)
|
|
return 0;
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
|
CRYPTO_THREADID_set_callback(NULL);
|
|
#else
|
|
CRYPTO_set_id_callback(NULL);
|
|
#endif
|
|
|
|
CRYPTO_set_locking_callback(NULL);
|
|
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
|
pthread_mutex_destroy(&(mutex_buf[i]));
|
|
}
|
|
|
|
mutex_buf_initialized = 0;
|
|
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void adjust_key_file_name(char *fn, const char* file_title, int critical)
|
|
{
|
|
char *full_path_to_file = NULL;
|
|
|
|
if(!fn[0]) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"\nERROR: you must set the %s file parameter\n",file_title);
|
|
goto keyerr;
|
|
} else {
|
|
|
|
full_path_to_file = find_config_file(fn, 1);
|
|
{
|
|
FILE *f = full_path_to_file ? fopen(full_path_to_file,"r") : NULL;
|
|
if(!f) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING,"WARNING: cannot find %s file: %s (1)\n",file_title,fn);
|
|
goto keyerr;
|
|
} else {
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
if(!full_path_to_file) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING,"WARNING: cannot find %s file: %s (2)\n",file_title,fn);
|
|
goto keyerr;
|
|
}
|
|
|
|
strncpy(fn,full_path_to_file,sizeof(turn_params.cert_file)-1);
|
|
fn[sizeof(turn_params.cert_file)-1]=0;
|
|
|
|
if(full_path_to_file)
|
|
turn_free(full_path_to_file,strlen(full_path_to_file)+1);
|
|
return;
|
|
}
|
|
|
|
keyerr:
|
|
{
|
|
if(critical) {
|
|
turn_params.no_tls = 1;
|
|
turn_params.no_dtls = 1;
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING,"WARNING: cannot start TLS and DTLS listeners because %s file is not set properly\n",file_title);
|
|
}
|
|
if(full_path_to_file)
|
|
turn_free(full_path_to_file,strlen(full_path_to_file)+1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void adjust_key_file_names(void)
|
|
{
|
|
if(turn_params.ca_cert_file[0])
|
|
adjust_key_file_name(turn_params.ca_cert_file,"CA",1);
|
|
adjust_key_file_name(turn_params.cert_file,"certificate",1);
|
|
adjust_key_file_name(turn_params.pkey_file,"private key",1);
|
|
if(turn_params.dh_file[0])
|
|
adjust_key_file_name(turn_params.dh_file,"DH key",0);
|
|
}
|
|
|
|
static DH *get_dh566(void) {
|
|
|
|
unsigned char dh566_p[] = {
|
|
0x36,0x53,0xA8,0x9C,0x3C,0xF1,0xD1,0x1B,0x2D,0xA2,0x64,0xDE,
|
|
0x59,0x3B,0xE3,0x8C,0x27,0x74,0xC2,0xBE,0x9B,0x6D,0x56,0xE7,
|
|
0xDF,0xFF,0x67,0x6A,0xD2,0x0C,0xE8,0x9E,0x52,0x00,0x05,0xB3,
|
|
0x53,0xF7,0x1C,0x41,0xB2,0xAC,0x38,0x16,0x32,0x3A,0x8E,0x90,
|
|
0x6C,0x7E,0xD1,0x44,0xCB,0xF9,0x2D,0x1E,0x4A,0x9A,0x32,0x81,
|
|
0x58,0xE1,0xE1,0x17,0xC1,0x9C,0xF1,0x1E,0x96,0x2D,0x5F
|
|
};
|
|
|
|
// -----BEGIN DH PARAMETERS-----
|
|
//MEwCRzZTqJw88dEbLaJk3lk744wndMK+m21W59//Z2rSDOieUgAFs1P3HEGyrDgW
|
|
//MjqOkGx+0UTL+S0eSpoygVjh4RfBnPEeli1fAgEF
|
|
// -----END DH PARAMETERS-----
|
|
|
|
unsigned char dh566_g[] = { 0x05 };
|
|
DH *dh;
|
|
|
|
if ((dh = DH_new()) == NULL )
|
|
return (NULL );
|
|
dh->p = BN_bin2bn(dh566_p, sizeof(dh566_p), NULL );
|
|
dh->g = BN_bin2bn(dh566_g, sizeof(dh566_g), NULL );
|
|
if ((dh->p == NULL )|| (dh->g == NULL)){ DH_free(dh); return(NULL);}
|
|
return (dh);
|
|
}
|
|
|
|
static DH *get_dh1066(void) {
|
|
|
|
unsigned char dh1066_p[] = {
|
|
0x02,0x0E,0x26,0x6F,0xAA,0x9F,0xA8,0xE5,0x3F,0x70,0x88,0xF1,
|
|
0xA9,0x29,0xAE,0x1A,0x2B,0xA8,0x2F,0xE8,0xE5,0x0E,0x81,0x78,
|
|
0xD7,0x12,0x41,0xDC,0xE2,0xD5,0x10,0x6F,0x8A,0x35,0x23,0xCE,
|
|
0x66,0x93,0x67,0x14,0xEA,0x0A,0x61,0xD4,0x43,0x63,0x5C,0xDF,
|
|
0xDE,0xF5,0xB9,0xC6,0xB4,0x8C,0xBA,0x1A,0x25,0x9F,0x73,0x0F,
|
|
0x1E,0x1A,0x97,0x42,0x2E,0x60,0x9E,0x4C,0x3C,0x70,0x6A,0xFB,
|
|
0xDD,0xAA,0x7A,0x48,0xA5,0x1E,0x87,0xC8,0xA3,0x5E,0x26,0x40,
|
|
0x1B,0xDE,0x08,0x5E,0xA2,0xB8,0xE8,0x76,0x43,0xE8,0xF1,0x4B,
|
|
0x35,0x4C,0x38,0x92,0xB9,0xFF,0x61,0xE6,0x6C,0xBA,0xF9,0x16,
|
|
0x36,0x3C,0x69,0x2D,0x57,0x90,0x62,0x8A,0xD0,0xD4,0xFB,0xB2,
|
|
0x5A,0x61,0x99,0xA9,0xE8,0x93,0x80,0xA2,0xB7,0xDC,0xB1,0x6A,
|
|
0xAF,0xE3
|
|
};
|
|
|
|
// -----BEGIN DH PARAMETERS-----
|
|
// MIGMAoGGAg4mb6qfqOU/cIjxqSmuGiuoL+jlDoF41xJB3OLVEG+KNSPOZpNnFOoK
|
|
// YdRDY1zf3vW5xrSMuholn3MPHhqXQi5gnkw8cGr73ap6SKUeh8ijXiZAG94IXqK4
|
|
// 6HZD6PFLNUw4krn/YeZsuvkWNjxpLVeQYorQ1PuyWmGZqeiTgKK33LFqr+MCAQI=
|
|
// -----END DH PARAMETERS-----
|
|
|
|
unsigned char dh1066_g[] = { 0x02 };
|
|
DH *dh;
|
|
|
|
if ((dh = DH_new()) == NULL )
|
|
return (NULL );
|
|
dh->p = BN_bin2bn(dh1066_p, sizeof(dh1066_p), NULL );
|
|
dh->g = BN_bin2bn(dh1066_g, sizeof(dh1066_g), NULL );
|
|
if ((dh->p == NULL )|| (dh->g == NULL)){ DH_free(dh); return(NULL);}
|
|
return (dh);
|
|
}
|
|
|
|
static DH *get_dh2066(void) {
|
|
|
|
unsigned char dh2066_p[] = {
|
|
0x03,0x31,0x77,0x20,0x58,0xA6,0x69,0xA3,0x9D,0x2D,0x5E,0xE0,
|
|
0x5C,0x46,0x82,0x0F,0x9E,0x80,0xF0,0x00,0x2A,0xF9,0x0F,0x62,
|
|
0x1F,0x89,0xCE,0x7D,0x2A,0xFD,0xC5,0x9A,0x7C,0x6A,0x60,0x2C,
|
|
0xF1,0xDD,0xD4,0x4D,0x6B,0xCD,0xE9,0x95,0xDB,0x42,0x97,0xBA,
|
|
0xE4,0xAF,0x41,0x38,0x8F,0x57,0x31,0xA4,0x39,0xDD,0x31,0xC3,
|
|
0x6F,0x98,0x0E,0xE3,0xB1,0x43,0xD1,0x36,0xB0,0x01,0x28,0x42,
|
|
0x71,0xD3,0xB0,0x36,0xA0,0x47,0x99,0x25,0x9B,0x32,0xF5,0x86,
|
|
0xB1,0x13,0x5C,0x24,0x8D,0x8D,0x7F,0xE2,0x7F,0x9A,0xC1,0x52,
|
|
0x58,0xC0,0x63,0xAA,0x00,0x7C,0x1F,0x11,0xBD,0xAC,0x4C,0x2D,
|
|
0xE0,0xA2,0x9D,0x4E,0x21,0xE4,0x0B,0xCD,0x24,0x92,0xD2,0x37,
|
|
0x27,0x84,0x59,0x90,0x46,0x2F,0xD5,0xB9,0x27,0x93,0x18,0x88,
|
|
0xBD,0x91,0x5B,0x87,0x55,0x56,0xD8,0x1B,0xE4,0xCF,0x1C,0xAA,
|
|
0xBC,0xCF,0x80,0x1E,0x35,0x2D,0xB1,0xBC,0x35,0x31,0x92,0x62,
|
|
0x3C,0x91,0x8D,0x62,0xDA,0xCF,0x83,0x63,0x12,0x4B,0x30,0x80,
|
|
0xEE,0x82,0x3C,0x2C,0xD2,0x17,0x13,0x1F,0xF9,0x62,0x33,0x5C,
|
|
0x63,0xD8,0x75,0x5B,0xAA,0x16,0x5A,0x36,0x49,0x17,0x77,0xB7,
|
|
0x74,0xBD,0x3E,0x3F,0x98,0x20,0x59,0x5E,0xC7,0x72,0xE8,0xA3,
|
|
0x89,0x21,0xB4,0x3C,0x25,0xF4,0xF4,0x21,0x96,0x5A,0xA6,0x77,
|
|
0xFF,0x2C,0x3A,0xFC,0x98,0x5F,0xC1,0xBF,0x2A,0xCF,0xB8,0x62,
|
|
0x67,0x23,0xE8,0x2F,0xCC,0x7B,0x32,0x1B,0x6B,0x33,0x67,0x0A,
|
|
0xCB,0xD0,0x1F,0x65,0xD7,0x84,0x54,0xF6,0xF1,0x88,0xB5,0xBB,
|
|
0x0C,0x63,0x65,0x34,0xE4,0x66,0x4B
|
|
};
|
|
|
|
// -----BEGIN DH PARAMETERS-----
|
|
//MIIBCgKCAQMDMXcgWKZpo50tXuBcRoIPnoDwACr5D2Ific59Kv3FmnxqYCzx3dRN
|
|
//a83pldtCl7rkr0E4j1cxpDndMcNvmA7jsUPRNrABKEJx07A2oEeZJZsy9YaxE1wk
|
|
//jY1/4n+awVJYwGOqAHwfEb2sTC3gop1OIeQLzSSS0jcnhFmQRi/VuSeTGIi9kVuH
|
|
//VVbYG+TPHKq8z4AeNS2xvDUxkmI8kY1i2s+DYxJLMIDugjws0hcTH/liM1xj2HVb
|
|
//qhZaNkkXd7d0vT4/mCBZXsdy6KOJIbQ8JfT0IZZapnf/LDr8mF/BvyrPuGJnI+gv
|
|
//zHsyG2szZwrL0B9l14RU9vGItbsMY2U05GZLAgEF
|
|
// -----END DH PARAMETERS-----
|
|
|
|
unsigned char dh2066_g[] = { 0x05 };
|
|
DH *dh;
|
|
|
|
if ((dh = DH_new()) == NULL )
|
|
return (NULL );
|
|
dh->p = BN_bin2bn(dh2066_p, sizeof(dh2066_p), NULL );
|
|
dh->g = BN_bin2bn(dh2066_g, sizeof(dh2066_g), NULL );
|
|
if ((dh->p == NULL )|| (dh->g == NULL)){ DH_free(dh); return(NULL);}
|
|
return (dh);
|
|
}
|
|
|
|
static int pem_password_func(char *buf, int size, int rwflag, void *password)
|
|
{
|
|
UNUSED_ARG(rwflag);
|
|
|
|
strncpy(buf, (char * )(password), size);
|
|
buf[size - 1] = 0;
|
|
return (strlen(buf));
|
|
}
|
|
|
|
#if ALPN_SUPPORTED
|
|
|
|
static int ServerALPNCallback(SSL *ssl,
|
|
const unsigned char **out,
|
|
unsigned char *outlen,
|
|
const unsigned char *in,
|
|
unsigned int inlen,
|
|
void *arg) {
|
|
|
|
UNUSED_ARG(ssl);
|
|
UNUSED_ARG(arg);
|
|
|
|
unsigned char sa_len = (unsigned char)strlen(STUN_ALPN);
|
|
unsigned char ta_len = (unsigned char)strlen(TURN_ALPN);
|
|
unsigned char ha_len = (unsigned char)strlen(HTTP_ALPN);
|
|
|
|
int found_http = 0;
|
|
|
|
const unsigned char *ptr = in;
|
|
while(ptr < (in+inlen)) {
|
|
unsigned char current_len = *ptr;
|
|
if(ptr+1+current_len > in+inlen)
|
|
break;
|
|
if((!turn_params.no_stun) && (current_len == sa_len) && (memcmp(ptr+1,STUN_ALPN,sa_len)==0)) {
|
|
*out = ptr+1;
|
|
*outlen = sa_len;
|
|
SSL_set_app_data(ssl,STUN_ALPN);
|
|
return SSL_TLSEXT_ERR_OK;
|
|
}
|
|
if((!turn_params.stun_only) && (current_len == ta_len) && (memcmp(ptr+1,TURN_ALPN,ta_len)==0)) {
|
|
*out = ptr+1;
|
|
*outlen = ta_len;
|
|
SSL_set_app_data(ssl,TURN_ALPN);
|
|
return SSL_TLSEXT_ERR_OK;
|
|
}
|
|
if((current_len == ha_len) && (memcmp(ptr+1,HTTP_ALPN,ha_len)==0)) {
|
|
*out = ptr+1;
|
|
*outlen = ta_len;
|
|
SSL_set_app_data(ssl,HTTP_ALPN);
|
|
found_http = 1;
|
|
}
|
|
ptr += 1 + current_len;
|
|
}
|
|
|
|
if(found_http)
|
|
return SSL_TLSEXT_ERR_OK;
|
|
|
|
return SSL_TLSEXT_ERR_NOACK; //???
|
|
}
|
|
|
|
#endif
|
|
|
|
static void set_ctx(SSL_CTX* ctx, const char *protocol)
|
|
{
|
|
#if ALPN_SUPPORTED
|
|
SSL_CTX_set_alpn_select_cb(ctx, ServerALPNCallback, NULL);
|
|
#endif
|
|
|
|
SSL_CTX_set_default_passwd_cb_userdata(ctx, turn_params.tls_password);
|
|
|
|
SSL_CTX_set_default_passwd_cb(ctx, pem_password_func);
|
|
|
|
if(!(turn_params.cipher_list[0]))
|
|
STRCPY(turn_params.cipher_list,DEFAULT_CIPHER_LIST);
|
|
|
|
SSL_CTX_set_cipher_list(ctx, turn_params.cipher_list);
|
|
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
|
|
|
if (!SSL_CTX_use_certificate_chain_file(ctx, turn_params.cert_file)) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: no certificate found\n", protocol);
|
|
} else {
|
|
print_abs_file_name(protocol, ": Certificate", turn_params.cert_file);
|
|
}
|
|
|
|
if (!SSL_CTX_use_PrivateKey_file(ctx, turn_params.pkey_file, SSL_FILETYPE_PEM)) {
|
|
if (!SSL_CTX_use_RSAPrivateKey_file(ctx, turn_params.pkey_file, SSL_FILETYPE_PEM)) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: no valid private key found, or invalid private key password provided\n", protocol);
|
|
} else {
|
|
print_abs_file_name(protocol, ": Private RSA key", turn_params.pkey_file);
|
|
}
|
|
} else {
|
|
print_abs_file_name(protocol, ": Private key", turn_params.pkey_file);
|
|
}
|
|
|
|
if (!SSL_CTX_check_private_key(ctx)) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: invalid private key\n", protocol);
|
|
}
|
|
|
|
if(turn_params.ca_cert_file[0]) {
|
|
|
|
if (!SSL_CTX_load_verify_locations(ctx, turn_params.ca_cert_file, NULL )) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot load CA from file: %s\n", turn_params.ca_cert_file);
|
|
}
|
|
|
|
SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(turn_params.ca_cert_file));
|
|
|
|
/* Set to require peer (client) certificate verification */
|
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE, NULL);
|
|
|
|
/* Set the verification depth to 9 */
|
|
SSL_CTX_set_verify_depth(ctx, 9);
|
|
|
|
} else {
|
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
|
|
}
|
|
|
|
#if !defined(OPENSSL_NO_EC) && defined(OPENSSL_EC_NAMED_CURVE)
|
|
{ //Elliptic curve algorithms:
|
|
int nid = 0;
|
|
int set_auto_curve = 0;
|
|
|
|
const char* curve_name = turn_params.ec_curve_name;
|
|
|
|
if (!(curve_name[0])) {
|
|
#if !SSL_SESSION_ECDH_AUTO_SUPPORTED
|
|
curve_name = DEFAULT_EC_CURVE_NAME;
|
|
#endif
|
|
set_auto_curve = 1;
|
|
}
|
|
|
|
if(curve_name[0]) {
|
|
{
|
|
nid = OBJ_sn2nid(curve_name);
|
|
if (nid == 0) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"unknown curve name: %s\n",curve_name);
|
|
curve_name = DEFAULT_EC_CURVE_NAME;
|
|
nid = OBJ_sn2nid(curve_name);
|
|
set_auto_curve = 1;
|
|
}
|
|
}
|
|
|
|
{
|
|
EC_KEY *ecdh = EC_KEY_new_by_curve_name(nid);
|
|
if (!ecdh) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
|
|
"%s: ERROR: allocate EC suite\n",__FUNCTION__);
|
|
set_auto_curve = 1;
|
|
} else {
|
|
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
|
EC_KEY_free(ecdh);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(set_auto_curve) {
|
|
#if SSL_SESSION_ECDH_AUTO_SUPPORTED
|
|
SSL_CTX_set_ecdh_auto(ctx,1);
|
|
#endif
|
|
set_auto_curve = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
{//DH algorithms:
|
|
|
|
DH *dh = NULL;
|
|
if(turn_params.dh_file[0]) {
|
|
FILE *paramfile = fopen(turn_params.dh_file, "r");
|
|
if (!paramfile) {
|
|
perror("Cannot open DH file");
|
|
} else {
|
|
dh = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
|
|
fclose(paramfile);
|
|
if(dh) {
|
|
turn_params.dh_key_size = DH_CUSTOM;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!dh) {
|
|
if(turn_params.dh_key_size == DH_566)
|
|
dh = get_dh566();
|
|
else if(turn_params.dh_key_size == DH_2066)
|
|
dh = get_dh2066();
|
|
else
|
|
dh = get_dh1066();
|
|
}
|
|
|
|
/*
|
|
if(!dh) {
|
|
dh = DH_new();
|
|
DH_generate_parameters_ex(dh, 32, DH_GENERATOR_2, 0);
|
|
DH_generate_key(dh);
|
|
}
|
|
*/
|
|
|
|
if(!dh) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: cannot allocate DH suite\n",__FUNCTION__);
|
|
} else {
|
|
if (1 != SSL_CTX_set_tmp_dh (ctx, dh)) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: cannot set DH\n",__FUNCTION__);
|
|
}
|
|
DH_free (dh);
|
|
}
|
|
}
|
|
|
|
{
|
|
int op = 0;
|
|
|
|
#if defined(SSL_OP_NO_SSLv2)
|
|
op |= SSL_OP_NO_SSLv2;
|
|
#endif
|
|
|
|
if(turn_params.no_sslv3)
|
|
op |= SSL_OP_NO_SSLv3;
|
|
|
|
if(turn_params.no_tlsv1)
|
|
op |= SSL_OP_NO_TLSv1;
|
|
|
|
#if defined(SSL_OP_NO_TLSv1_1)
|
|
if(turn_params.no_tlsv1_1)
|
|
op |= SSL_OP_NO_TLSv1_1;
|
|
#endif
|
|
|
|
#if defined(SSL_OP_NO_TLSv1_2)
|
|
if(turn_params.no_tlsv1_2)
|
|
op |= SSL_OP_NO_TLSv1_2;
|
|
#endif
|
|
|
|
#if defined(SSL_OP_NO_DTLSv1) && DTLS_SUPPORTED
|
|
if(turn_params.no_tlsv1)
|
|
op |= SSL_OP_NO_DTLSv1;
|
|
#endif
|
|
|
|
#if defined(SSL_OP_NO_DTLSv1_2) && DTLSv1_2_SUPPORTED
|
|
if(turn_params.no_tlsv1_2)
|
|
op |= SSL_OP_NO_DTLSv1_2;
|
|
#endif
|
|
|
|
#if defined(SSL_OP_CIPHER_SERVER_PREFERENCE)
|
|
op |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
|
#endif
|
|
|
|
#if defined(SSL_OP_SINGLE_DH_USE)
|
|
op |= SSL_OP_SINGLE_DH_USE;
|
|
#endif
|
|
|
|
#if defined(SSL_OP_SINGLE_ECDH_USE)
|
|
op |= SSL_OP_SINGLE_ECDH_USE;
|
|
#endif
|
|
|
|
SSL_CTX_set_options(ctx, op);
|
|
}
|
|
}
|
|
|
|
static void openssl_setup(void)
|
|
{
|
|
THREAD_setup();
|
|
SSL_load_error_strings();
|
|
OpenSSL_add_ssl_algorithms();
|
|
|
|
#if !TLS_SUPPORTED
|
|
if(!turn_params.no_tls) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "WARNING: TLS is not supported\n");
|
|
turn_params.no_tls = 1;
|
|
}
|
|
#endif
|
|
|
|
if(!(turn_params.no_tls && turn_params.no_dtls) && !turn_params.cert_file[0]) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING,"\nWARNING: certificate file is not specified, I cannot start TLS/DTLS services.\nOnly 'plain' UDP/TCP listeners can be started.\n");
|
|
turn_params.no_tls = 1;
|
|
turn_params.no_dtls = 1;
|
|
}
|
|
|
|
if(!(turn_params.no_tls && turn_params.no_dtls) && !turn_params.pkey_file[0]) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING,"\nWARNING: private key file is not specified, I cannot start TLS/DTLS services.\nOnly 'plain' UDP/TCP listeners can be started.\n");
|
|
turn_params.no_tls = 1;
|
|
turn_params.no_dtls = 1;
|
|
}
|
|
|
|
if(!(turn_params.no_tls && turn_params.no_dtls)) {
|
|
adjust_key_file_names();
|
|
}
|
|
|
|
if(!turn_params.no_tls) {
|
|
turn_params.tls_ctx_ssl23 = SSL_CTX_new(SSLv23_server_method()); /*compatibility mode */
|
|
set_ctx(turn_params.tls_ctx_ssl23,"SSL23");
|
|
if(!turn_params.no_tlsv1) {
|
|
turn_params.tls_ctx_v1_0 = SSL_CTX_new(TLSv1_server_method());
|
|
set_ctx(turn_params.tls_ctx_v1_0,"TLS1.0");
|
|
}
|
|
#if TLSv1_1_SUPPORTED
|
|
if(!turn_params.no_tlsv1_1) {
|
|
turn_params.tls_ctx_v1_1 = SSL_CTX_new(TLSv1_1_server_method());
|
|
set_ctx(turn_params.tls_ctx_v1_1,"TLS1.1");
|
|
}
|
|
#if TLSv1_2_SUPPORTED
|
|
if(!turn_params.no_tlsv1_2) {
|
|
turn_params.tls_ctx_v1_2 = SSL_CTX_new(TLSv1_2_server_method());
|
|
set_ctx(turn_params.tls_ctx_v1_2,"TLS1.2");
|
|
}
|
|
#endif
|
|
#endif
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "TLS cipher suite: %s\n",turn_params.cipher_list);
|
|
}
|
|
|
|
if(!turn_params.no_dtls) {
|
|
#if !DTLS_SUPPORTED
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "ERROR: DTLS is not supported.\n");
|
|
#else
|
|
if(OPENSSL_VERSION_NUMBER < 0x10000000L) {
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: TURN Server was compiled with rather old OpenSSL version, DTLS may not be working correctly.\n");
|
|
}
|
|
|
|
#if DTLSv1_2_SUPPORTED
|
|
turn_params.dtls_ctx = SSL_CTX_new(DTLS_server_method());
|
|
turn_params.dtls_ctx_v1_2 = SSL_CTX_new(DTLSv1_2_server_method());
|
|
set_ctx(turn_params.dtls_ctx_v1_2,"DTLS1,2");
|
|
SSL_CTX_set_read_ahead(turn_params.dtls_ctx_v1_2, 1);
|
|
#else
|
|
turn_params.dtls_ctx = SSL_CTX_new(DTLSv1_server_method());
|
|
#endif
|
|
set_ctx(turn_params.dtls_ctx,"DTLS");
|
|
SSL_CTX_set_read_ahead(turn_params.dtls_ctx, 1);
|
|
|
|
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "DTLS cipher suite: %s\n",turn_params.cipher_list);
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
///////////////////////////////
|