diff --git a/config b/config index 044ad97..968b63a 100644 --- a/config +++ b/config @@ -44,6 +44,7 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/ngx_rtmp_relay_module.h \ $ngx_addon_dir/ngx_rtmp_streams.h \ $ngx_addon_dir/ngx_rtmp_bitop.h \ + $ngx_addon_dir/ngx_rtmp_proxy_protocol.h \ $ngx_addon_dir/hls/ngx_rtmp_mpegts.h \ $ngx_addon_dir/dash/ngx_rtmp_mp4.h \ " @@ -79,6 +80,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/ngx_rtmp_log_module.c \ $ngx_addon_dir/ngx_rtmp_limit_module.c \ $ngx_addon_dir/ngx_rtmp_bitop.c \ + $ngx_addon_dir/ngx_rtmp_proxy_protocol.c \ $ngx_addon_dir/hls/ngx_rtmp_hls_module.c \ $ngx_addon_dir/dash/ngx_rtmp_dash_module.c \ $ngx_addon_dir/hls/ngx_rtmp_mpegts.c \ diff --git a/ngx_rtmp.c b/ngx_rtmp.c index 0390df7..c079c90 100644 --- a/ngx_rtmp.c +++ b/ngx_rtmp.c @@ -544,6 +544,7 @@ found: addr->bind = listen->bind; addr->wildcard = listen->wildcard; addr->so_keepalive = listen->so_keepalive; + addr->proxy_protocol = listen->proxy_protocol; #if (NGX_HAVE_KEEPALIVE_TUNABLE) addr->tcp_keepidle = listen->tcp_keepidle; addr->tcp_keepintvl = listen->tcp_keepintvl; @@ -702,6 +703,7 @@ ngx_rtmp_add_addrs(ngx_conf_t *cf, ngx_rtmp_port_t *mport, addrs[i].conf.addr_text.len = len; addrs[i].conf.addr_text.data = p; + addrs[i].conf.proxy_protocol = addr->proxy_protocol; } return NGX_OK; @@ -751,6 +753,7 @@ ngx_rtmp_add_addrs6(ngx_conf_t *cf, ngx_rtmp_port_t *mport, addrs6[i].conf.addr_text.len = len; addrs6[i].conf.addr_text.data = p; + addrs6[i].conf.proxy_protocol = addr->proxy_protocol; } return NGX_OK; diff --git a/ngx_rtmp.h b/ngx_rtmp.h index 8c53138..d3648f7 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -43,6 +43,7 @@ typedef struct { unsigned ipv6only:2; #endif unsigned so_keepalive:2; + unsigned proxy_protocol:1; #if (NGX_HAVE_KEEPALIVE_TUNABLE) int tcp_keepidle; int tcp_keepintvl; @@ -54,6 +55,7 @@ typedef struct { typedef struct { ngx_rtmp_conf_ctx_t *ctx; ngx_str_t addr_text; + unsigned proxy_protocol:1; } ngx_rtmp_addr_conf_t; typedef struct { @@ -97,6 +99,7 @@ typedef struct { unsigned ipv6only:2; #endif unsigned so_keepalive:2; + unsigned proxy_protocol:1; #if (NGX_HAVE_KEEPALIVE_TUNABLE) int tcp_keepidle; int tcp_keepintvl; diff --git a/ngx_rtmp_core_module.c b/ngx_rtmp_core_module.c index 3ffedb1..01303c6 100644 --- a/ngx_rtmp_core_module.c +++ b/ngx_rtmp_core_module.c @@ -719,6 +719,11 @@ ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) { + ls->proxy_protocol = 1; + continue; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[i]); return NGX_CONF_ERROR; diff --git a/ngx_rtmp_init.c b/ngx_rtmp_init.c index 1492c49..836935d 100644 --- a/ngx_rtmp_init.c +++ b/ngx_rtmp_init.c @@ -7,6 +7,7 @@ #include #include #include "ngx_rtmp.h" +#include "ngx_rtmp_proxy_protocol.h" static void ngx_rtmp_close_connection(ngx_connection_t *c); @@ -130,7 +131,12 @@ ngx_rtmp_init_connection(ngx_connection_t *c) s->auto_pushed = unix_socket; - ngx_rtmp_handshake(s); + if (addr_conf->proxy_protocol) { + ngx_rtmp_proxy_protocol(s); + + } else { + ngx_rtmp_handshake(s); + } } diff --git a/ngx_rtmp_proxy_protocol.c b/ngx_rtmp_proxy_protocol.c new file mode 100644 index 0000000..8a96914 --- /dev/null +++ b/ngx_rtmp_proxy_protocol.c @@ -0,0 +1,172 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_proxy_protocol.h" + + +static void ngx_rtmp_proxy_protocol_recv(ngx_event_t *rev); + + +void +ngx_rtmp_proxy_protocol(ngx_rtmp_session_t *s) +{ + ngx_connection_t *c; + + c = s->connection; + c->read->handler = ngx_rtmp_proxy_protocol_recv; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "proxy_protocol: start"); + + ngx_rtmp_proxy_protocol_recv(c->read); +} + + +static void +ngx_rtmp_proxy_protocol_recv(ngx_event_t *rev) +{ + u_char buf[107], *p, *pp, *text; + size_t len; + ssize_t n; + ngx_err_t err; + ngx_int_t i; + ngx_addr_t addr; + ngx_connection_t *c; + ngx_rtmp_session_t *s; + + c = rev->data; + s = c->data; + + if (c->destroyed) { + return; + } + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, + "proxy_protocol: recv: client timed out"); + c->timedout = 1; + ngx_rtmp_finalize_session(s); + return; + } + + if (rev->timer_set) { + ngx_del_timer(rev); + } + + n = recv(c->fd, buf, sizeof(buf), MSG_PEEK); + + err = ngx_socket_errno; + + if (n == -1) { + + if (err == NGX_EAGAIN) { + ngx_add_timer(rev, s->timeout); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } + + return; + } + + ngx_rtmp_finalize_session(s); + + return; + } + + p = buf; + + if (n <= 8 && ngx_strncmp(p, "PROXY ", 6) != 0) { + goto bad_header; + } + + n -= 6; + p += 6; + + ngx_memzero(&addr, sizeof(ngx_addr_t)); + + if (n >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) { + n -= 7; + p += 7; + goto skip; + } + + if (n < 5 || ngx_strncmp(p, "TCP", 3) != 0 + || (p[3] != '4' && p[3] != '6') || p[4] != ' ') + { + goto bad_header; + } + + n -= 5; + p += 5; + + pp = ngx_strlchr(p, p + n, ' '); + + if (pp == NULL) { + goto bad_header; + } + + if (ngx_parse_addr(s->connection->pool, &addr, p, pp - p) != NGX_OK) { + goto bad_header; + } + + n -= pp - p; + p = pp; + +skip: + + for (i = 0; i + 1 < n; i++) { + if (p[i] == CR && p[i + 1] == LF) { + break; + } + } + + if (i + 1 == n) { + goto bad_header; + } + + n = p - buf + i + 2; + + if (c->recv(c, buf, n) != n) { + goto failed; + } + + if (addr.socklen) { + text = ngx_palloc(s->connection->pool, NGX_SOCKADDR_STRLEN); + + if (text == NULL) { + goto failed; + } + + len = ngx_sock_ntop(addr.sockaddr, addr.socklen, text, + NGX_SOCKADDR_STRLEN, 0); + if (len == 0) { + goto failed; + } + + c->sockaddr = addr.sockaddr; + c->socklen = addr.socklen; + c->addr_text.data = text; + c->addr_text.len = len; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, + "proxy_protocol: remote_addr:'%V'", &c->addr_text); + } + + ngx_rtmp_handshake(s); + + return; + +bad_header: + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy_protocol: bad header"); + +failed: + + ngx_rtmp_finalize_session(s); +} diff --git a/ngx_rtmp_proxy_protocol.h b/ngx_rtmp_proxy_protocol.h new file mode 100644 index 0000000..e873c3c --- /dev/null +++ b/ngx_rtmp_proxy_protocol.h @@ -0,0 +1,19 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ +#define _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" + + +void ngx_rtmp_proxy_protocol(ngx_rtmp_session_t *c); + + +#endif /* _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ */