使用Tor作为代理

38

我想在 HttpWebRequest 中使用 Tor 服务器作为代理,我的代码如下:

HttpWebRequest request;
HttpWebResponse response;

request = (HttpWebRequest)WebRequest.Create("http://www.google.com");
request.Proxy = new WebProxy("127.0.0.1:9051");

response = (HttpWebResponse)request.GetResponse();
response.Close();

使用“普通”代理时它完美运行,但是使用Tor时,在调用GetResponse()时会出现异常。

异常状态为ServerProtocolViolation,消息为(德语):Message =“Der Server hat eine Protokollverletzung ausgeführt.. Section=ResponseStatusLine”。

5个回答

34

如果你已经安装并运行了privoxy,那么你可以执行以下操作:

request.Proxy = new WebProxy("127.0.0.1:8118"); // default privoxy port

这将使您能够使用Tor进行请求


10
当然,您需要首先编辑Privoxy文件夹中的config.txt文件并取消注释以下行:forward-socks5 / 127.0.0.1:9050 .。请注意不要更改原本的意思,但可以使内容更加通俗易懂。 - Junior Mayhé
Vidalia现在已从Tor Bundle中移除。 - Marcello Grechi Lins
我已经手动下载并安装了Tor Bundle和Privoxy。我已经取消了配置文件中提到的行的注释,并将代理添加到我的webrequest对象中,但它给出了错误503-服务器不可用,并且在Privoxy上没有日志表明请求已通过它路由。你成功让它工作了吗? - Marcello Grechi Lins
我正在尝试更改config.txt,但它显示访问被拒绝? - confusedMind
@confusedMind 只需以管理员身份打开您的文本编辑器,然后找到配置文件并进行编辑。 - André C. Andersen
我能够在以管理员身份打开后更改配置文件。然而,现在我已经在Tor打开的情况下更改了这些设置,我仍然收到相同的503错误。Provixy启动日志显示“000000a0错误:配置文件中forward-socks4a指令的参数数量不正确。”所有我的forward-socks4a都被禁用了。有何想法? - jamesbar2

25

Tor不是一个HTTP代理,而是一个SOCKS代理。您可以使用支持在SOCKS上进行转发的HTTP代理(如Privoxy),并通过代码连接到该代理。


2
Lay:.NET 中没有内置的功能可以通过 SOCKS 代理转发 HTTP 内容。 - Mehrdad Afshari

8

5
使用"SocksWebProxy"库。您可以将其与WebClient和WebRequest一起使用(只需将新的SocksWebProxy分配给*.Proxy属性)。无需使用Privoxy或类似服务将http流量转换为tor。

https://github.com/Ogglas/SocksWebProxy

我还对其进行了扩展,启用了控制端口。以下是如何在不启动Tor浏览器套件的情况下在后台运行Tor,并且我们可以使用Telnet或通过Socket编程方式发送命令来控制Tor。请注意,保留HTML标签。
Socket server = null;

//Authenticate using control password
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9151);
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Connect(endPoint);
server.Send(Encoding.ASCII.GetBytes("AUTHENTICATE \"your_password\"" + Environment.NewLine));
byte[] data = new byte[1024];
int receivedDataLength = server.Receive(data);
string stringData = Encoding.ASCII.GetString(data, 0, receivedDataLength);

//Request a new Identity
server.Send(Encoding.ASCII.GetBytes("SIGNAL NEWNYM" + Environment.NewLine));
data = new byte[1024];
receivedDataLength = server.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, receivedDataLength);
if (!stringData.Contains("250"))
{
    Console.WriteLine("Unable to signal new user to server.");
    server.Shutdown(SocketShutdown.Both);
    server.Close();
}
else
{
    Console.WriteLine("SIGNAL NEWNYM sent successfully");
}

配置Tor的步骤:
  1. 将torrc-defaults复制到tor.exe所在的目录中。如果您使用Tor浏览器,则默认目录为:“〜\ Tor Browser \ Browser \ TorBrowser \ Data \ Tor”
  2. 打开cmd提示窗口
  3. chdir到tor.exe所在的目录。如果您使用Tor浏览器,则默认目录为:“〜\ Tor Browser \ Browser \ TorBrowser \ Tor \”
  4. 为Tor控制端口访问生成密码。tor.exe --hash-password“your_password_without_hyphens”| more
  5. 将您的密码哈希添加到torrc-defaults下的ControlPort 9151中。它应该看起来像这样:hashedControlPassword 16:3B7DA467B1C0D550602211995AE8D9352BF942AB04110B2552324B2507。如果您接受将密码设置为“password”,则可以复制上面的字符串。
  6. 一旦启动,您现在可以通过Telnet访问Tor控制。现在代码可以运行,只需编辑程序中Tor文件所在的路径即可。 测试通过Telnet修改Tor:
  7. 使用以下命令启动tor:tor.exe -f .\torrc-defaults
  8. 打开另一个cmd提示并键入:telnet localhost 9151
  9. 如果一切顺利,您应该会看到完全黑屏。键入“autenticate“your_password_with_hyphens””,如果一切顺利,您应该会看到“250 OK”。
  10. 键入“SIGNAL NEWNYM”,您将获得新路由,因此是新IP。如果一切顺利,您应该会看到“250 OK”。
  11. 键入“setevents circ”(电路事件)以启用控制台输出
  12. 键入“getinfo circuit-status”以查看当前电路

