From 9a740f04d03d6f6ffe22421e1e10d23f0e7ac699 Mon Sep 17 00:00:00 2001
From: Bensong Liu <bensl@microsoft.com>
Date: Thu, 30 Jul 2020 16:30:50 +0800
Subject: [PATCH] add reverse filter

---
 src/filters/base.hpp | 27 +++++++++++++++++++++++++--
 src/forwarder.hpp    | 32 +++++++++++++++++++-------------
 src/main.cc          |  2 +-
 3 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/src/filters/base.hpp b/src/filters/base.hpp
index 00bb003..09a7d1a 100644
--- a/src/filters/base.hpp
+++ b/src/filters/base.hpp
@@ -30,7 +30,7 @@ namespace Filters {
 	};
 
 	struct ChainedFilters : public BaseFilter {
-		ChainedFilters(const std::list<Filters::BaseFilter*>& chainedFilters)
+		explicit ChainedFilters(const std::list<Filters::BaseFilter*>& chainedFilters)
 			: chainedFilters(chainedFilters) {}
 
 		// Usually the encrypt/encode/obfs function.
@@ -42,7 +42,7 @@ namespace Filters {
 		}
 
 		// Usually the decrypt/decode/de-obfs function.
-		virtual string convertBackward(string binaryDatagram) {
+		virtual string convertBackward(string binaryDatagram) override {
 			for (auto iter = chainedFilters.rbegin(); iter != chainedFilters.rend(); ++iter) {
 				binaryDatagram = (*iter)->convertForward(binaryDatagram);
 			}
@@ -51,6 +51,29 @@ namespace Filters {
 
 		const std::list<Filters::BaseFilter*>& chainedFilters;
 	};
+
+	struct ReversedFilter : public BaseFilter {
+		explicit ReversedFilter(BaseFilter* real, bool I_should_delete = false) : real(real), I_should_delete(I_should_delete) {}
+
+		virtual ~ReversedFilter() {
+			if (I_should_delete)
+				delete real;
+		}
+
+		// Usually the encrypt/encode/obfs function.
+		virtual string convertForward(string binaryDatagram) override {
+			return real->convertBackward(binaryDatagram);
+		}
+
+		// Usually the decrypt/decode/de-obfs function.
+		virtual string convertBackward(string binaryDatagram) override {
+			return real->convertForward(binaryDatagram);
+		}
+
+		bool I_should_delete = false;
+		BaseFilter* real;
+	};
+
 }
 
 #endif
diff --git a/src/forwarder.hpp b/src/forwarder.hpp
index 9dfaea3..584784b 100644
--- a/src/forwarder.hpp
+++ b/src/forwarder.hpp
@@ -14,6 +14,23 @@
 using std::string;
 
 
+// This function parse the FilterConfig string for you. Register implemented modules here!
+inline Filters::BaseFilter* CreateFilterFromConfig(rlib::string filterConfig) {
+	Filters::BaseFilter *newFilter = nullptr;
+    if (filterConfig.starts_with("aes@"))
+        newFilter = new Filters::AESFilter();
+    else if (filterConfig.starts_with("xor@"))
+        newFilter = new Filters::XorFilter(); // these filters were not deleted. just a note.
+	else if (filterConfig.starts_with("reverse@")) {
+		auto newFilterConfig = filterConfig.substr(8);
+		newFilter = new Filters::ReversedFilter(CreateFilterFromConfig(newFilterConfig), true);
+	}
+    else
+        throw std::invalid_argument("Unknown filter in filterConfig item: " + filterConfig);
+
+    newFilter->loadConfig(filterConfig);
+    return newFilter;
+}
 
 class Forwarder {
 public:
@@ -36,19 +53,8 @@ public:
 
 
         std::list<Filters::BaseFilter*> chainedFilters;
-        for (auto &&filterConfig : filterConfigs) {
-            Filters::BaseFilter *newFilter = nullptr;
-            if (filterConfig.starts_with("aes"))
-                newFilter = new Filters::AESFilter();
-            else if (filterConfig.starts_with("xor"))
-                newFilter = new Filters::XorFilter(); // these filters were not deleted. just a note.
-            else
-                throw std::invalid_argument("Unknown filter in filterConfig item: " + filterConfig);
-
-            newFilter->loadConfig(filterConfig);
-            chainedFilters.push_back(newFilter);
-        }
-
+        for (auto &&filterConfig : filterConfigs)
+            chainedFilters.push_back(CreateFilterFromConfig(filterConfig));
         ptrFilter = new Filters::ChainedFilters(chainedFilters);
     }
 
diff --git a/src/main.cc b/src/main.cc
index 88680ea..8c3c39d 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -26,7 +26,7 @@ int real_main(int argc, char **argv) {
         rlog.info("  '$method@$params', available methods: ");
         rlog.info("  'plain@$addr@$port', 'misc@$addr@$portRange@$psk'");
         rlog.info("There could be multiple --filter, but they MUST be in correct order. ");
-        rlog.info("available filters: 'aes@$password' , 'xor@$password'");
+        rlog.info("available filters: 'aes@$password' , 'xor@$password', 'reverse@$otherFilter'");
         return 0;
     }
     auto inboundConfig = args.getValueArg("-i");
-- 
GitLab