diff -rupN tvheadend-master/src/config.c tvheadend-patch/src/config.c --- tvheadend/src/config.c 2017-02-13 13:07:29.000000000 +0100 +++ tvheadend/src/config.c 2017-02-18 13:07:29.000000000 +0100 @@ -1676,6 +1676,7 @@ config_boot ( const char *path, gid_t gi config.idnode.in_class = &config_class; config.ui_quicktips = 1; config.digest = 1; + config.proxy = 0; config.realm = strdup("tvheadend"); config.info_area = strdup("login,storage,time"); config.cookie_expires = 7; @@ -2127,6 +2128,20 @@ const idclass_t config_class = { .opts = PO_EXPERT, .group = 1 }, + { + .type = PT_BOOL, + .id = "proxy", + .name = N_("Use PROXY protocol & X-Forwarded-For"), + .desc = N_("PROXY protocol is an extension for support incoming " + "TCP connections from a remote server (like a firewall) " + "sending the original IP address of the client. " + "The HTTP header 'X-Forwarded-For' do the same with " + "HTTP connections. Both enable tunneled connections." + "This option should be disabled for standard usage."), + .off = offsetof(config_t, proxy), + .opts = PO_EXPERT, + .group = 1 + }, { .type = PT_U32, .intextra = INTEXTRA_RANGE(1, 0x7ff, 1), diff -rupN tvheadend-master/src/config.h tvheadend-patch/src/config.h --- tvheadend/src/config.h 2017-02-13 13:07:29.000000000 +0100 +++ tvheadend/src/config.h 2017-02-18 13:07:29.000000000 +0100 @@ -34,6 +34,7 @@ typedef struct config { int uilevel_nochange; int ui_quicktips; int digest; + int proxy; char *realm; char *wizard; char *full_version; diff -rupN tvheadend-master/src/http.c tvheadend-patch/src/http.c --- tvheadend/src/http.c 2017-02-13 13:07:29.000000000 +0100 +++ tvheadend/src/http.c 2017-02-18 13:07:29.000000000 +0100 @@ -1100,7 +1100,13 @@ process_request(http_connection_t *hc, h char authbuf[150]; hc->hc_url_orig = tvh_strdupa(hc->hc_url); + + v = (config.proxy) ? http_arg_get(&hc->hc_args, "x-forwarded-for") : NULL; + if (v) + tcp_get_sockaddr((struct sockaddr*)hc->hc_peer, v); + tcp_get_str_from_ip((struct sockaddr*)hc->hc_peer, authbuf, sizeof(authbuf)); + hc->hc_peer_ipstr = tvh_strdupa(authbuf); hc->hc_representative = hc->hc_peer_ipstr; hc->hc_username = NULL; @@ -1460,6 +1466,48 @@ http_serve_requests(http_connection_t *h if ((cmdline = tcp_read_line(hc->hc_fd, &spill)) == NULL) goto error; + // PROXY Protocol v1 support + // Format: 'PROXY TCP4 192.168.0.1 192.168.0.11 56324 9981\r\n' + // SRC-ADDRESS DST-ADDRESS SPORT DPORT + // + if ((config.proxy) && (strlen(cmdline) >= 6) && (strncmp(cmdline,"PROXY ",6) == 0 )) { + tvhinfo(LS_HTTP, "[PROXY] PROXY protocol detected! cmdline='%s'",cmdline); + + char* pl = cmdline + 6; + + if ((cmdline = tcp_read_line(hc->hc_fd, &spill)) == NULL) { + goto error; // No more data after the PROXY protocol + } + + if ( (strlen(pl) >= 7) && (strncmp(pl,"UNKNOWN",7) == 0)) + goto error; // Unknown PROXY protocol + + if ( (strlen(pl) < 5) || (strncmp(pl,"TCP4 ",5) != 0)) + goto error; // Only IPv4 supported + pl += 5; + + // Check the SRC-ADDRESS + c = pl; + char ch; + for ( ;; ) { + if (strlen(pl) == 0) goto error; // Incomplete PROXY format + ch = *pl++; + if (ch == ' ') break; + if (ch != '.' && (ch < '0' || ch > '9')) goto error; // Not valid IP address + } + if (((pl-c) < 8) || ((pl-c) > 16)) goto error; // Not valid IP address + + // Here 'c' points to a dotted IPv4 SRC-ADRRESS + char srcaddr[16]; + memset(srcaddr, 0, 16); + strncpy(srcaddr, c, (pl-c)-1); + + // Don't care about DST-ADDRESS, SRC-PORT & DST-PORT + // All it's OK, push the original client IP + tvhinfo(LS_HTTP, "[PROXY] Original source='%s'",srcaddr); + http_arg_set(&hc->hc_args, "x-forwarded-for", srcaddr); + } + if((n = http_tokenize(cmdline, argv, 3, -1)) != 3) goto error; diff -rupN tvheadend-master/src/tcp.c tvheadend-patch/src/tcp.c --- tvheadend/src/tcp.c 2017-02-13 13:07:29.000000000 +0100 +++ tvheadend/src/tcp.c 2017-02-18 13:07:29.0000000007 +0100 @@ -446,6 +446,28 @@ tcp_get_ip_from_str(const char *src, str /** * */ +int +tcp_get_sockaddr(struct sockaddr *sa, const char *s) +{ + if(sa == NULL || s == NULL) + return -1; + + struct sockaddr_in *sin = (struct sockaddr_in*)sa; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; + + if (inet_pton(AF_INET, s, &sin->sin_addr) == 1) + sa->sa_family = AF_INET; + else if (inet_pton(AF_INET6, s, &sin6->sin6_addr) == 1) + sa->sa_family = AF_INET6; + else + return -1; + + return 0; +} + +/** + * + */ static tvhpoll_t *tcp_server_poll; static uint32_t tcp_server_launch_id; diff -rupN tvheadend-master/src/tcp.h tvheadend-patch/src/tcp.h --- tvheadend/src/tcp.h 2017-02-13 13:07:29.000000000 +0100 +++ tvheadend/src/tcp.h 2017-02-18 13:07:29.000000000 +0100 @@ -94,6 +94,8 @@ int tcp_read_timeout(int fd, void *buf, char *tcp_get_str_from_ip(const struct sockaddr *sa, char *dst, size_t maxlen); +int tcp_get_sockaddr(struct sockaddr *sa, const char *s); + struct sockaddr *tcp_get_ip_from_str(const char *str, struct sockaddr *sa); int tcp_socket_dead(int fd);