diff --git a/Makefile b/Makefile index 19dc991..5850275 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ prefix ?= /usr/local # WITH_PROXY enables PROXY Protocol v2 support ifeq ($(WITH_PROXY),1) - override CXXFLAGS += -DWITH_PROXY + override CXXFLAGS += -DUWS_WITH_PROXY endif # WITH_OPENSSL=1 enables OpenSSL 1.1+ support diff --git a/examples/HelloWorld.cpp b/examples/HelloWorld.cpp index 94e6215..d18e8d8 100644 --- a/examples/HelloWorld.cpp +++ b/examples/HelloWorld.cpp @@ -1,5 +1,4 @@ #include "App.h" -#include /* Note that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support */ @@ -10,8 +9,6 @@ int main() { .cert_file_name = "../misc/cert.pem", .passphrase = "1234" }).get("/*", [](auto *res, auto *req) { - std::cout << res->getRemoteAddressAsText() << std::endl; - std::cout << res->getProxiedRemoteAddressAsText() << std::endl; res->end("Hello world!"); }).listen(3000, [](auto *token) { if (token) { diff --git a/src/HttpContext.h b/src/HttpContext.h index 89c7b7d..18c7049 100644 --- a/src/HttpContext.h +++ b/src/HttpContext.h @@ -127,7 +127,7 @@ private: // how far did we read then? we need to know to continue with websocket parsing data? or? void *proxyParser = nullptr; -#ifdef WITH_PROXY +#ifdef UWS_WITH_PROXY proxyParser = &httpResponseData->proxyParser; #endif diff --git a/src/HttpContextData.h b/src/HttpContextData.h index 5ba04bc..77760df 100644 --- a/src/HttpContextData.h +++ b/src/HttpContextData.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/HttpParser.h b/src/HttpParser.h index 643ba52..1ac893c 100644 --- a/src/HttpParser.h +++ b/src/HttpParser.h @@ -183,7 +183,7 @@ private: /* How much data we CONSUMED (to throw away) */ int consumedTotal = 0; -#ifdef WITH_PROXY +#ifdef UWS_WITH_PROXY /* ProxyParser is passed as reserved parameter */ ProxyParser *pp = (ProxyParser *) reserved; diff --git a/src/HttpResponse.h b/src/HttpResponse.h index 1c20154..a9c5674 100644 --- a/src/HttpResponse.h +++ b/src/HttpResponse.h @@ -168,7 +168,7 @@ private: public: /* If we have proxy support; returns the proxed source address as reported by the proxy. */ -#ifdef WITH_PROXY +#ifdef UWS_WITH_PROXY std::string_view getProxiedRemoteAddress() { return getHttpResponseData()->proxyParser.getSourceAddress(); } diff --git a/src/HttpResponseData.h b/src/HttpResponseData.h index c81d475..1e04cef 100644 --- a/src/HttpResponseData.h +++ b/src/HttpResponseData.h @@ -22,11 +22,10 @@ #include "HttpParser.h" #include "AsyncSocketData.h" +#include "ProxyParser.h" #include "f2/function2.hpp" -#include "ProxyParser.h" - namespace uWS { template @@ -53,8 +52,7 @@ private: /* Current state (content-length sent, status sent, write called, etc */ int state = 0; -#ifdef WITH_PROXY - // proxy protocol +#ifdef UWS_WITH_PROXY ProxyParser proxyParser; #endif }; diff --git a/src/HttpRouter.h b/src/HttpRouter.h index 7c61698..aba0b21 100644 --- a/src/HttpRouter.h +++ b/src/HttpRouter.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/Loop.h b/src/Loop.h index 3681dad..a4d0840 100644 --- a/src/Loop.h +++ b/src/Loop.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); @@ -80,7 +80,7 @@ private: Loop *loop = nullptr; bool cleanMe = false; }; - + public: /* Lazily initializes a per-thread loop and returns it. * Will automatically free all initialized loops at exit. */ diff --git a/src/LoopData.h b/src/LoopData.h index 112bae8..ffcd7cf 100644 --- a/src/LoopData.h +++ b/src/LoopData.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/PerMessageDeflate.h b/src/PerMessageDeflate.h index 79aa3be..f5a75d5 100644 --- a/src/PerMessageDeflate.h +++ b/src/PerMessageDeflate.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/ProxyParser.h b/src/ProxyParser.h index 7bdf744..9dc7836 100644 --- a/src/ProxyParser.h +++ b/src/ProxyParser.h @@ -1,135 +1,163 @@ -// - -// implements PROXY v2 protocol - -#ifndef PROXY_PARSER -#define PROXY_PARSER - -#ifdef WITH_PROXY - -struct proxy_hdr_v2 { - uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */ - uint8_t ver_cmd; /* protocol version and command */ - uint8_t fam; /* protocol family and address */ - uint16_t len; /* number of following bytes part of the header */ -}; - -union proxy_addr { - struct { /* for TCP/UDP over IPv4, len = 12 */ - uint32_t src_addr; - uint32_t dst_addr; - uint16_t src_port; - uint16_t dst_port; - } ipv4_addr; - struct { /* for TCP/UDP over IPv6, len = 36 */ - uint8_t src_addr[16]; - uint8_t dst_addr[16]; - uint16_t src_port; - uint16_t dst_port; - } ipv6_addr; -}; - -/* Byte swap for little-endian systems */ -template -T _cond_byte_swap(T value) { - uint32_t endian_test = 1; - if (*((char *)&endian_test)) { - union { - T i; - uint8_t b[sizeof(T)]; - } src = { value }, dst; - - for (unsigned int i = 0; i < sizeof(value); i++) { - dst.b[i] = src.b[sizeof(value) - 1 - i]; - } - - return dst.i; - } - return value; -} - -struct ProxyParser { -private: - union proxy_addr addr; - - // we should have "unset" where the return value is "" from proxied ip! - uint8_t family = 0; - -public: - /* Returns 4 or 16 bytes source address */ - std::string_view getSourceAddress() { - - // UNSPEC family and protocol - if (family == 0) { - return {}; - } - - if ((family & 0xf0) >> 4 == 1) { - /* Family 1 is INET4 */ - return {(char *) &addr.ipv4_addr.src_addr, 4}; - } else { - /* Family 2 is INET6 */ - return {(char *) &addr.ipv6_addr.src_addr, 16}; - } - } - - /* Returns [done, consumed] where done = false on failure */ - std::pair parse(std::string_view data) { - - /* We require at least one byte to be done */ - if (!data.length()) { - return {false, 0}; - } - - /* HTTP does not start with \r, but PROXY always does */ - if (data[0] != '\r') { - /* This is HTTP, so be done */ - return {true, 0}; - } - - /* We assume we are parsing PROXY V2 here */ - - /* We require 16 bytes here */ - if (data.length() < 16) { - return {false, 0}; - } - - struct proxy_hdr_v2 header; - memcpy(&header, data.data(), 16); - - if (memcmp(header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12)) { - /* This is not PROXY protocol at all */ - return {false, 0}; - } - - /* If we have version 2 */ - - printf("Version: %d\n", (header.ver_cmd & 0xf0) >> 4); - printf("Command: %d\n", (header.ver_cmd & 0x0f)); - - uint16_t hostLength = _cond_byte_swap(header.len); - - if (data.length() < 16 + hostLength) { - return {false, 0}; - } - - printf("Length: %d\n", hostLength); - - printf("Family: %d\n", (header.fam & 0xf0) >> 4); - printf("Transport: %d\n", (header.fam & 0x0f)); - - family = header.fam; - - // copy source ip - memcpy(&addr, data.data() + 16, hostLength); - - - - return {true, 16 + hostLength}; - } - -}; - -#endif - -#endif \ No newline at end of file +/* + * Authored by Alex Hultman, 2018-2020. + * Intellectual property of third-party. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This module implements The PROXY Protocol v2 */ + +#ifndef UWS_PROXY_PARSER_H +#define UWS_PROXY_PARSER_H + +#ifdef UWS_WITH_PROXY + +namespace uWS { + +struct proxy_hdr_v2 { + uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */ + uint8_t ver_cmd; /* protocol version and command */ + uint8_t fam; /* protocol family and address */ + uint16_t len; /* number of following bytes part of the header */ +}; + +union proxy_addr { + struct { /* for TCP/UDP over IPv4, len = 12 */ + uint32_t src_addr; + uint32_t dst_addr; + uint16_t src_port; + uint16_t dst_port; + } ipv4_addr; + struct { /* for TCP/UDP over IPv6, len = 36 */ + uint8_t src_addr[16]; + uint8_t dst_addr[16]; + uint16_t src_port; + uint16_t dst_port; + } ipv6_addr; +}; + +/* Byte swap for little-endian systems */ +/* Todo: This functions should be shared with the one in WebSocketProtocol.h! */ +template +T _cond_byte_swap(T value) { + uint32_t endian_test = 1; + if (*((char *)&endian_test)) { + union { + T i; + uint8_t b[sizeof(T)]; + } src = { value }, dst; + + for (unsigned int i = 0; i < sizeof(value); i++) { + dst.b[i] = src.b[sizeof(value) - 1 - i]; + } + + return dst.i; + } + return value; +} + +struct ProxyParser { +private: + union proxy_addr addr; + + /* Default family of 0 signals no proxy address */ + uint8_t family = 0; + +public: + /* Returns 4 or 16 bytes source address */ + std::string_view getSourceAddress() { + + // UNSPEC family and protocol + if (family == 0) { + return {}; + } + + if ((family & 0xf0) >> 4 == 1) { + /* Family 1 is INET4 */ + return {(char *) &addr.ipv4_addr.src_addr, 4}; + } else { + /* Family 2 is INET6 */ + return {(char *) &addr.ipv6_addr.src_addr, 16}; + } + } + + /* Returns [done, consumed] where done = false on failure */ + std::pair parse(std::string_view data) { + + /* We require at least one byte to be done */ + if (!data.length()) { + return {false, 0}; + } + + /* HTTP does not start with \r, but PROXY always does */ + if (data[0] != '\r') { + /* This is HTTP, so be done */ + return {true, 0}; + } + + /* We assume we are parsing PROXY V2 here */ + + /* We require 16 bytes here */ + if (data.length() < 16) { + return {false, 0}; + } + + /* Header is 16 bytes */ + struct proxy_hdr_v2 header; + memcpy(&header, data.data(), 16); + + if (memcmp(header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12)) { + /* This is not PROXY protocol at all */ + return {false, 0}; + } + + /* We only support version 2 */ + if ((header.ver_cmd & 0xf0) >> 4 != 2) { + return {false, 0}; + } + + //printf("Version: %d\n", (header.ver_cmd & 0xf0) >> 4); + //printf("Command: %d\n", (header.ver_cmd & 0x0f)); + + /* We get length in network byte order (todo: share this function with the rest) */ + uint16_t hostLength = _cond_byte_swap(header.len); + + /* We must have all the data available */ + if (data.length() < 16 + hostLength) { + return {false, 0}; + } + + /* Payload cannot be more than sizeof proxy_addr */ + if (sizeof(proxy_addr) < hostLength) { + return {false, 0}; + } + + //printf("Family: %d\n", (header.fam & 0xf0) >> 4); + //printf("Transport: %d\n", (header.fam & 0x0f)); + + /* We have 0 family by default, and UNSPEC is 0 as well */ + family = header.fam; + + /* Copy payload */ + memcpy(&addr, data.data() + 16, hostLength); + + /* We consumed everything */ + return {true, 16 + hostLength}; + } +}; + +} + +#endif + +#endif // UWS_PROXY_PARSER_H \ No newline at end of file diff --git a/src/Utilities.h b/src/Utilities.h index c84029e..8ff80ad 100644 --- a/src/Utilities.h +++ b/src/Utilities.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/WebSocket.h b/src/WebSocket.h index a395f99..dd32540 100644 --- a/src/WebSocket.h +++ b/src/WebSocket.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/WebSocketContext.h b/src/WebSocketContext.h index 8de6d24..73e76ec 100644 --- a/src/WebSocketContext.h +++ b/src/WebSocketContext.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/WebSocketContextData.h b/src/WebSocketContextData.h index 477f448..120e0eb 100644 --- a/src/WebSocketContextData.h +++ b/src/WebSocketContextData.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/WebSocketData.h b/src/WebSocketData.h index 5e1e24d..7b29ed4 100644 --- a/src/WebSocketData.h +++ b/src/WebSocketData.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/WebSocketExtensions.h b/src/WebSocketExtensions.h index 9368ec9..79994ee 100644 --- a/src/WebSocketExtensions.h +++ b/src/WebSocketExtensions.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/WebSocketHandshake.h b/src/WebSocketHandshake.h index a539c75..c4daab9 100644 --- a/src/WebSocketHandshake.h +++ b/src/WebSocketHandshake.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/WebSocketProtocol.h b/src/WebSocketProtocol.h index 4d6736f..1dfb8f1 100644 --- a/src/WebSocketProtocol.h +++ b/src/WebSocketProtocol.h @@ -1,5 +1,5 @@ /* - * Authored by Alex Hultman, 2018-2019. + * Authored by Alex Hultman, 2018-2020. * Intellectual property of third-party. * Licensed under the Apache License, Version 2.0 (the "License");