How to use Tor control protocol in C#?

2020-05-21 05:30发布

I'm trying to send commands to the Tor control port programmatically to make it refresh the chain. I haven't been able to find any examples in C#, and my solution's not working. The request times out. I have the service running, and I can see it listening on the control port.

public string Refresh()
{
    TcpClient client = new TcpClient("localhost", 9051);
    string response = string.Empty;
    string authenticate = MakeTcpRequest("AUTHENTICATE\r\n", client);
    if (authenticate.Equals("250"))
    {
        response = MakeTcpRequest("SIGNAL NEWNYM\r\n", client);
    }
    client.Close();
    return response;
}

public string MakeTcpRequest(string message, TcpClient client)
{
    client.ReceiveTimeout = 20000;
    client.SendTimeout = 20000;
    string proxyResponse = string.Empty;

    try
    {
        // Send message
        StreamWriter streamWriter = new StreamWriter(client.GetStream());
        streamWriter.Write(message);
        streamWriter.Flush();

        // Read response
        StreamReader streamReader = new StreamReader(client.GetStream());
        proxyResponse = streamReader.ReadToEnd();
    }
    catch (Exception ex)
    {
        // Ignore
    }

    return proxyResponse;
}

Can anyone spot what I'm doing wrong?

Edit:

Following Hans's suggestion, which he has now deleted for some reason, I tried to send "AUTHENTICATE\n" instead of just "AUTHENTICATE". Now I'm getting back an error from Tor: "551 Invalid quoted string. You need to put the password in double quotes." At least there's some progress.

I then tried to send "AUTHENTICATE \"\"\n", like it wants to, but it times out while waiting for a response.

Edit:

The command works fine in the Windows Telnet client. I don't even have to add the quotes. Can't figure out what's wrong. Maybe the double quotes aren't encoded correctly when they're sent?

4条回答
Juvenile、少年°
2楼-- · 2020-05-21 06:07
    public static void CheckIfBlocked(ref HtmlDocument htmlDoc, string ypURL, HtmlWeb hw)
    {
        if (htmlDoc.DocumentNode.InnerText.Contains("FORBIDDEN ACCESS!"))
        {
            Console.WriteLine("Getting Blocked");
            Utils.RefreshTor();
            htmlDoc = hw.Load(ypURL, "127.0.0.1", 8118, null, null);
            if (htmlDoc.DocumentNode.InnerText.Contains("FORBIDDEN ACCESS!"))
            {
                Console.WriteLine("Getting Blocked");
                Utils.RefreshTor();
            }
        }
    }
    public static void RefreshTor()
    {
        IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9051);
        Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        try
        {
            server.Connect(ip);
        }
        catch (SocketException e)
        {
            Console.WriteLine("Unable to connect to server.");
            RefreshTor();
            return;
        }

        server.Send(Encoding.ASCII.GetBytes("AUTHENTICATE \"butt\"\n"));
        byte[] data = new byte[1024];
        int receivedDataLength = server.Receive(data);
        string stringData = Encoding.ASCII.GetString(data, 0, receivedDataLength);

        if (stringData.Contains("250"))
        {
            server.Send(Encoding.ASCII.GetBytes("SIGNAL NEWNYM\r\n"));
            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();
                RefreshTor();
            }
        }
        else
        {
            Console.WriteLine("Unable to authenticate to server.");
            server.Shutdown(SocketShutdown.Both);
            server.Close();
            RefreshTor();
        }
        server.Shutdown(SocketShutdown.Both);
        server.Close();
    }
查看更多
地球回转人心会变
3楼-- · 2020-05-21 06:10

Probably you using Vidalia that generates a hashed password for control port access. You need to use Tor console app and configure a torrc file.

查看更多
一夜七次
4楼-- · 2020-05-21 06:22

When I send the AUTHENTICATE command, the StreamReader is reading the response to the end, but there is no end because on success the stream is kept open. So I changed it to only read the first line of the response in this case.

public static string MakeTcpRequest(string message, TcpClient client, bool readToEnd)
{
    client.ReceiveTimeout = 20000;
    client.SendTimeout = 20000;
    string proxyResponse = string.Empty;

    try
    {
        // Send message
        using (StreamWriter streamWriter = new StreamWriter(client.GetStream()))
        {
            streamWriter.Write(message);
            streamWriter.Flush();
        }

        // Read response
        using (StreamReader streamReader = new StreamReader(client.GetStream()))
        {
            proxyResponse = readToEnd ? streamReader.ReadToEnd() : streamReader.ReadLine();
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }

    return proxyResponse;
}
查看更多
戒情不戒烟
5楼-- · 2020-05-21 06:29

Added another example I'm using myself below. Also added steps for those who would like to setup Tor that can accept commands through the control port.

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");
}

Steps to configure Tor:

  1. Copy torrc-defaults into the directory in which tor.exe is. Default directory if you are using Tor browser is: "~\Tor Browser\Browser\TorBrowser\Data\Tor"
  2. Open a cmd prompt window
  3. chdir to the directory where tor.exe is. Default directory if you are using Tor browser is: "~\Tor Browser\Browser\TorBrowser\Tor\"
  4. Generate a password for Tor control port access. tor.exe --hash-password “your_password_without_hyphens” | more
  5. Add your password password hash to torrc-defaults under ControlPort 9151. It should look something like this: hashedControlPassword 16:3B7DA467B1C0D550602211995AE8D9352BF942AB04110B2552324B2507. If you accept your password to be "password" you can copy the string above.
  6. You can now access Tor control via Telnet once it is started. Now the code can run, just edit the path to where your Tor files are located in the program. Test modifying Tor via Telnet:
  7. Start tor with the following command: tor.exe -f .\torrc-defaults
  8. Open up another cmd prompt and type: telnet localhost 9151
  9. If all goes well you should see a completely black screen. Type "autenticate “your_password_with_hyphens”" If all goes well you should see "250 OK".
  10. Type "SIGNAL NEWNYM" and you will get a new route, ergo new IP. If all goes well you should see "250 OK".
  11. Type "setevents circ" (circuit events) to enable console output
  12. Type "getinfo circuit-status" to see current circuits
查看更多
登录 后发表回答