Как использовать протокол управления Tor в С#?

Я пытаюсь отправить команды в порт управления Tor программным образом, чтобы обновить цепочку. Я не смог найти примеры на С#, и мое решение не работает. Запрос истекает. У меня работает служба, и я вижу, как он прослушивает порт управления.

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

Может ли кто-нибудь определить, что я делаю неправильно?

Edit:

Следуя предложению Ганса, которое он по какой-то причине удалил, я попытался отправить "AUTHENTICATE\n" вместо "AUTHENTICATE". Теперь я возвращаю ошибку от Tor: "551 Недопустимая строка с кавычками. Вам нужно ввести пароль в двойные кавычки". По крайней мере, есть некоторый прогресс.

Затем я попытался отправить "AUTHENTICATE \" \ "\n", как он хочет, но он истекает время ожидания ответа.

Edit:

Команда отлично работает в клиенте Windows Telnet. Мне даже не нужно добавлять кавычки. Не могу понять, что случилось. Возможно, двойные кавычки неправильно кодируются при отправке?

Ответы

Ответ 1

Когда я отправляю команду AUTHENTICATE, StreamReader читает ответ до конца, но нет конца, потому что по успеху поток остается открытым. Поэтому я изменил его, чтобы прочитать только первую строку ответа в этом случае.

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

Ответ 2

    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

Добавлен еще один пример, который я использую ниже. Также добавлены шаги для тех, кто хотел бы установить Tor, который может принимать команды через порт управления.

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:

  • Скопировать torrc-defaults в каталог, в котором находится tor.exe. Каталог по умолчанию, если вы используете браузер Tor: "~\Tor Browser\Browser\TorBrowser\Data\Tor"
  • Откройте окно подсказки cmd
  • chdir в каталог, где находится tor.exe. Каталог по умолчанию, если вы используете браузер Tor: "~\Tor Browser\Browser\TorBrowser\Tor \"
  • Создайте пароль для доступа к управляющему порту Tor. tor.exe --hash-password "your_password_without_hyphens" | more
  • Добавьте хэш пароля пароля в torrc-defaults в ControlPort 9151. Он должен выглядеть примерно так: hashedControlPassword 16:3B7DA467B1C0D550602211995AE8D9352BF942AB04110B2552324B2507. Если вы принимаете свой пароль как "пароль", вы можете скопировать строку выше.
  • Теперь вы можете получить доступ к управлению Tor через Telnet после его запуска. Теперь код может запускаться, просто отредактируйте путь к тому месту, где находятся файлы Tor в программе. Проверка модификации Tor через Telnet:
  • Запустите tor с помощью следующей команды: tor.exe -f .\torrc-defaults
  • Откройте следующую команду cmd и введите: telnet localhost 9151
  • Если все пойдет хорошо, вы должны увидеть полностью черный экран. Введите "autenticate "your_password_with_hyphens"" Если все пойдет хорошо, вы должны увидеть "250 OK".
  • Введите "SIGNAL NEWNYM", и вы получите новый маршрут ergo new IP. Если все пойдет хорошо, вы должны увидеть "250 OK".
  • Введите "setevents circ" (события схемы), чтобы включить вывод консоли.
  • Введите "getinfo circuit-status", чтобы увидеть текущие цепи

Ответ 4

Возможно, вы используете Vidalia, который генерирует хешированный пароль для доступа к управляющему порту. Вам нужно использовать консольное приложение Tor и настроить файл torrc.