diff --git a/src/common.hpp b/src/common.hpp index 5596d2eaadc886a457983cbc3c0fde3f4dafda4f..02f342743909cf04713194d0a7dc0b3e0925b80c 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -5,5 +5,16 @@ extern rlib::logger rlog; +// epoll buffer size. +constexpr size_t EPOLL_MAX_EVENTS = 32; +// DGRAM packet usually smaller than 1400B. +constexpr size_t DGRAM_BUFFER_SIZE = 20480; + +// Change a connection on every n seconds, +// to reset the GFW deep-packet-inspection process. +// ( Only if server side is encrypted, so nothing happens +// to the real openvpn server. +constexpr size_t SERVER_ENCRYPT_CONNECTION_TIMEOUT_SECONDS = 60; + #endif diff --git a/src/forwarder.hpp b/src/forwarder.hpp index 163790b613e0a3bd181164ba527134f812f37219..91ba1e3a3ce7e50ca40f201339253337139d041f 100644 --- a/src/forwarder.hpp +++ b/src/forwarder.hpp @@ -12,7 +12,7 @@ struct ConnectionMapping { std::unordered_multimap<fd_t, string> server2client; static string clientInfoAsKey(string ip, uint16_t port) { // Also works for ipv6. We just want to eliminate duplication, rather than make it easy to read. - return ip + "@" + port; + return ip + '@' + port; } }; diff --git a/src/protocols/base.hpp b/src/protocols/base.hpp index 46e8ce8184d6dca092353b4036053dc4b01b3468..9aa17f74c607cf31dce188b9d0911a6b5d8785a5 100644 --- a/src/protocols/base.hpp +++ b/src/protocols/base.hpp @@ -6,23 +6,32 @@ using std::string; namespace Protocols { - class BaseHandler : rlib::noncopyable { + // Handler holds the senderId=>nextHopFd mapping. + // senderId is "$ip@$port", for example, `fe80:8100::1@1080`. + // Misc protocol may use duplicateSenderId to work on port migration. + // Any listener may use removeSenderId to disconnect a sender. + // Note: this interface works for both TCP and UDP. + struct BaseHandler : rlib::noncopyable { BaseHandler(string outboundConfig) { loadConfig(outboundConfig); } - virtual ~BaseOutboundHandler = default; + virtual ~BaseHandler = default; // Interfaces - virtual loadConfig(string config) = 0; - virtual handleMessage(string binaryMessage) = 0; + virtual void loadConfig(string config) = 0; + virtual void handleMessage(string binaryMessage, string senderId) = 0; + virtual void duplicateSenderId(string newSenderId, string oldSenderId) = 0; + virtual void removeSenderId(string senderId) = 0; }; - class BaseListener : rlib::noncopyable { + struct BaseListener : rlib::noncopyable { BaseListener(string inboundConfig) { loadConfig(inboundConfig); } - virtual loadConfig(string config) = 0; - virtual listenForever(BaseHandler *nextHop) = 0; + virtual ~BaseListener = default; + + virtual void loadConfig(string config) = 0; + virtual void listenForever(BaseHandler *nextHop) = 0; }; } diff --git a/src/protocols/misc.hpp b/src/protocols/misc.hpp index 2f456e4363ede9426aa82cb872f14da0c5e7ad51..ceef4e5fc24d457dba05ef691d0199eef5148b01 100644 --- a/src/protocols/misc.hpp +++ b/src/protocols/misc.hpp @@ -16,10 +16,14 @@ namespace Protocols { // listenPort = ar[2].as<uint16_t>(); psk = ar[3]; + // listen these ports. } virtual listenForever(BaseHandler* nextHop) override { + // if message arrives: + // send to handler. + } private: diff --git a/src/protocols/plain.hpp b/src/protocols/plain.hpp index ba4b955fb30a5e8f69090b30c0a813d0bf4f3a59..c2f6b63df7971102c811f5ff0598e8d4b024f580 100644 --- a/src/protocols/plain.hpp +++ b/src/protocols/plain.hpp @@ -4,6 +4,8 @@ #include <protocols/base.hpp> #include <rlib/sys/sio.hpp> #include <rlib/string.hpp> +#include <utils.hpp> +#include <common.hpp> namespace Protocols { class PlainInboundListener : public BaseListener { @@ -12,17 +14,33 @@ namespace Protocols { auto ar = rlib::string(config).split('@'); // Also works for ipv6. if (ar.size() != 3) throw std::invalid_argument("Wrong parameter string for protocol 'plain'. Example: plain@fe00:1e10:ce95:1@10809"); - auto listenAddr = ar[1]; - auto listenPort = ar[2].as<uint16_t>(); + listenAddr = ar[1]; + listenPort = ar[2].as<uint16_t>(); - listenFd = rlib::quick_listen(listenAddr, listenPort, true); } virtual listenForever(BaseHandler* nextHop) override { + auto listenFd = rlib::quick_listen(listenAddr, listenPort, true); + rlib_defer([&] {close(listenFd);}); + + auto epollFd = epoll_create1(0); + if(epollFd == -1) + throw std::runtime_error("Failed to create epoll fd."); + epoll_add_fd(epollFd, listenFd); + + epoll_event events[MAX_EVENTS]; + char buffer[DGRAM_BUFFER_SIZE]; + // WARN: If you want to modify this program to work for both TCP and UDP, PLEASE use rlib::sockIO::recv instead of fixed buffer. + + rlog.info("PlainListener listening [{}]:{} ...", listenAddr, listenPort); + while (true) { + // ... + } } private: - fd_t listenFd; + string listenAddr; + uint16_t listenPort; }; using PlainOutboundListener = PlainInboundListener; diff --git a/src/utils.hpp b/src/utils.hpp index d4c1d1453fdc120410a7d974c9b0814eb123ebcd..97313e10e8da1bc20c916322e05c61be6fa039e6 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -9,6 +9,7 @@ #include <wepoll.h> #endif + inline void epoll_add_fd(fd_t epollFd, fd_t fd) { epoll_event event { .events = EPOLLIN,