0
你需要从socks中“提取”一个流...
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Runtime.CompilerServices

Public Class Form1

    Sub Form1_Load() Handles Me.Load

        Dim Host As String = "google.com"

        Dim P As New SocksProxy("localhost", 64129) 'Set your socks proxy here
        Dim Stream As NetworkStream = P.GetStream(Host, 80)
        Dim buffer As Byte() = Download(Stream, Host, "")

        My.Computer.FileSystem.WriteAllBytes("C:\webpage.html", buffer, False)

        MsgBox("ok")
    End Sub

    Function Download(Stream As NetworkStream, Host As String, Resource As String) As Byte()

        Using writer = New StreamWriter(Stream)
            writer.Write(String.Format("GET /{2} HTTP/1.1{0}Host: {1}{0}{0}", vbCrLf, Host, Resource))
            writer.Flush()

            Dim byteList As New List(Of Byte)
            Dim bufferSize As Integer = 4096
            Dim buffer(bufferSize - 1) As Byte

            Do
                Dim bytesRead As Integer = Stream.Read(buffer, 0, bufferSize)
                byteList.AddRange(buffer.Take(bytesRead))
            Loop While Stream.DataAvailable

            Return byteList.ToArray
        End Using

    End Function
End Class


Public Class SocksProxy

    Private _SocksHost As String
    Private _SocksPort As Integer

    Sub New(SocksHost As String, SocksPort As Integer)
        _SocksHost = SocksHost
        _SocksPort = SocksPort
    End Sub

    Function GetStream(HostDest As String, PortDest As Short) As NetworkStream

        Dim client As TcpClient = New TcpClient()
        client.Connect(_SocksHost, _SocksPort)

        Dim stream As NetworkStream = client.GetStream()
        'Auth
        Dim buf = New Byte(299) {}
        buf(0) = &H5
        buf(1) = &H1
        buf(2) = &H0
        stream.Write(buf, 0, 3)

        ReadExactSize(stream, buf, 0, 2)
        If buf(0) <> &H5 Then
            Throw New IOException("Invalid Socks Version")
        End If
        If buf(1) = &HFF Then
            Throw New IOException("Socks Server does not support no-auth")
        End If
        If buf(1) <> &H0 Then
            Throw New Exception("Socks Server did choose bogus auth")
        End If

        buf(0) = &H5
        buf(1) = &H1
        buf(2) = &H0
        buf(3) = &H3
        Dim domain = Encoding.ASCII.GetBytes(HostDest)
        buf(4) = CByte(domain.Length)
        Array.Copy(domain, 0, buf, 5, domain.Length)
        Dim port = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(CShort(PortDest)))
        buf(5 + domain.Length) = port(0)
        buf(6 + domain.Length) = port(1)
        stream.Write(buf, 0, domain.Length + 7)


        ' Reply
        ReadExactSize(stream, buf, 0, 4)
        If buf(0) <> &H5 Then
            Throw New IOException("Invalid Socks Version")
        End If
        If buf(1) <> &H0 Then
            Throw New IOException(String.Format("Socks Error {0:X}", buf(1)))
        End If
        Dim rdest = String.Empty
        Select Case buf(3)
            Case &H1
                ' IPv4
                ReadExactSize(stream, buf, 0, 4)
                Dim v4 = BitConverter.ToUInt32(buf, 0)
                rdest = New IPAddress(v4).ToString()
                Exit Select
            Case &H3
                ' Domain name
                ReadExactSize(stream, buf, 0, 1)
                If buf(0) = &HFF Then
                    Throw New IOException("Invalid Domain Name")
                End If
                ReadExactSize(stream, buf, 1, buf(0))
                rdest = Encoding.ASCII.GetString(buf, 1, buf(0))
                Exit Select
            Case &H4
                ' IPv6
                Dim octets = New Byte(15) {}
                ReadExactSize(stream, octets, 0, 16)
                rdest = New IPAddress(octets).ToString()
                Exit Select
            Case Else
                Throw New IOException("Invalid Address type")
        End Select
        ReadExactSize(stream, buf, 0, 2)
        Dim rport = CUShort(IPAddress.NetworkToHostOrder(CShort(BitConverter.ToUInt16(buf, 0))))

        Return stream
    End Function

    Private Sub ReadExactSize(stream As NetworkStream, buffer As Byte(), offset As Integer, size As Integer)
        While size <> 0
            Dim read = stream.Read(buffer, offset, size)
            If read < 0 Then
                Throw New IOException("Premature end")
            End If
            size -= read
            offset += read
        End While
    End Sub

End Class

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接