1
0
mirror of https://github.com/coturn/coturn.git synced 2025-11-04 08:51:00 +01:00

Merge pull request #479 from WaxieSDR/master

Add support for reverse proxy connections
This commit is contained in:
Mészáros Mihály 2020-04-28 09:47:42 +02:00 committed by GitHub
commit db68c76195
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 141 additions and 29 deletions

View File

@ -322,6 +322,10 @@ Options with values:
--alt-tls-listening-port Alternative listening port for TLS and DTLS protocols. --alt-tls-listening-port Alternative listening port for TLS and DTLS protocols.
Default (or zero) value means "TLS listening port plus one". Default (or zero) value means "TLS listening port plus one".
--tcp-proxy-port Support connections from TCP loadbalancer on this port. The loadbalancer
should use the binary proxy protocol.
(https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
--aux-server Auxiliary STUN/TURN server listening endpoint. --aux-server Auxiliary STUN/TURN server listening endpoint.
Aux servers have almost full TURN and STUN functionality. Aux servers have almost full TURN and STUN functionality.
The (minor) limitations are: The (minor) limitations are:

View File

@ -45,6 +45,14 @@
# #
#alt-tls-listening-port=0 #alt-tls-listening-port=0
# Some network setups will require using a TCP reverse proxy in front
# of the STUN server. If the proxy port option is set a single listener
# is started on the given port that accepts connections using the
# haproxy proxy protocol v2.
# (https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
#
#tcp-proxy-port=5555
# Listener IP address of relay server. Multiple listeners can be specified. # Listener IP address of relay server. Multiple listeners can be specified.
# If no IP(s) specified in the config file or in the command line options, # If no IP(s) specified in the config file or in the command line options,
# then all IPv4 and IPv6 system IPs will be used for listening. # then all IPv4 and IPv6 system IPs will be used for listening.

View File

@ -481,6 +481,12 @@ Alternative listening port for TLS and DTLS protocols.
Default (or zero) value means "TLS listening port plus one". Default (or zero) value means "TLS listening port plus one".
.TP .TP
.B .B
\fB\-\-tcp\-proxy\-port\fP
Support connections from TCP loadbalancer on this port. The loadbalancer
should use the binary proxy protocol.
(https://www.haproxy.org/download/1.8/doc/proxy\-protocol.txt)
.TP
.B
\fB\-\-aux\-server\fP \fB\-\-aux\-server\fP
Auxiliary STUN/TURN server listening endpoint. Auxiliary STUN/TURN server listening endpoint.
Aux servers have almost full TURN and STUN functionality. Aux servers have almost full TURN and STUN functionality.

View File

@ -439,6 +439,7 @@ int set_raw_socket_tos(evutil_socket_t fd, int family, int tos)
int is_stream_socket(int st) { int is_stream_socket(int st) {
switch(st) { switch(st) {
case TCP_SOCKET: case TCP_SOCKET:
case TCP_SOCKET_PROXY:
case TLS_SOCKET: case TLS_SOCKET:
case TENTATIVE_TCP_SOCKET: case TENTATIVE_TCP_SOCKET:
case SCTP_SOCKET: case SCTP_SOCKET:

View File

@ -110,8 +110,8 @@ NULL, PTHREAD_MUTEX_INITIALIZER,
//////////////// Common params //////////////////// //////////////// Common params ////////////////////
TURN_VERBOSE_NONE,0,0,0,0, TURN_VERBOSE_NONE,0,0,0,0,
"/var/run/turnserver.pid", "/var/run/turnserver.pid",
DEFAULT_STUN_PORT,DEFAULT_STUN_TLS_PORT,0,0,1, DEFAULT_STUN_PORT,DEFAULT_STUN_TLS_PORT,0,0,0,1,
0,0,0,0, 0,0,0,0,0,
"", "",
"",0, "",0,
{ {
@ -402,6 +402,8 @@ static char Usage[] = "Usage: turnserver [options]\n"
" or in old RFC 3489 sense, default is \"listening port plus one\").\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" " --alt-tls-listening-port <port> Alternative listening port for TLS and DTLS,\n"
" the default is \"TLS/DTLS port plus one\".\n" " the default is \"TLS/DTLS port plus one\".\n"
" --tcp-proxy-port <port> Support connections from TCP loadbalancer on this port. The loadbalancer should\n"
" use the binary proxy protocol (https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)\n"
" -L, --listening-ip <ip> Listener IP address of relay server. Multiple listeners can be specified.\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" " --aux-server <ip:port> Auxiliary STUN/TURN server listening endpoint.\n"
" Auxiliary servers do not have alternative ports and\n" " Auxiliary servers do not have alternative ports and\n"
@ -713,6 +715,7 @@ static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
enum EXTRA_OPTS { enum EXTRA_OPTS {
NO_UDP_OPT=256, NO_UDP_OPT=256,
NO_TCP_OPT, NO_TCP_OPT,
TCP_PROXY_PORT_OPT,
NO_TLS_OPT, NO_TLS_OPT,
NO_DTLS_OPT, NO_DTLS_OPT,
NO_UDP_RELAY_OPT, NO_UDP_RELAY_OPT,
@ -805,6 +808,7 @@ static const struct myoption long_options[] = {
{ "tls-listening-port", required_argument, NULL, TLS_PORT_OPT }, { "tls-listening-port", required_argument, NULL, TLS_PORT_OPT },
{ "alt-listening-port", required_argument, NULL, ALT_PORT_OPT }, { "alt-listening-port", required_argument, NULL, ALT_PORT_OPT },
{ "alt-tls-listening-port", required_argument, NULL, ALT_TLS_PORT_OPT }, { "alt-tls-listening-port", required_argument, NULL, ALT_TLS_PORT_OPT },
{ "tcp-proxy-port", required_argument, NULL, TCP_PROXY_PORT_OPT },
{ "listening-ip", required_argument, NULL, 'L' }, { "listening-ip", required_argument, NULL, 'L' },
{ "relay-device", required_argument, NULL, 'i' }, { "relay-device", required_argument, NULL, 'i' },
{ "relay-ip", required_argument, NULL, 'E' }, { "relay-ip", required_argument, NULL, 'E' },
@ -1267,6 +1271,10 @@ static void set_option(int c, char *value)
case ALT_TLS_PORT_OPT: case ALT_TLS_PORT_OPT:
turn_params.alt_tls_listener_port = atoi(value); turn_params.alt_tls_listener_port = atoi(value);
break; break;
case TCP_PROXY_PORT_OPT:
turn_params.tcp_proxy_port = atoi(value);
turn_params.tcp_use_proxy = 1;
break;
case MIN_PORT_OPT: case MIN_PORT_OPT:
turn_params.min_port = atoi(value); turn_params.min_port = atoi(value);
break; break;

View File

@ -226,10 +226,12 @@ typedef struct _turn_params_ {
int tls_listener_port; int tls_listener_port;
int alt_listener_port; int alt_listener_port;
int alt_tls_listener_port; int alt_tls_listener_port;
int tcp_proxy_port;
int rfc5780; int rfc5780;
int no_udp; int no_udp;
int no_tcp; int no_tcp;
int tcp_use_proxy;
vint no_tcp_relay; vint no_tcp_relay;
vint no_udp_relay; vint no_udp_relay;

View File

@ -1473,7 +1473,7 @@ static void setup_tcp_listener_servers(ioa_engine_handle e, struct relay_server
/* Create listeners */ /* Create listeners */
/* Aux TCP servers */ /* Aux TCP servers */
if(!turn_params.no_tls || !turn_params.no_tcp) { if(!turn_params.tcp_use_proxy && (!turn_params.no_tls || !turn_params.no_tcp)) {
for(i=0; i<turn_params.aux_servers_list.size; i++) { for(i=0; i<turn_params.aux_servers_list.size; i++) {
@ -1494,15 +1494,15 @@ static void setup_tcp_listener_servers(ioa_engine_handle e, struct relay_server
/* TCP: */ /* TCP: */
if(!turn_params.no_tcp) { if(!turn_params.no_tcp) {
tcp_services[index] = create_tls_listener_server(turn_params.listener_ifname, turn_params.listener.addrs[i], turn_params.listener_port, turn_params.verbose, e, send_socket_to_general_relay, relay_server); tcp_services[index] = create_tls_listener_server(turn_params.listener_ifname, turn_params.listener.addrs[i], turn_params.tcp_use_proxy?turn_params.tcp_proxy_port:turn_params.listener_port, turn_params.verbose, e, send_socket_to_general_relay, relay_server);
if(turn_params.rfc5780) if(turn_params.rfc5780)
tcp_services[index+1] = create_tls_listener_server(turn_params.listener_ifname, turn_params.listener.addrs[i], get_alt_listener_port(), turn_params.verbose, e, send_socket_to_general_relay, relay_server); tcp_services[index+1] = turn_params.tcp_use_proxy?NULL:create_tls_listener_server(turn_params.listener_ifname, turn_params.listener.addrs[i], get_alt_listener_port(), turn_params.verbose, e, send_socket_to_general_relay, relay_server);
} else { } else {
tcp_services[index] = NULL; tcp_services[index] = NULL;
if(turn_params.rfc5780) if(turn_params.rfc5780)
tcp_services[index+1] = NULL; tcp_services[index+1] = NULL;
} }
if(!turn_params.no_tls && (turn_params.no_tcp || (turn_params.listener_port != turn_params.tls_listener_port))) { if(!turn_params.no_tls && !turn_params.tcp_use_proxy && (turn_params.no_tcp || (turn_params.listener_port != turn_params.tls_listener_port))) {
tls_services[index] = create_tls_listener_server(turn_params.listener_ifname, turn_params.listener.addrs[i], turn_params.tls_listener_port, turn_params.verbose, e, send_socket_to_general_relay, relay_server); tls_services[index] = create_tls_listener_server(turn_params.listener_ifname, turn_params.listener.addrs[i], turn_params.tls_listener_port, turn_params.verbose, e, send_socket_to_general_relay, relay_server);
if(turn_params.rfc5780) if(turn_params.rfc5780)
tls_services[index+1] = create_tls_listener_server(turn_params.listener_ifname, turn_params.listener.addrs[i], get_alt_tls_listener_port(), turn_params.verbose, e, send_socket_to_general_relay, relay_server); tls_services[index+1] = create_tls_listener_server(turn_params.listener_ifname, turn_params.listener.addrs[i], get_alt_tls_listener_port(), turn_params.verbose, e, send_socket_to_general_relay, relay_server);

View File

@ -2157,6 +2157,67 @@ static TURN_TLS_TYPE check_tentative_tls(ioa_socket_raw fd)
} }
#endif #endif
static ssize_t socket_parse_proxy_v2(ioa_socket_handle s, uint8_t *buf, size_t len)
{
if(len < 16){
return 0 ;
}
/* Check for proxy-v2 magic field */
char magic[] = {0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A};
if(memcmp(magic, buf, sizeof(magic))){
return -1;
}
/* Check version */
uint8_t version = buf[12] >> 4;
if(version != 2) return -1;
/* Read data */
uint8_t command = buf[12] & 0xF;
uint8_t family = buf[13] >> 4;
uint8_t proto = buf[13] & 0xF;
size_t plen = ((size_t)buf[14] << 8) | buf[15];
size_t tlen = 16 + plen;
if(len < tlen) return 0;
/* A local connection is used by the proxy itself and does not carry a valid address */
if(command == 0) return tlen;
/* Accept only proxied TCP connections */
if(command != 1 || proto != 1) return -1;
/* Read the address */
if(family == 1 && plen >= 12){ /* IPv4 */
struct sockaddr_in remote, local;
remote.sin_family = local.sin_family = AF_INET;
memcpy(&remote.sin_addr.s_addr, &buf[16], 4);
memcpy(&local.sin_addr.s_addr, &buf[20], 4);
memcpy(&remote.sin_port, &buf[24], 2);
memcpy(&local.sin_port, &buf[26], 2);
addr_cpy4(&(s->local_addr), &local);
addr_cpy4(&(s->remote_addr), &remote);
}else if(family == 2 && plen >= 36){ /* IPv6 */
struct sockaddr_in6 remote, local;
remote.sin6_family = local.sin6_family = AF_INET6;
memcpy(&remote.sin6_addr.s6_addr, &buf[16], 16);
memcpy(&local.sin6_addr.s6_addr, &buf[32], 16);
memcpy(&remote.sin6_port, &buf[48], 2);
memcpy(&local.sin6_port, &buf[50], 2);
addr_cpy6(&(s->local_addr), &local);
addr_cpy6(&(s->remote_addr), &remote);
}else{
return -1;
}
return tlen;
}
static int socket_input_worker(ioa_socket_handle s) static int socket_input_worker(ioa_socket_handle s)
{ {
int len = 0; int len = 0;
@ -2372,12 +2433,30 @@ static int socket_input_worker(ioa_socket_handle s)
struct evbuffer *inbuf = bufferevent_get_input(s->bev); struct evbuffer *inbuf = bufferevent_get_input(s->bev);
if(inbuf) { if(inbuf) {
ev_ssize_t blen = evbuffer_copyout(inbuf, buf_elem->buf.buf, STUN_BUFFER_SIZE); ev_ssize_t blen = evbuffer_copyout(inbuf, buf_elem->buf.buf, STUN_BUFFER_SIZE);
if(blen>0) { if(blen>0) {
int mlen = 0; int mlen = 0;
if(blen>(ev_ssize_t)STUN_BUFFER_SIZE) if(blen>(ev_ssize_t)STUN_BUFFER_SIZE)
blen=(ev_ssize_t)STUN_BUFFER_SIZE; blen=(ev_ssize_t)STUN_BUFFER_SIZE;
if(s->st == TCP_SOCKET_PROXY){
ssize_t tlen = socket_parse_proxy_v2(s, buf_elem->buf.buf, blen);
blen = 0;
if (tlen < 0){
s->tobeclosed = 1;
s->broken = 1;
ret = -1;
log_socket_event(s, "proxy protocol violated",1);
}else if(tlen > 0){
bufferevent_read(s->bev, buf_elem->buf.buf, tlen);
blen = evbuffer_copyout(inbuf, buf_elem->buf.buf, STUN_BUFFER_SIZE);
s->st = TCP_SOCKET;
}
}
if(blen){
if(is_stream_socket(s->st) && ((s->sat == TCP_CLIENT_DATA_SOCKET)||(s->sat==TCP_RELAY_DATA_SOCKET))) { if(is_stream_socket(s->st) && ((s->sat == TCP_CLIENT_DATA_SOCKET)||(s->sat==TCP_RELAY_DATA_SOCKET))) {
mlen = blen; mlen = blen;
} else { } else {
@ -2404,7 +2483,7 @@ static int socket_input_worker(ioa_socket_handle s)
ret = len; ret = len;
} }
} }
}
} else if(blen<0) { } else if(blen<0) {
s->tobeclosed = 1; s->tobeclosed = 1;
s->broken = 1; s->broken = 1;
@ -3277,6 +3356,7 @@ int register_callback_on_ioa_socket(ioa_engine_handle e, ioa_socket_handle s, in
break; break;
case SCTP_SOCKET: case SCTP_SOCKET:
case TCP_SOCKET: case TCP_SOCKET:
case TCP_SOCKET_PROXY:
if(s->bev) { if(s->bev) {
if(!clean_preexisting) { if(!clean_preexisting) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,

View File

@ -82,7 +82,9 @@ static void server_input_handler(struct evconnlistener *l, evutil_socket_t fd,
SOCKET_TYPE st = TENTATIVE_TCP_SOCKET; SOCKET_TYPE st = TENTATIVE_TCP_SOCKET;
if(turn_params.no_tls) if(turn_params.tcp_use_proxy)
st = TCP_SOCKET_PROXY;
else if(turn_params.no_tls)
st = TCP_SOCKET; st = TCP_SOCKET;
else if(turn_params.no_tcp) else if(turn_params.no_tcp)
st = TLS_SOCKET; st = TLS_SOCKET;

View File

@ -90,6 +90,7 @@ enum _SOCKET_TYPE {
SCTP_SOCKET=132, SCTP_SOCKET=132,
TLS_SCTP_SOCKET=133, TLS_SCTP_SOCKET=133,
DTLS_SOCKET=250, DTLS_SOCKET=250,
TCP_SOCKET_PROXY=253,
TENTATIVE_SCTP_SOCKET=254, TENTATIVE_SCTP_SOCKET=254,
TENTATIVE_TCP_SOCKET=255 TENTATIVE_TCP_SOCKET=255
}; };