Proxy

如何通過 TOR 路由 TCP 連接?

  • October 22, 2013

我正在閱讀有關torchat的內容,它本質上是一個匿名聊天程序。

聽起來很酷,所以我想嘗試自己製作。首先,我編寫了一個測試來使用 Http 抓取網頁。Sicne .NET 不支持 SOCKS4A/SOCKS5 我使用了 privoxy 並且我的應用程序工作正常。然後我切換到 TCP echo 測試,而 privoxy 不支持 TCP,所以我搜尋並安裝了 6 個以上的代理應用程序(freecap、socat、freeproxy、delegate 是我能記住的那些,我還玩過 putty bc i知道它支持隧道和 SOCK5),但我無法成功地讓它們中的任何一個工作,更不用說通過 privoxy 輕鬆無痛地完成的我的 http 測試執行它了。

我可以使用什麼來獲得通過 TOR 的 TCP 連接?我花了超過 2 個小時沒有成功。我不知道我是否正在尋找在我的搜尋中出現的中繼、隧道、轉發器、代理或代理鏈。我將以下配置用於 .NET。我需要 TCP 工作,但我首先使用 http 進行測試,因為我知道我使用 privoxy 讓它工作。我使用哪些應用程序和配置來讓 TCP 通過 Tor?

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.net>
   <defaultProxy enabled="true">
     <proxy bypassonlocal="True" proxyaddress="http://127.0.0.1:8118"/>
   </defaultProxy>
   <settings>
     <httpWebRequest useUnsafeHeaderParsing="true"/>
   </settings>
 </system.net>
</configuration>

-edit- 感謝 Bernd,我有一個解決方案。這是我最終編寫的程式碼。這並不令人驚訝,但它是公平的。

static NetworkStream ConnectSocksProxy(string proxyDomain, short proxyPort, string host, short hostPort, TcpClient tc)
{
   tc.Connect(proxyDomain, proxyPort);
   if (System.Text.RegularExpressions.Regex.IsMatch(host, @"[\:/\\]"))
       throw new Exception("Invalid Host name. Use FQDN such as www.google.com. Do not have http, a port or / in it");
   NetworkStream ns = tc.GetStream();
   var HostNameBuf = new ASCIIEncoding().GetBytes(host);
   var HostPortBuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(hostPort));
   if (true) //5
   {
       var bufout = new byte[128];
       var buflen = 0;
       ns.Write(new byte[] { 5, 1, 0 }, 0, 3);
       buflen = ns.Read(bufout, 0, bufout.Length);
       if (buflen != 2 || bufout[0] != 5 || bufout[1] != 0)
           throw new Exception();

       var buf = new byte[] { 5, 1, 0, 3, (byte)HostNameBuf.Length };
       var mem = new MemoryStream();
       mem.Write(buf, 0, buf.Length);
       mem.Write(HostNameBuf, 0, HostNameBuf.Length);
       mem.Write(new byte[] { HostPortBuf[0], HostPortBuf[1] }, 0, 2);
       var memarr = mem.ToArray();
       ns.Write(memarr, 0, memarr.Length);
       buflen = ns.Read(bufout, 0, bufout.Length);
       if (bufout[0] != 5 || bufout[1] != 0)
           throw new Exception();
   }
   else //4a
   {
       var bufout = new byte[128];
       var buflen = 0;
       var mem = new MemoryStream();
       mem.WriteByte(4);
       mem.WriteByte(1);
       mem.Write(HostPortBuf, 0, 2);
       mem.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(1)), 0, 4);
       mem.WriteByte(0);
       mem.Write(HostNameBuf, 0, HostNameBuf.Length);
       mem.WriteByte(0);
       var memarr = mem.ToArray();
       ns.Write(memarr, 0, memarr.Length);
       buflen = ns.Read(bufout, 0, bufout.Length);
       if (buflen != 8 || bufout[0] != 0 || bufout[1] != 90)
           throw new Exception();
   }
   return ns;
}

用法

using (TcpClient client = new TcpClient())
using (var ns = ConnectSocksProxy("127.0.0.1", 9050, "website.com", 80, client)) {...}

Socks4a 真的很簡單。你可以用 5 行程式碼手動完成 socks4a。查看 socks RFC(或其在 wikipedia 上更簡單的解釋)。

本質上,您只需與 socks 代理建立一個正常的 TCP 連接(這意味著在 tor 的情況下,您只需連接到 127.0.0.1 埠 9050,連接將被接受,然後您在此連接上發送一個非常簡單的請求(範例在RFC),然後一段時間後,tor 將準確地回答 8 個字節(第二個字節是狀態,應該是 90 表示成功)。僅此而已。

在此連接上收到 Tor 的成功回答後,您繼續使用相同的連接,此時您已經通過此套接字與另一端連接,從此刻起,它的行為就像任何其他 TCP 連接一樣,用於所有意圖和目的,並且您可以像直接連接一樣開始發送/接收。

編輯:您不需要學習整個 RFC,在維基百科中有一個非常簡短和完整的 Socks 4a 描述(socks 5 對您的需求來說太過分了,socks 4 無法解析主機名,所以 4a 是 Tor 的理想選擇) :

這是 http://en.wikipedia.org/wiki/SOCKS#SOCKS4a

引用自:https://serverfault.com/questions/406084