1
0
mirror of https://github.com/coturn/coturn.git synced 2025-11-01 07:21:04 +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

@ -321,6 +321,10 @@ Options with values:
--alt-tls-listening-port Alternative listening port for TLS and DTLS protocols.
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 servers have almost full TURN and STUN functionality.

View File

@ -44,6 +44,14 @@
# Default (or zero) value means "TLS listening port plus one".
#
#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.
# If no IP(s) specified in the config file or in the command line options,

View File

@ -481,6 +481,12 @@ Alternative listening port for TLS and DTLS protocols.
Default (or zero) value means "TLS listening port plus one".
.TP
.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
Auxiliary STUN/TURN server listening endpoint.
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) {
switch(st) {
case TCP_SOCKET:
case TCP_SOCKET_PROXY:
case TLS_SOCKET:
case TENTATIVE_TCP_SOCKET:
case SCTP_SOCKET:

View File

@ -110,8 +110,8 @@ NULL, PTHREAD_MUTEX_INITIALIZER,
//////////////// Common params ////////////////////
TURN_VERBOSE_NONE,0,0,0,0,
"/var/run/turnserver.pid",
DEFAULT_STUN_PORT,DEFAULT_STUN_TLS_PORT,0,0,1,
0,0,0,0,
DEFAULT_STUN_PORT,DEFAULT_STUN_TLS_PORT,0,0,0,1,
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"
" --alt-tls-listening-port <port> Alternative listening port for TLS and DTLS,\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"
" --aux-server <ip:port> Auxiliary STUN/TURN server listening endpoint.\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 {
NO_UDP_OPT=256,
NO_TCP_OPT,
TCP_PROXY_PORT_OPT,
NO_TLS_OPT,
NO_DTLS_OPT,
NO_UDP_RELAY_OPT,
@ -805,6 +808,7 @@ static const struct myoption long_options[] = {
{ "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 },
{ "tcp-proxy-port", required_argument, NULL, TCP_PROXY_PORT_OPT },
{ "listening-ip", required_argument, NULL, 'L' },
{ "relay-device", required_argument, NULL, 'i' },
{ "relay-ip", required_argument, NULL, 'E' },
@ -1267,6 +1271,10 @@ static void set_option(int c, char *value)
case ALT_TLS_PORT_OPT:
turn_params.alt_tls_listener_port = atoi(value);
break;
case TCP_PROXY_PORT_OPT:
turn_params.tcp_proxy_port = atoi(value);
turn_params.tcp_use_proxy = 1;
break;
case MIN_PORT_OPT:
turn_params.min_port = atoi(value);
break;

View File

@ -226,10 +226,12 @@ typedef struct _turn_params_ {
int tls_listener_port;
int alt_listener_port;
int alt_tls_listener_port;
int tcp_proxy_port;
int rfc5780;
int no_udp;
int no_tcp;
int tcp_use_proxy;
vint no_tcp_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 */
/* 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++) {
@ -1494,15 +1494,15 @@ static void setup_tcp_listener_servers(ioa_engine_handle e, struct relay_server
/* 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)
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 {
tcp_services[index] = NULL;
if(turn_params.rfc5780)
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);
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);

View File

@ -2157,6 +2157,67 @@ static TURN_TLS_TYPE check_tentative_tls(ioa_socket_raw fd)
}
#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)
{
int len = 0;
@ -2372,39 +2433,57 @@ static int socket_input_worker(ioa_socket_handle s)
struct evbuffer *inbuf = bufferevent_get_input(s->bev);
if(inbuf) {
ev_ssize_t blen = evbuffer_copyout(inbuf, buf_elem->buf.buf, STUN_BUFFER_SIZE);
if(blen>0) {
int mlen = 0;
if(blen>(ev_ssize_t)STUN_BUFFER_SIZE)
blen=(ev_ssize_t)STUN_BUFFER_SIZE;
if(is_stream_socket(s->st) && ((s->sat == TCP_CLIENT_DATA_SOCKET)||(s->sat==TCP_RELAY_DATA_SOCKET))) {
mlen = blen;
} else {
mlen = stun_get_message_len_str(buf_elem->buf.buf, blen, 1, &app_msg_len);
}
if(mlen>0 && mlen<=(int)blen) {
len = (int)bufferevent_read(s->bev, buf_elem->buf.buf, mlen);
if(len < 0) {
ret = -1;
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;
log_socket_event(s, "socket read failed, to be closed",1);
} else if((s->st == TLS_SOCKET)||(s->st == TLS_SCTP_SOCKET)) {
#if TLS_SUPPORTED
SSL *ctx = bufferevent_openssl_get_ssl(s->bev);
if(!ctx || SSL_get_shutdown(ctx)) {
ret = -1;
s->tobeclosed = 1;
}
#endif
}
if(ret != -1) {
ret = len;
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))) {
mlen = blen;
} else {
mlen = stun_get_message_len_str(buf_elem->buf.buf, blen, 1, &app_msg_len);
}
if(mlen>0 && mlen<=(int)blen) {
len = (int)bufferevent_read(s->bev, buf_elem->buf.buf, mlen);
if(len < 0) {
ret = -1;
s->tobeclosed = 1;
s->broken = 1;
log_socket_event(s, "socket read failed, to be closed",1);
} else if((s->st == TLS_SOCKET)||(s->st == TLS_SCTP_SOCKET)) {
#if TLS_SUPPORTED
SSL *ctx = bufferevent_openssl_get_ssl(s->bev);
if(!ctx || SSL_get_shutdown(ctx)) {
ret = -1;
s->tobeclosed = 1;
}
#endif
}
if(ret != -1) {
ret = len;
}
}
}
} else if(blen<0) {
s->tobeclosed = 1;
s->broken = 1;
@ -3277,6 +3356,7 @@ int register_callback_on_ioa_socket(ioa_engine_handle e, ioa_socket_handle s, in
break;
case SCTP_SOCKET:
case TCP_SOCKET:
case TCP_SOCKET_PROXY:
if(s->bev) {
if(!clean_preexisting) {
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;
if(turn_params.no_tls)
if(turn_params.tcp_use_proxy)
st = TCP_SOCKET_PROXY;
else if(turn_params.no_tls)
st = TCP_SOCKET;
else if(turn_params.no_tcp)
st = TLS_SOCKET;

View File

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