From 835bb66f3ed65830c7afb66c818df46e63fd2706 Mon Sep 17 00:00:00 2001
From: klzgrad <kizdiv@gmail.com>
Date: Sun, 23 Jun 2019 05:20:30 +0800
Subject: [PATCH] Support TCP transparent proxying

Enable with naive --listen=redir:// and iptables ... -j REDIRECT
--to-ports 1080.
---
 src/net/tools/naive/naive_connection.cc | 27 +++++++++++++++++++++++++
 src/net/tools/naive/naive_connection.h  |  1 +
 src/net/tools/naive/naive_proxy.cc      |  3 +++
 src/net/tools/naive/naive_proxy_bin.cc  |  5 +++++
 4 files changed, 36 insertions(+)

diff --git a/src/net/tools/naive/naive_connection.cc b/src/net/tools/naive/naive_connection.cc
index 31a0040b06..674aba407f 100644
--- a/src/net/tools/naive/naive_connection.cc
+++ b/src/net/tools/naive/naive_connection.cc
@@ -26,6 +26,16 @@
 #include "net/tools/naive/http_proxy_socket.h"
 #include "net/tools/naive/socks5_server_socket.h"
 
+#if defined(OS_LINUX)
+#include <linux/netfilter_ipv4.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "net/base/ip_endpoint.h"
+#include "net/base/sockaddr_storage.h"
+#include "net/socket/tcp_client_socket.h"
+#endif
+
 namespace net {
 
 namespace {
@@ -187,6 +197,23 @@ int NaiveConnection::DoConnectServer() {
     const auto* socket =
         static_cast<const HttpProxySocket*>(client_socket_.get());
     origin = socket->request_endpoint();
+  } else if (protocol_ == kRedir) {
+#if defined(OS_LINUX)
+    const auto* socket =
+        static_cast<const TCPClientSocket*>(client_socket_.get());
+    int sd = socket->SocketDescriptorForTesting();
+    SockaddrStorage dst;
+    int rv;
+    rv = getsockopt(sd, SOL_IP, SO_ORIGINAL_DST, dst.addr, &dst.addr_len);
+    if (rv == 0) {
+      IPEndPoint ipe;
+      if (ipe.FromSockAddr(dst.addr, dst.addr_len)) {
+        origin = HostPortPair::FromIPEndPoint(ipe);
+      }
+    }
+#else
+    static_cast<void>(resolver_);
+#endif
   }
 
   if (origin.IsEmpty()) {
diff --git a/src/net/tools/naive/naive_connection.h b/src/net/tools/naive/naive_connection.h
index ff1e68ec52..ca6657ca5d 100644
--- a/src/net/tools/naive/naive_connection.h
+++ b/src/net/tools/naive/naive_connection.h
@@ -35,6 +35,7 @@ class NaiveConnection {
   enum Protocol {
     kSocks5,
     kHttp,
+    kRedir,
   };
 
   // From this direction.
diff --git a/src/net/tools/naive/naive_proxy.cc b/src/net/tools/naive/naive_proxy.cc
index e5671be37c..dda0d9b27a 100644
--- a/src/net/tools/naive/naive_proxy.cc
+++ b/src/net/tools/naive/naive_proxy.cc
@@ -96,6 +96,9 @@ void NaiveProxy::DoConnect() {
     socket = std::make_unique<HttpProxySocket>(std::move(accepted_socket_),
                                                traffic_annotation_);
     pad_direction = NaiveConnection::kServer;
+  } else if (protocol_ == NaiveConnection::kRedir) {
+    socket = std::move(accepted_socket_);
+    pad_direction = NaiveConnection::kClient;
   } else {
     return;
   }
diff --git a/src/net/tools/naive/naive_proxy_bin.cc b/src/net/tools/naive/naive_proxy_bin.cc
index 49f1816066..6c5dd70870 100644
--- a/src/net/tools/naive/naive_proxy_bin.cc
+++ b/src/net/tools/naive/naive_proxy_bin.cc
@@ -172,6 +172,7 @@ void GetCommandLine(const base::CommandLine& proc, CommandLine* cmdline) {
                  "--version                  Print version\n"
                  "--listen=<proto>://[addr][:port]\n"
                  "                           proto: socks, http\n"
+                 "                                  redir (Linux only)\n"
                  "--proxy=<proto>://[<user>:<pass>@]<hostname>[:<port>]\n"
                  "                           proto: https, quic\n"
                  "--padding                  Use padding\n"
@@ -257,6 +258,7 @@ bool ParseCommandLine(const CommandLine& cmdline, Params* params) {
   params->listen_addr = "0.0.0.0";
   params->listen_port = 1080;
   url::AddStandardScheme("socks", url::SCHEME_WITH_HOST_AND_PORT);
+  url::AddStandardScheme("redir", url::SCHEME_WITH_HOST_AND_PORT);
   if (!cmdline.listen.empty()) {
     GURL url(cmdline.listen);
     if (url.scheme() == "socks") {
@@ -265,6 +267,9 @@ bool ParseCommandLine(const CommandLine& cmdline, Params* params) {
     } else if (url.scheme() == "http") {
       params->protocol = net::NaiveConnection::kHttp;
       params->listen_port = 8080;
+    } else if (url.scheme() == "redir") {
+      params->protocol = net::NaiveConnection::kRedir;
+      params->listen_port = 1080;
     } else {
       std::cerr << "Invalid scheme in --listen" << std::endl;
       return false;